From 255f3e52fb66ae6cb55e24938fff60ec6e28b285 Mon Sep 17 00:00:00 2001 From: kanishkkatara Date: Wed, 4 Sep 2024 16:33:26 +0530 Subject: [PATCH 001/147] fix: add namespace and cluster labels to python transformation functions --- src/util/customTransformer-faas.js | 4 ++++ src/util/openfaas/index.js | 7 +++++++ test/__tests__/user_transformation.test.js | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/util/customTransformer-faas.js b/src/util/customTransformer-faas.js index 07dc2055828..0f59f5db60f 100644 --- a/src/util/customTransformer-faas.js +++ b/src/util/customTransformer-faas.js @@ -8,6 +8,8 @@ const { executeFaasFunction, FAAS_AST_FN_NAME, FAAS_AST_VID, + PARENT_NAMESPACE, + PARENT_CLUSTER, } = require('./openfaas'); const { getLibraryCodeV1 } = require('./customTransforrmationsStore-v1'); @@ -26,6 +28,8 @@ function generateFunctionName(userTransformation, libraryVersionIds, testMode, h (libraryVersionIds || []).sort(), ); + ids = ids.concat([PARENT_NAMESPACE, PARENT_CLUSTER]); + if (hashSecret !== '') { ids = ids.concat([hashSecret]); } diff --git a/src/util/openfaas/index.js b/src/util/openfaas/index.js index 1f44df86bba..7d4adf2321c 100644 --- a/src/util/openfaas/index.js +++ b/src/util/openfaas/index.js @@ -38,6 +38,9 @@ const FAAS_READINESS_HTTP_FAILURE_THRESHOLD = const FAAS_READINESS_HTTP_SUCCESS_THRESHOLD = process.env.FAAS_READINESS_HTTP_SUCCESS_THRESHOLD || '1'; +const PARENT_NAMESPACE = process.env.NAMESPACE || 'default'; +const PARENT_CLUSTER = process.env.FAAS_FN_PARENT_CLUSTER || 'default'; + const CONFIG_BACKEND_URL = process.env.CONFIG_BACKEND_URL || 'https://api.rudderlabs.com'; const GEOLOCATION_URL = process.env.GEOLOCATION_URL || ''; const FAAS_AST_VID = 'ast'; @@ -313,6 +316,8 @@ function buildOpenfaasFn(name, code, versionId, libraryVersionIDs, testMode, trM const labels = { 'openfaas-fn': 'true', 'parent-component': 'openfaas', + 'parent-namespace': PARENT_NAMESPACE, + 'parent-cluster': PARENT_CLUSTER, 'com.openfaas.scale.max': FAAS_MAX_PODS_IN_TEXT, 'com.openfaas.scale.min': FAAS_MIN_PODS_IN_TEXT, 'com.openfaas.scale.zero': FAAS_SCALE_ZERO, @@ -431,6 +436,8 @@ module.exports = { buildOpenfaasFn, FAAS_AST_VID, FAAS_AST_FN_NAME, + PARENT_NAMESPACE, + PARENT_CLUSTER, setFunctionInCache, reconcileFunction, }; diff --git a/test/__tests__/user_transformation.test.js b/test/__tests__/user_transformation.test.js index af3d84173a2..eff11b083f6 100644 --- a/test/__tests__/user_transformation.test.js +++ b/test/__tests__/user_transformation.test.js @@ -92,6 +92,7 @@ const pyLibCode = (name, versionId) => { const pyfaasFuncName = (workspaceId, versionId, libraryVersionIds=[], hashSecret="") => { let ids = [workspaceId, versionId].concat(libraryVersionIds.sort()); + ids = ids.concat(["default", "default"]); if (hashSecret !== "") { ids = ids.concat([hashSecret]); } @@ -119,7 +120,7 @@ describe("User transformation utils", () => { [], false, 'hash-secret'); - expect(fnName).toEqual('fn-workspaceid-34a32ade07ebbc7bc5ea795b8200de9f'); + expect(fnName).toEqual('fn-workspaceid-91d66b4cea6f0ed16cd41258d138d0a8'); }); }); From 6a81e888729e7b2eb6e93db711a3daeb54f6c42f Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 5 Sep 2024 08:13:06 +0000 Subject: [PATCH 002/147] chore(release): 1.77.1 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc517256bda..fc2f0ba14a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.77.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.77.0...v1.77.1) (2024-09-05) + + +### Bug Fixes + +* add namespace and cluster labels to python transformation functions ([255f3e5](https://github.com/rudderlabs/rudder-transformer/commit/255f3e52fb66ae6cb55e24938fff60ec6e28b285)) + ## [1.77.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.76.1...v1.77.0) (2024-09-02) diff --git a/package-lock.json b/package-lock.json index 489739879b4..5b6bde22eb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.77.0", + "version": "1.77.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.77.0", + "version": "1.77.1", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index f51501ff919..bb529053478 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.77.0", + "version": "1.77.1", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From f7783d8fb30093a847f450ee7ddd9449f272b112 Mon Sep 17 00:00:00 2001 From: Gauravudia <60897972+Gauravudia@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:54:48 +0530 Subject: [PATCH 003/147] feat: webhook v2 path variables support (#3705) --- src/cdk/v2/destinations/webhook_v2/utils.js | 16 +- .../destinations/webhook_v2/common.ts | 37 ++++- .../webhook_v2/processor/configuration.ts | 2 +- .../destinations/webhook_v2/router/data.ts | 146 +++++++++++++++++- 4 files changed, 189 insertions(+), 12 deletions(-) diff --git a/src/cdk/v2/destinations/webhook_v2/utils.js b/src/cdk/v2/destinations/webhook_v2/utils.js index 8e04b59ec02..329c5fc0539 100644 --- a/src/cdk/v2/destinations/webhook_v2/utils.js +++ b/src/cdk/v2/destinations/webhook_v2/utils.js @@ -3,7 +3,12 @@ const { groupBy } = require('lodash'); const { createHash } = require('crypto'); const { ConfigurationError } = require('@rudderstack/integrations-lib'); const { BatchUtils } = require('@rudderstack/workflow-engine'); -const { base64Convertor, applyCustomMappings, isEmptyObject } = require('../../../../v0/util'); +const { + base64Convertor, + applyCustomMappings, + isEmptyObject, + applyJSONStringTemplate, +} = require('../../../../v0/util'); const getAuthHeaders = (config) => { let headers; @@ -36,8 +41,13 @@ const getCustomMappings = (message, mapping) => { } }; -// TODO: write a func to evaluate json path template -const addPathParams = (message, webhookUrl) => webhookUrl; +const addPathParams = (message, webhookUrl) => { + try { + return applyJSONStringTemplate(message, `\`${webhookUrl}\``); + } catch (e) { + throw new ConfigurationError(`[Webhook]:: Error in url template: ${e.message}`); + } +}; const excludeMappedFields = (payload, mapping) => { const rawPayload = { ...payload }; diff --git a/test/integrations/destinations/webhook_v2/common.ts b/test/integrations/destinations/webhook_v2/common.ts index c31a7aabada..dafc5853d5a 100644 --- a/test/integrations/destinations/webhook_v2/common.ts +++ b/test/integrations/destinations/webhook_v2/common.ts @@ -41,7 +41,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contact/$traits.userId', + webhookUrl: 'http://abc.com/contacts', auth: 'basicAuth', username: 'test-user', password: '', @@ -92,7 +92,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts/$.traits.userId/', + webhookUrl: 'http://abc.com/contacts/{{$.traits.email}}/', auth: 'apiKeyAuth', apiKeyName: 'x-api-key', apiKeyValue: 'test-api-key', @@ -114,7 +114,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts/$.traits.userId/', + webhookUrl: 'http://abc.com/contacts/{{$.traits.email}}/', auth: 'apiKeyAuth', apiKeyName: 'x-api-key', apiKeyValue: 'test-api-key', @@ -247,6 +247,37 @@ const destinations: Destination[] = [ Transformations: [], WorkspaceID: 'test-workspace-id', }, + { + Config: { + webhookUrl: 'http://abc.com/contacts/{{$.traits.phone}}', + auth: 'noAuth', + method: 'POST', + format: 'JSON', + isBatchingEnabled: true, + maxBatchSize: 4, + headers: [ + { + to: "$.'content-type'", + from: "'application/json'", + }, + { + to: '$.key', + from: '.traits.key', + }, + ], + }, + DestinationDefinition: { + DisplayName: displayName, + ID: '123', + Name: destTypeInUpperCase, + Config: { cdkV2Enabled: true }, + }, + Enabled: true, + ID: '123', + Name: destTypeInUpperCase, + Transformations: [], + WorkspaceID: 'test-workspace-id', + }, ]; const traits = { diff --git a/test/integrations/destinations/webhook_v2/processor/configuration.ts b/test/integrations/destinations/webhook_v2/processor/configuration.ts index 7a1c105ed03..702c20a6fb5 100644 --- a/test/integrations/destinations/webhook_v2/processor/configuration.ts +++ b/test/integrations/destinations/webhook_v2/processor/configuration.ts @@ -87,7 +87,7 @@ export const configuration: ProcessorTestData[] = [ output: transformResultBuilder({ method: 'DELETE', userId: '', - endpoint: 'http://abc.com/contacts/$.traits.userId/', + endpoint: 'http://abc.com/contacts/john.doe@example.com/', headers: { 'x-api-key': 'test-api-key', }, diff --git a/test/integrations/destinations/webhook_v2/router/data.ts b/test/integrations/destinations/webhook_v2/router/data.ts index 44c9f0e6feb..34f16f211f9 100644 --- a/test/integrations/destinations/webhook_v2/router/data.ts +++ b/test/integrations/destinations/webhook_v2/router/data.ts @@ -120,7 +120,48 @@ const routerRequest3 = { destType, }; -// TODO: add failure testcases +const routerRequest4 = { + input: [ + { + message: { + type: 'identify', + userId: 'userId1', + traits: { ...traits, key: 'value1' }, + }, + metadata: generateMetadata(1), + destination: destinations[6], + }, + { + message: { + type: 'identify', + userId: 'userId1', + traits: { ...traits, key: 'value1' }, + }, + metadata: generateMetadata(2), + destination: destinations[6], + }, + { + message: { + type: 'identify', + userId: 'userId1', + traits, + }, + metadata: generateMetadata(3), + destination: destinations[6], + }, + { + message: { + type: 'identify', + userId: 'userId1', + traits: { ...traits, phone: '2234567890' }, + }, + metadata: generateMetadata(4), + destination: destinations[6], + }, + ], + destType, +}; + export const data = [ { id: 'webhook_v2-router-test-1', @@ -147,7 +188,7 @@ export const data = [ version: '1', type: 'REST', method: 'GET', - endpoint: 'http://abc.com/contacts/$.traits.userId/', + endpoint: 'http://abc.com/contacts/john.doe@example.com/', headers: { 'x-api-key': 'test-api-key', }, @@ -196,7 +237,7 @@ export const data = [ version: '1', type: 'REST', method: 'GET', - endpoint: 'http://abc.com/contact/$traits.userId', + endpoint: 'http://abc.com/contacts', headers: { Authorization: 'Basic dGVzdC11c2VyOg==', 'content-type': 'application/json', @@ -228,7 +269,7 @@ export const data = [ version: '1', type: 'REST', method: 'GET', - endpoint: 'http://abc.com/contact/$traits.userId', + endpoint: 'http://abc.com/contacts', headers: { Authorization: 'Basic dGVzdC11c2VyOg==', 'content-type': 'application/json', @@ -260,7 +301,7 @@ export const data = [ version: '1', type: 'REST', method: 'GET', - endpoint: 'http://abc.com/contact/$traits.userId', + endpoint: 'http://abc.com/contacts', headers: { Authorization: 'Basic dGVzdC11c2VyOg==', 'content-type': 'application/json', @@ -347,4 +388,99 @@ export const data = [ }, }, }, + { + id: 'webhook_v2-router-test-4', + name: destType, + description: 'Batch multiple requests based on webhook url and headers', + scenario: 'Framework', + successCriteria: 'All events should be transformed successfully and status code should be 200', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest4, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'http://abc.com/contacts/1234567890', + headers: { + 'content-type': 'application/json', + key: 'value1', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { batch: '[]' }, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1), generateMetadata(2)], + batched: true, + statusCode: 200, + destination: destinations[6], + }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'http://abc.com/contacts/1234567890', + headers: { + 'content-type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { batch: '[]' }, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(3)], + batched: true, + statusCode: 200, + destination: destinations[6], + }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'http://abc.com/contacts/2234567890', + headers: { + 'content-type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { batch: '[]' }, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(4)], + batched: true, + statusCode: 200, + destination: destinations[6], + }, + ], + }, + }, + }, + }, ]; From 263d0758be828402068278c7c5356b65119e7e9a Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Fri, 6 Sep 2024 20:09:56 +0530 Subject: [PATCH 004/147] fix: circular json bugsnag (#3713) --- src/v0/util/index.js | 21 ++++++- src/v0/util/index.test.js | 124 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/src/v0/util/index.js b/src/v0/util/index.js index e1fe8ee9429..c3b9570bc44 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -1552,6 +1552,18 @@ const getErrorStatusCode = (error, defaultStatusCode = HTTP_STATUS_CODES.INTERNA } }; +function isAxiosError(err) { + return ( + Array.isArray(err?.config?.adapter) && + err?.config?.adapter?.length > 1 && + typeof err?.request?.socket === 'object' && + !!err?.request?.protocol && + !!err?.request?.method && + !!err?.request?.path && + !!err?.status + ); +} + /** * Used for generating error response with stats from native and built errors */ @@ -1567,11 +1579,15 @@ function generateErrorObject(error, defTags = {}, shouldEnrichErrorMessage = tru error.authErrorCategory, ); let errorMessage = error.message; + if (isAxiosError(errObject.destinationResponse)) { + delete errObject?.destinationResponse.config; + delete errObject?.destinationResponse.request; + } if (shouldEnrichErrorMessage) { - if (error.destinationResponse) { + if (errObject.destinationResponse) { errorMessage = JSON.stringify({ message: errorMessage, - destinationResponse: error.destinationResponse, + destinationResponse: errObject.destinationResponse, }); } errObject.message = errorMessage; @@ -2411,4 +2427,5 @@ module.exports = { validateEventAndLowerCaseConversion, getRelativePathFromURL, removeEmptyKey, + isAxiosError, }; diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index a8d13ab873e..1b99e5ebb7e 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -8,6 +8,7 @@ const { generateExclusionList, combineBatchRequestsWithSameJobIds, validateEventAndLowerCaseConversion, + isAxiosError, } = require('./index'); const exp = require('constants'); @@ -735,3 +736,126 @@ describe('get relative path from url', () => { expect(utilities.getRelativePathFromURL(null)).toEqual(null); }); }); + +describe('isAxiosError', () => { + const validAxiosError = { + config: { + adapter: ['xhr', 'fetch'], + }, + request: { + socket: {}, + protocol: 'https:', + headers: {}, + method: 'GET', + path: '/api/data', + }, + status: 404, + statusText: 'Not Found', + }; + + it('should return true for a valid Axios error object', () => { + expect(isAxiosError(validAxiosError)).toBe(true); + }); + + it('should return false for null', () => { + expect(isAxiosError(null)).toBe(false); + }); + + it('should return false for undefined', () => { + expect(isAxiosError(undefined)).toBe(false); + }); + + it('should return false for non-object types', () => { + expect(isAxiosError('string')).toBe(false); + expect(isAxiosError(123)).toBe(false); + expect(isAxiosError(true)).toBe(false); + expect(isAxiosError([])).toBe(false); + }); + + it('should return false for an empty object', () => { + expect(isAxiosError({})).toBe(false); + }); + + it('should return false when config is missing', () => { + const { config, ...errorWithoutConfig } = validAxiosError; + expect(isAxiosError(errorWithoutConfig)).toBe(false); + }); + + it('should return false when config.adapter is not an array', () => { + const error = { ...validAxiosError, config: { adapter: 'not an array' } }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when config.adapter has length <= 1', () => { + const error = { ...validAxiosError, config: { adapter: ['some'] } }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when request is missing', () => { + const { request, ...errorWithoutRequest } = validAxiosError; + expect(isAxiosError(errorWithoutRequest)).toBe(false); + }); + + it('should return false when request.socket is missing', () => { + const error = { + ...validAxiosError, + request: { ...validAxiosError.request, socket: undefined }, + }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when request.socket is not an object', () => { + const error = { + ...validAxiosError, + request: { ...validAxiosError.request, socket: 'not an object' }, + }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when request.protocol is missing', () => { + const error = { + ...validAxiosError, + request: { ...validAxiosError.request, protocol: undefined }, + }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when request.method is missing', () => { + const error = { + ...validAxiosError, + request: { ...validAxiosError.request, method: undefined }, + }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when request.path is missing', () => { + const error = { + ...validAxiosError, + request: { ...validAxiosError.request, path: undefined }, + }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when status is missing', () => { + const { status, ...errorWithoutStatus } = validAxiosError; + expect(isAxiosError(errorWithoutStatus)).toBe(false); + }); + + it('should return true when all required properties are present and valid, even with extra properties', () => { + const errorWithExtraProps = { + ...validAxiosError, + extraProp: 'some value', + }; + expect(isAxiosError(errorWithExtraProps)).toBe(true); + }); + + it('should return false when config.adapter is an empty array', () => { + const error = { ...validAxiosError, config: { adapter: [] } }; + expect(isAxiosError(error)).toBe(false); + }); + + it('should return false when status is 0', () => { + const error = { ...validAxiosError, status: 0 }; + expect(isAxiosError(error)).toBe(false); + }); +}); From d381dac3b3dbc8752d88818e679bbe0bde84e27d Mon Sep 17 00:00:00 2001 From: Gauravudia <60897972+Gauravudia@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:10:06 +0530 Subject: [PATCH 005/147] refactor: rename webhook v2 destination to http (#3722) --- .../{webhook_v2 => http}/procWorkflow.yaml | 5 ++--- .../{webhook_v2 => http}/rtWorkflow.yaml | 0 .../{webhook_v2 => http}/utils.js | 8 ++++---- .../{webhook_v2 => http}/common.ts | 20 +++++++++---------- .../processor/configuration.ts | 14 ++++++------- .../{webhook_v2 => http}/processor/data.ts | 0 .../{webhook_v2 => http}/router/data.ts | 18 ++++++----------- 7 files changed, 29 insertions(+), 36 deletions(-) rename src/cdk/v2/destinations/{webhook_v2 => http}/procWorkflow.yaml (94%) rename src/cdk/v2/destinations/{webhook_v2 => http}/rtWorkflow.yaml (100%) rename src/cdk/v2/destinations/{webhook_v2 => http}/utils.js (93%) rename test/integrations/destinations/{webhook_v2 => http}/common.ts (93%) rename test/integrations/destinations/{webhook_v2 => http}/processor/configuration.ts (93%) rename test/integrations/destinations/{webhook_v2 => http}/processor/data.ts (100%) rename test/integrations/destinations/{webhook_v2 => http}/router/data.ts (97%) diff --git a/src/cdk/v2/destinations/webhook_v2/procWorkflow.yaml b/src/cdk/v2/destinations/http/procWorkflow.yaml similarity index 94% rename from src/cdk/v2/destinations/webhook_v2/procWorkflow.yaml rename to src/cdk/v2/destinations/http/procWorkflow.yaml index 873a9807ce3..080dcdd80af 100644 --- a/src/cdk/v2/destinations/webhook_v2/procWorkflow.yaml +++ b/src/cdk/v2/destinations/http/procWorkflow.yaml @@ -3,7 +3,6 @@ bindings: path: ../../../../constants - path: ../../bindings/jsontemplate exportAll: true - - path: ../../../../v0/destinations/webhook/utils - name: getHashFromArray path: ../../../../v0/util - name: getIntegrationsObj @@ -19,7 +18,7 @@ bindings: steps: - name: validateInput template: | - $.assertConfig(.destination.Config.webhookUrl, "Webhook URL required. Aborting"); + $.assertConfig(.destination.Config.apiUrl, "API URL is required. Aborting"); $.assertConfig(!(.destination.Config.auth === "basicAuth" && !(.destination.Config.username)), "Username is required for Basic Authentication. Aborting"); $.assertConfig(!(.destination.Config.auth === "bearerTokenAuth" && !(.destination.Config.bearerToken)), "Token is required for Bearer Token Authentication. Aborting"); $.assertConfig(!(.destination.Config.auth === "apiKeyAuth" && !(.destination.Config.apiKeyName)), "API Key Name is required for API Key Authentication. Aborting"); @@ -48,7 +47,7 @@ steps: - name: deduceEndPoint template: | - $.context.endpoint = $.addPathParams(.message, .destination.Config.webhookUrl); + $.context.endpoint = $.addPathParams(.message, .destination.Config.apiUrl); - name: prepareBody template: | diff --git a/src/cdk/v2/destinations/webhook_v2/rtWorkflow.yaml b/src/cdk/v2/destinations/http/rtWorkflow.yaml similarity index 100% rename from src/cdk/v2/destinations/webhook_v2/rtWorkflow.yaml rename to src/cdk/v2/destinations/http/rtWorkflow.yaml diff --git a/src/cdk/v2/destinations/webhook_v2/utils.js b/src/cdk/v2/destinations/http/utils.js similarity index 93% rename from src/cdk/v2/destinations/webhook_v2/utils.js rename to src/cdk/v2/destinations/http/utils.js index 329c5fc0539..355eb034870 100644 --- a/src/cdk/v2/destinations/webhook_v2/utils.js +++ b/src/cdk/v2/destinations/http/utils.js @@ -37,15 +37,15 @@ const getCustomMappings = (message, mapping) => { try { return applyCustomMappings(message, mapping); } catch (e) { - throw new ConfigurationError(`[Webhook]:: Error in custom mappings: ${e.message}`); + throw new ConfigurationError(`Error in custom mappings: ${e.message}`); } }; -const addPathParams = (message, webhookUrl) => { +const addPathParams = (message, apiUrl) => { try { - return applyJSONStringTemplate(message, `\`${webhookUrl}\``); + return applyJSONStringTemplate(message, `\`${apiUrl}\``); } catch (e) { - throw new ConfigurationError(`[Webhook]:: Error in url template: ${e.message}`); + throw new ConfigurationError(`Error in api url template: ${e.message}`); } }; diff --git a/test/integrations/destinations/webhook_v2/common.ts b/test/integrations/destinations/http/common.ts similarity index 93% rename from test/integrations/destinations/webhook_v2/common.ts rename to test/integrations/destinations/http/common.ts index dafc5853d5a..f0c8bc8a337 100644 --- a/test/integrations/destinations/webhook_v2/common.ts +++ b/test/integrations/destinations/http/common.ts @@ -1,12 +1,12 @@ import { Destination } from '../../../../src/types'; -const destType = 'webhook_v2'; -const destTypeInUpperCase = 'WEBHOOK_V2'; -const displayName = 'Webhook V2'; +const destType = 'http'; +const destTypeInUpperCase = 'HTTP'; +const displayName = 'HTTP'; const destinations: Destination[] = [ { Config: { - webhookUrl: 'http://abc.com/contacts', + apiUrl: 'http://abc.com/contacts', auth: 'noAuth', method: 'POST', format: 'JSON', @@ -41,7 +41,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts', + apiUrl: 'http://abc.com/contacts', auth: 'basicAuth', username: 'test-user', password: '', @@ -92,7 +92,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts/{{$.traits.email}}/', + apiUrl: 'http://abc.com/contacts/{{$.traits.email}}/', auth: 'apiKeyAuth', apiKeyName: 'x-api-key', apiKeyValue: 'test-api-key', @@ -114,7 +114,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts/{{$.traits.email}}/', + apiUrl: 'http://abc.com/contacts/{{$.traits.email}}/', auth: 'apiKeyAuth', apiKeyName: 'x-api-key', apiKeyValue: 'test-api-key', @@ -136,7 +136,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/events', + apiUrl: 'http://abc.com/events', auth: 'bearerTokenAuth', bearerToken: 'test-token', method: 'POST', @@ -196,7 +196,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/events', + apiUrl: 'http://abc.com/events', auth: 'noAuth', method: 'POST', format: 'JSON', @@ -249,7 +249,7 @@ const destinations: Destination[] = [ }, { Config: { - webhookUrl: 'http://abc.com/contacts/{{$.traits.phone}}', + apiUrl: 'http://abc.com/contacts/{{$.traits.phone}}', auth: 'noAuth', method: 'POST', format: 'JSON', diff --git a/test/integrations/destinations/webhook_v2/processor/configuration.ts b/test/integrations/destinations/http/processor/configuration.ts similarity index 93% rename from test/integrations/destinations/webhook_v2/processor/configuration.ts rename to test/integrations/destinations/http/processor/configuration.ts index 702c20a6fb5..b493a236ee0 100644 --- a/test/integrations/destinations/webhook_v2/processor/configuration.ts +++ b/test/integrations/destinations/http/processor/configuration.ts @@ -4,7 +4,7 @@ import { destType, destinations, properties, traits } from '../common'; export const configuration: ProcessorTestData[] = [ { - id: 'webhook_v2-configuration-test-1', + id: 'http-configuration-test-1', name: destType, description: 'Identify call with properties mapping', scenario: 'Business', @@ -36,7 +36,7 @@ export const configuration: ProcessorTestData[] = [ output: transformResultBuilder({ method: 'POST', userId: '', - endpoint: destinations[0].Config.webhookUrl, + endpoint: destinations[0].Config.apiUrl, JSON: { contacts: { first_name: 'John', @@ -55,7 +55,7 @@ export const configuration: ProcessorTestData[] = [ }, }, { - id: 'webhook_v2-configuration-test-2', + id: 'http-configuration-test-2', name: destType, description: 'Identify call with api key auth, delete method and path params', scenario: 'Business', @@ -100,7 +100,7 @@ export const configuration: ProcessorTestData[] = [ }, }, { - id: 'webhook_v2-configuration-test-3', + id: 'http-configuration-test-3', name: destType, description: 'Track call with basic auth, get method, headers and query params mapping', scenario: 'Business', @@ -132,7 +132,7 @@ export const configuration: ProcessorTestData[] = [ output: transformResultBuilder({ method: 'GET', userId: '', - endpoint: destinations[1].Config.webhookUrl, + endpoint: destinations[1].Config.apiUrl, headers: { Authorization: 'Basic dGVzdC11c2VyOg==', h1: 'val1', @@ -151,7 +151,7 @@ export const configuration: ProcessorTestData[] = [ }, }, { - id: 'webhook_v2-configuration-test-4', + id: 'http-configuration-test-4', name: destType, description: 'Track call with bearer token, xml format, post method, additional headers and properties mapping', @@ -185,7 +185,7 @@ export const configuration: ProcessorTestData[] = [ output: transformResultBuilder({ method: 'POST', userId: '', - endpoint: destinations[4].Config.webhookUrl, + endpoint: destinations[4].Config.apiUrl, headers: { Authorization: 'Bearer test-token', h1: 'val1', diff --git a/test/integrations/destinations/webhook_v2/processor/data.ts b/test/integrations/destinations/http/processor/data.ts similarity index 100% rename from test/integrations/destinations/webhook_v2/processor/data.ts rename to test/integrations/destinations/http/processor/data.ts diff --git a/test/integrations/destinations/webhook_v2/router/data.ts b/test/integrations/destinations/http/router/data.ts similarity index 97% rename from test/integrations/destinations/webhook_v2/router/data.ts rename to test/integrations/destinations/http/router/data.ts index 34f16f211f9..ea14ec73418 100644 --- a/test/integrations/destinations/webhook_v2/router/data.ts +++ b/test/integrations/destinations/http/router/data.ts @@ -1,11 +1,5 @@ import { generateMetadata } from '../../../testUtils'; -import { - destType, - destinations, - traits, - properties, - RouterInstrumentationErrorStatTags, -} from '../common'; +import { destType, destinations, traits, properties } from '../common'; const routerRequest1 = { input: [ @@ -164,7 +158,7 @@ const routerRequest4 = { export const data = [ { - id: 'webhook_v2-router-test-1', + id: 'http-router-test-1', name: destType, description: 'Batch multiple GET requests in a single batch with given batch size', scenario: 'Framework', @@ -212,7 +206,7 @@ export const data = [ }, }, { - id: 'webhook_v2-router-test-2', + id: 'http-router-test-2', name: destType, description: 'Batch multiple GET requests in multiple batches when number of requests are greater then given batch size', @@ -334,7 +328,7 @@ export const data = [ }, }, { - id: 'webhook_v2-router-test-3', + id: 'http-router-test-3', name: destType, description: 'Batch multiple POST requests with properties mappings', scenario: 'Framework', @@ -389,9 +383,9 @@ export const data = [ }, }, { - id: 'webhook_v2-router-test-4', + id: 'http-router-test-4', name: destType, - description: 'Batch multiple requests based on webhook url and headers', + description: 'Batch multiple requests based on api url and headers', scenario: 'Framework', successCriteria: 'All events should be transformed successfully and status code should be 200', feature: 'router', From f77d2ab4125a1a44bba95bebbee25bb4fac032da Mon Sep 17 00:00:00 2001 From: Anant Jain <62471433+anantjain45823@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:27:20 +0530 Subject: [PATCH 006/147] feat: onboard X(Twiiter) Audience (#3696) * feat: onboard X(Twiiter) Audience * chore: add test cases * chore: add router test cases * chore: small fixes * fix: common mock value for twitter ads and audience * chore: config fallback * fix: root level batching stringification --- src/features.json | 1 + src/v0/destinations/x_audience/config.js | 5 + src/v0/destinations/x_audience/transform.js | 76 ++++++ src/v0/destinations/x_audience/utils.js | 241 ++++++++++++++++++ .../destinations/x_audience/common.ts | 27 ++ .../destinations/x_audience/processor/data.ts | 236 +++++++++++++++++ .../destinations/x_audience/router/data.ts | 235 +++++++++++++++++ 7 files changed, 821 insertions(+) create mode 100644 src/v0/destinations/x_audience/config.js create mode 100644 src/v0/destinations/x_audience/transform.js create mode 100644 src/v0/destinations/x_audience/utils.js create mode 100644 test/integrations/destinations/x_audience/common.ts create mode 100644 test/integrations/destinations/x_audience/processor/data.ts create mode 100644 test/integrations/destinations/x_audience/router/data.ts diff --git a/src/features.json b/src/features.json index 77ab5cb2437..503df3eccfc 100644 --- a/src/features.json +++ b/src/features.json @@ -77,6 +77,7 @@ "CLICKSEND": true, "ZOHO": true, "CORDIAL": true, + "X_AUDIENCE": true, "BLOOMREACH_CATALOG": true, "SMARTLY": true, "WEBHOOK_V2": true diff --git a/src/v0/destinations/x_audience/config.js b/src/v0/destinations/x_audience/config.js new file mode 100644 index 00000000000..37b35c00b70 --- /dev/null +++ b/src/v0/destinations/x_audience/config.js @@ -0,0 +1,5 @@ +const BASE_URL = + 'https://ads-api.twitter.com/12/accounts/:account_id/custom_audiences/:audience_id/users'; +const MAX_PAYLOAD_SIZE_IN_BYTES = 4000000; +const MAX_OPERATIONS = 2500; +module.exports = { BASE_URL, MAX_PAYLOAD_SIZE_IN_BYTES, MAX_OPERATIONS }; diff --git a/src/v0/destinations/x_audience/transform.js b/src/v0/destinations/x_audience/transform.js new file mode 100644 index 00000000000..69f76507e56 --- /dev/null +++ b/src/v0/destinations/x_audience/transform.js @@ -0,0 +1,76 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const { + removeUndefinedAndNullAndEmptyValues, + InstrumentationError, + ConfigurationError, +} = require('@rudderstack/integrations-lib'); +const { handleRtTfSingleEventError } = require('../../util'); +const { batchEvents, buildResponseWithJSON, getUserDetails } = require('./utils'); +/** + * This function returns audience object in the form of destination API + * @param {*} message + * @param {*} destination + * @param {*} metadata + */ +const processRecordEvent = (message, config) => { + const { fields, action, type } = message; + if (type !== 'record') { + throw new InstrumentationError(`[X AUDIENCE]: ${type} is not supported`); + } + const { accountId, audienceId } = { config }; + if (accountId) { + throw new ConfigurationError('[X AUDIENCE]: Account Id not found'); + } + if (audienceId) { + throw new ConfigurationError('[X AUDIENCE]: Audience Id not found'); + } + const { effective_at, expires_at } = fields; + const users = [getUserDetails(fields, config)]; + + return { + operation_type: action !== 'delete' ? 'Update' : 'Delete', + params: removeUndefinedAndNullAndEmptyValues({ + effective_at, + expires_at, + users, + }), + }; +}; +const process = (event) => { + const { message, destination, metadata } = event; + const Config = destination.Config || destination.config; + + const payload = [processRecordEvent(message, Config)]; + return buildResponseWithJSON(payload, Config, metadata); +}; +const processRouterDest = async (inputs, reqMetadata) => { + const responseList = []; // list containing single track event payload + const errorRespList = []; // list of error + const { destination } = inputs[0]; + const Config = destination.Config || destination.config; + inputs.map(async (event) => { + try { + if (event.message.statusCode) { + // already transformed event + responseList.push(event); + } else { + // if not transformed + responseList.push({ + message: processRecordEvent(event.message, Config), + metadata: event.metadata, + destination, + }); + } + } catch (error) { + const errRespEvent = handleRtTfSingleEventError(event, error, reqMetadata); + errorRespList.push(errRespEvent); + } + }); + let batchedResponseList = []; + if (responseList.length > 0) { + batchedResponseList = batchEvents(responseList, destination); + } + return [...batchedResponseList, ...errorRespList]; +}; + +module.exports = { process, processRouterDest, buildResponseWithJSON }; diff --git a/src/v0/destinations/x_audience/utils.js b/src/v0/destinations/x_audience/utils.js new file mode 100644 index 00000000000..62c825efac8 --- /dev/null +++ b/src/v0/destinations/x_audience/utils.js @@ -0,0 +1,241 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const sha256 = require('sha256'); +const lodash = require('lodash'); +const jsonSize = require('json-size'); +const { OAuthSecretError } = require('@rudderstack/integrations-lib'); +const { + defaultRequestConfig, + getSuccessRespEvents, + removeUndefinedAndNullAndEmptyValues, +} = require('../../util'); +const { MAX_PAYLOAD_SIZE_IN_BYTES, BASE_URL, MAX_OPERATIONS } = require('./config'); +const { getAuthHeaderForRequest } = require('../twitter_ads/util'); +const { JSON_MIME_TYPE } = require('../../util/constant'); + +const getOAuthFields = ({ secret }) => { + if (!secret) { + throw new OAuthSecretError('[X Audience]:: OAuth - access keys not found'); + } + const oAuthObject = { + consumerKey: secret.consumerKey, + consumerSecret: secret.consumerSecret, + accessToken: secret.accessToken, + accessTokenSecret: secret.accessTokenSecret, + }; + return oAuthObject; +}; + +// Docs: https://developer.x.com/en/docs/x-ads-api/audiences/api-reference/custom-audience-user +const buildResponseWithJSON = (payload, config, metadata) => { + const response = defaultRequestConfig(); + const accountId = Object.values(JSON.parse(config.accountId))[0]; + response.endpoint = BASE_URL.replace(':account_id', accountId).replace( + ':audience_id', + config.audienceId, + ); + response.body.JSON_ARRAY = { batch: JSON.stringify(payload) }; + // required to be in accordance with oauth package + const request = { + url: response.endpoint, + method: response.method, + body: response.body.JSON, + }; + + const oAuthObject = getOAuthFields(metadata); + const authHeader = getAuthHeaderForRequest(request, oAuthObject).Authorization; + response.headers = { + Authorization: authHeader, + 'Content-Type': JSON_MIME_TYPE, + }; + return response; +}; + +/** + * This fucntion groups the response list based upoin 3 fields that are + * 1. operation_type + * 2. effective_at + * 3. expires_at + * @param {*} respList + * @returns object + */ +const groupResponsesUsingOperationAndTime = (respList) => { + const eventGroups = lodash.groupBy(respList, (item) => [ + item.message.operation_type, + item.message.params.effective_at, + item.message.params.expires_at, + ]); + return eventGroups; +}; +/** + * This function groups the operation object list based upon max sized or batch size allowed + * and returns the final batched request + * @param {*} operationObjectList + */ +const getFinalResponseList = (operationObjectList, destination) => { + const respList = []; + let currentMetadataList = []; + let currentBatchedRequest = []; + let metadataWithSecret; // used for authentication purposes + operationObjectList.forEach((operationObject) => { + const { payload, metadataList } = operationObject; + metadataWithSecret = { secret: metadataList[0].secret }; + if ( + currentBatchedRequest.length >= MAX_OPERATIONS || + jsonSize([...currentBatchedRequest, payload]) > MAX_PAYLOAD_SIZE_IN_BYTES + ) { + respList.push( + getSuccessRespEvents( + buildResponseWithJSON( + currentBatchedRequest, + destination.Config || destination.config, + metadataWithSecret, + ), + currentMetadataList, + destination, + true, + ), + ); + currentBatchedRequest = [payload]; + currentMetadataList = metadataList; + } else { + currentBatchedRequest.push(payload); + currentMetadataList.push(...metadataList); + } + }); + // pushing the remainder operation payloads as well + respList.push( + getSuccessRespEvents( + buildResponseWithJSON( + currentBatchedRequest, + destination.Config || destination.config, + metadataWithSecret, + ), + currentMetadataList, + destination, + true, + ), + ); + return respList; +}; + +/** + * This function takes in object containing key as the grouped parameter + * and values as list of all concerned payloads ( having the same key ). + * Then it makes the list of operationObject based upon + * operation and effective and expires time and json size of payload of one object + * @param {*} eventGroups + * @returns + */ +const getOperationObjectList = (eventGroups) => { + const operationList = []; + Object.keys(eventGroups).forEach((group) => { + const { operation_type, params } = eventGroups[group][0].message; + const { effective_at, expires_at } = params; + let currentUserList = []; + let currentMetadata = []; + eventGroups[group].forEach((event) => { + const newUsers = event.message.params.users; + // calculating size before appending the user and metadata list + if (jsonSize([...currentUserList, ...newUsers]) < MAX_PAYLOAD_SIZE_IN_BYTES) { + currentUserList.push(...event.message.params.users); + currentMetadata.push(event.metadata); + } else { + operationList.push({ + payload: { + operation_type, + params: removeUndefinedAndNullAndEmptyValues({ + effective_at, + expires_at, + users: currentUserList, + }), + }, + metadataList: currentMetadata, + }); + currentUserList = event.message.params.users; + currentMetadata = event.metadata; + } + }); + // all the remaining user and metadata list used in one list + operationList.push({ + payload: { + operation_type, + params: removeUndefinedAndNullAndEmptyValues({ + effective_at, + expires_at, + users: currentUserList, + }), + }, + metadataList: currentMetadata, + }); + }); + return operationList; +}; + +/** + * Input: [{ + message: { + operation_type: 'Delete', + params: { + effective_at, + expires_at, + users, + }, + }, + metadata, + destination, + }] + * @param {*} responseList + */ +const batchEvents = (responseList, destination) => { + const eventGroups = groupResponsesUsingOperationAndTime(responseList); + const operationObjectList = getOperationObjectList(eventGroups); + /* at this point we will a list of json payloads in the following format + operationObjectList = [ + { + payload:{ + operation_type: 'Delete', + params: { + effective_at, + expires_at, + users, + }, + metadata: + [ + {jobId:1}, {jobId:2} + ] + } + ] + */ + return getFinalResponseList(operationObjectList, destination); +}; + +const getUserDetails = (fields, config) => { + const { enableHash } = config; + const { email, phone_number, handle, device_id, twitter_id, partner_user_id } = fields; + const user = {}; + if (email) { + const emailList = email.split(','); + user.email = enableHash ? emailList.map(sha256) : emailList; + } + if (phone_number) { + const phone_numberList = phone_number.split(','); + user.phone_number = enableHash ? phone_numberList.map(sha256) : phone_numberList; + } + if (handle) { + const handleList = handle.split(','); + user.handle = enableHash ? handleList.map(sha256) : handleList; + } + if (device_id) { + const device_idList = device_id.split(','); + user.device_id = enableHash ? device_idList.map(sha256) : device_idList; + } + if (twitter_id) { + const twitter_idList = twitter_id.split(','); + user.twitter_id = enableHash ? twitter_idList.map(sha256) : twitter_idList; + } + if (partner_user_id) { + user.partner_user_id = partner_user_id.split(','); + } + return removeUndefinedAndNullAndEmptyValues(user); +}; +module.exports = { getOAuthFields, batchEvents, getUserDetails, buildResponseWithJSON }; diff --git a/test/integrations/destinations/x_audience/common.ts b/test/integrations/destinations/x_audience/common.ts new file mode 100644 index 00000000000..547e04ba848 --- /dev/null +++ b/test/integrations/destinations/x_audience/common.ts @@ -0,0 +1,27 @@ +export const authHeaderConstant = + 'OAuth oauth_consumer_key="qwe", oauth_nonce="V1kMh028kZLLhfeYozuL0B45Pcx6LvuW", oauth_signature="Di4cuoGv4PnCMMEeqfWTcqhvdwc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1685603652", oauth_token="dummyAccessToken", oauth_version="1.0"'; +export const destination = { + Config: { + accountId: '{"Dummy Name":"1234"}', + audienceId: 'dummyId', + }, + ID: 'xpixel-1234', +}; + +export const generateMetadata = (jobId: number, userId?: string): any => { + return { + jobId, + attemptNum: 1, + userId: userId || 'default-userId', + sourceId: 'default-sourceId', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + secret: { + consumerKey: 'validConsumerKey', + consumerSecret: 'validConsumerSecret', + accessToken: 'validAccessToken', + accessTokenSecret: 'validAccessTokenSecret', + }, + dontBatch: false, + }; +}; diff --git a/test/integrations/destinations/x_audience/processor/data.ts b/test/integrations/destinations/x_audience/processor/data.ts new file mode 100644 index 00000000000..deada7ab58c --- /dev/null +++ b/test/integrations/destinations/x_audience/processor/data.ts @@ -0,0 +1,236 @@ +import { destination, authHeaderConstant, generateMetadata } from '../common'; + +const fields = { + email: 'abc@xyz.com,a+1@xyz.com', + phone_number: '98765433232,21323', + handle: '@abc,@xyz', + twitter_id: 'tid1,tid2', + partner_user_id: 'puid1,puid2', +}; + +export const data = [ + { + name: 'x_audience', + description: 'All traits are present with hash enbaled for the audience with insert operation', + successCriteria: 'It should be passed with 200 Ok with all traits mapped after hashing', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { ...destination, Config: { ...destination.Config, enableHash: true } }, + message: { + type: 'record', + action: 'insert', + fields: { + ...fields, + device_id: 'did123,did456', + effective_at: '2024-05-15T00:00:00Z', + expires_at: '2025-05-15T00:00:00Z', + }, + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ads-api.twitter.com/12/accounts/1234/custom_audiences/dummyId/users', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { + batch: JSON.stringify([ + { + operation_type: 'Update', + params: { + effective_at: '2024-05-15T00:00:00Z', + expires_at: '2025-05-15T00:00:00Z', + users: [ + { + email: [ + 'ee278943de84e5d6243578ee1a1057bcce0e50daad9755f45dfa64b60b13bc5d', + '27a1b87036e9b0f43235026e7cb1493f1838b6fe41965ea04486d82e499f8401', + ], + phone_number: [ + '76742d946d9f6d0c844da5648e461896227782ccf1cd0db64573f39dbd92e05f', + '69c3bf36e0476c08a883fd6a995f67fc6d362c865549312fb5170737945fd073', + ], + handle: [ + '771c7b0ff2eff313009a81739307c3f7cde375acd7902b11061266a899a375f6', + '7bde3c2d41eab9043df37c9adf4f5f7591c632340d1cabc894e438e881fdd5f6', + ], + device_id: [ + '85a598fd6c8834f2d4da3d6886bb53d0032021e137307ec91d3f0da78e9bfa5b', + '936444046bea8b5d9de6bcae59b6f196ea4bb59945bc93e84bc9533dbf3e01c0', + ], + twitter_id: [ + 'a70d41727df61f21ce0ec81cca51c58f516b6151275d9293d7437bf15fa22e0d', + 'e39994d056999d79ff5a35b02cf2af946fc14bd7bd1b799b58619796584af02f', + ], + partner_user_id: ['puid1', 'puid2'], + }, + ], + }, + }, + ]), + }, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'x_audience', + description: 'All traits are present with hash disabled for the audience with delete operation', + successCriteria: 'It should be passed with 200 Ok with all traits mapped without hashing', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'record', + action: 'delete', + fields, + channel: 'sources', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ads-api.twitter.com/12/accounts/1234/custom_audiences/dummyId/users', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { + batch: JSON.stringify([ + { + operation_type: 'Delete', + params: { + users: [ + { + email: ['abc@xyz.com', 'a+1@xyz.com'], + phone_number: ['98765433232', '21323'], + handle: ['@abc', '@xyz'], + twitter_id: ['tid1', 'tid2'], + partner_user_id: ['puid1', 'puid2'], + }, + ], + }, + }, + ]), + }, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'x_audience', + description: 'Type Validation case', + successCriteria: 'It should be passed with 200 Ok giving validation error', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'identify', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + statusCode: 400, + error: '[X AUDIENCE]: identify is not supported', + statTags: { + errorCategory: 'dataValidation', + destinationId: 'default-destinationId', + errorType: 'instrumentation', + destType: 'X_AUDIENCE', + module: 'destination', + implementation: 'native', + workspaceId: 'default-workspaceId', + feature: 'processor', + }, + }, + ], + }, + }, + }, +].map((tc) => ({ + ...tc, + mockFns: (_) => { + jest.mock('../../../../../src/v0/destinations/twitter_ads/util', () => ({ + getAuthHeaderForRequest: (_a, _b) => { + return { Authorization: authHeaderConstant }; + }, + })); + }, +})); diff --git a/test/integrations/destinations/x_audience/router/data.ts b/test/integrations/destinations/x_audience/router/data.ts new file mode 100644 index 00000000000..228a5ecd894 --- /dev/null +++ b/test/integrations/destinations/x_audience/router/data.ts @@ -0,0 +1,235 @@ +import { destination, authHeaderConstant, generateMetadata } from '../common'; + +export const data = [ + { + name: 'x_audience', + id: 'router-test-1', + description: + 'case with 2 record with no effective and expire at date with insert operations, 4 insert with 2 each having same effective and expire at and one delete and one failure event', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + message: { + type: 'record', + action: 'delete', + fields: { email: 'email1@abc.com' }, + channel: 'sources', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { email: 'email2@abc.com' }, + channel: 'sources', + context: {}, + recordId: '2', + }, + metadata: generateMetadata(2), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { email: 'email3@abc.com' }, + channel: 'sources', + context: {}, + recordId: '3', + }, + metadata: generateMetadata(3), + }, + { + destination, + message: { + type: 'record', + action: 'update', + fields: { + email: 'email4@abc.com', + expires_at: 'some date', + effective_at: 'some effective date', + }, + channel: 'sources', + context: {}, + recordId: '4', + }, + metadata: generateMetadata(4), + }, + { + destination, + message: { + type: 'record', + action: 'update', + fields: { + email: 'email5@abc.com', + expires_at: 'some date', + effective_at: 'some effective date', + }, + channel: 'sources', + context: {}, + recordId: '5', + }, + metadata: generateMetadata(5), + }, + { + destination, + message: { + type: 'identify', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(6), + }, + ], + destType: 'x_audience', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: true, + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ads-api.twitter.com/12/accounts/1234/custom_audiences/dummyId/users', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { + batch: JSON.stringify([ + { + operation_type: 'Delete', + params: { + users: [ + { + email: ['email1@abc.com'], + }, + ], + }, + }, + { + operation_type: 'Update', + params: { + users: [ + { + email: ['email2@abc.com'], + }, + { + email: ['email3@abc.com'], + }, + ], + }, + }, + ]), + }, + XML: {}, + FORM: {}, + }, + files: {}, + }, + destination, + metadata: [generateMetadata(1), generateMetadata(2), generateMetadata(3)], + statusCode: 200, + }, + { + batched: true, + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ads-api.twitter.com/12/accounts/1234/custom_audiences/dummyId/users', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: {}, + JSON_ARRAY: { + batch: JSON.stringify([ + { + operation_type: 'Update', + params: { + effective_at: 'some effective date', + expires_at: 'some date', + users: [ + { + email: ['email4@abc.com'], + }, + { + email: ['email5@abc.com'], + }, + ], + }, + }, + ]), + }, + XML: {}, + FORM: {}, + }, + files: {}, + }, + destination, + metadata: [generateMetadata(4), generateMetadata(5)], + statusCode: 200, + }, + { + metadata: [generateMetadata(6)], + destination, + batched: false, + statusCode: 400, + error: '[X AUDIENCE]: identify is not supported', + statTags: { + errorCategory: 'dataValidation', + destinationId: 'default-destinationId', + errorType: 'instrumentation', + destType: 'X_AUDIENCE', + module: 'destination', + implementation: 'native', + workspaceId: 'default-workspaceId', + feature: 'router', + }, + }, + ], + }, + }, + }, + }, +].map((tc) => ({ + ...tc, + mockFns: (_) => { + jest.mock('../../../../../src/v0/destinations/twitter_ads/util', () => ({ + getAuthHeaderForRequest: (_a, _b) => { + return { Authorization: authHeaderConstant }; + }, + })); + jest.mock('../../../../../src/v0/destinations/x_audience/config', () => ({ + BASE_URL: + 'https://ads-api.twitter.com/12/accounts/:account_id/custom_audiences/:audience_id/users', + MAX_PAYLOAD_SIZE_IN_BYTES: 40000, + MAX_OPERATIONS: 2, + })); + }, +})); From 8dcf1b3c5aff424d39bece8c9912ec4a1eb221ea Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Wed, 11 Sep 2024 12:05:07 +0530 Subject: [PATCH 007/147] fix: added support for window stabilization fix through envs (#3720) * fix: added support for window stabilization fix through envs * fix: updated the error message matching condition for race condition when spinning up the fn --- src/util/openfaas/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/openfaas/index.js b/src/util/openfaas/index.js index 1f44df86bba..2411395bc3f 100644 --- a/src/util/openfaas/index.js +++ b/src/util/openfaas/index.js @@ -45,6 +45,7 @@ const FAAS_AST_FN_NAME = 'fn-ast'; const CUSTOM_NETWORK_POLICY_WORKSPACE_IDS = process.env.CUSTOM_NETWORK_POLICY_WORKSPACE_IDS || ''; const customNetworkPolicyWorkspaceIds = CUSTOM_NETWORK_POLICY_WORKSPACE_IDS.split(','); const CUSTOMER_TIER = process.env.CUSTOMER_TIER || 'shared'; +const FAAS_SCALE_DOWN_WINDOW = process.env.FAAS_SCALE_DOWN_WINDOW || ''; // Go time values are supported ( max 5m or 300s ) // Initialise node cache const functionListCache = new NodeCache(); @@ -243,7 +244,7 @@ const deployFaasFunction = async ( if ( ((error.statusCode === 500 || error.statusCode === 400) && error.message.includes('already exists')) || - (error.statusCode === 409 && error.message.includes('Conflict change already made')) + (error.statusCode === 409 && error.message.includes('Conflicting change already made')) ) { setFunctionInCache(functionName); throw new RetryRequestError(`${functionName} already exists`); @@ -328,6 +329,10 @@ function buildOpenfaasFn(name, code, versionId, libraryVersionIDs, testMode, trM 'customer-tier': CUSTOMER_TIER, }; + if (FAAS_SCALE_DOWN_WINDOW !== '') { + labels['com.openfaas.scale.down.window'] = FAAS_SCALE_DOWN_WINDOW; + } + if (trMetadata.workspaceId && customNetworkPolicyWorkspaceIds.includes(trMetadata.workspaceId)) { labels['custom-network-policy'] = 'true'; } From b4f4dd1c43f8fd4b4f744413d79cfe8f5f77708b Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:26:23 +0530 Subject: [PATCH 008/147] feat: add source id isolation for reverse etl (#3496) * feat: add job run id level isolation * feat: add group by sourceID for rETL * fix: lint isues * fix: lint issues * fix: component test cases * chore: add fallback to destination and source ids * chore: revert test cases * chore: refactor to use sources.job_id to group events --- src/services/destination/cdkV2Integration.ts | 70 +++++------ src/services/destination/nativeIntegration.ts | 7 +- src/v0/util/index.js | 22 +++- src/v0/util/index.test.js | 111 +++++++++++++++++- 4 files changed, 163 insertions(+), 47 deletions(-) diff --git a/src/services/destination/cdkV2Integration.ts b/src/services/destination/cdkV2Integration.ts index a91bc5674ba..0789a98c1e7 100644 --- a/src/services/destination/cdkV2Integration.ts +++ b/src/services/destination/cdkV2Integration.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable class-methods-use-this */ import { TransformationError } from '@rudderstack/integrations-lib'; -import groupBy from 'lodash/groupBy'; import { processCdkV2Workflow } from '../../cdk/v2/handler'; import { DestinationService } from '../../interfaces/DestinationService'; import { @@ -20,6 +19,7 @@ import { } from '../../types/index'; import stats from '../../util/stats'; import { CatchErr } from '../../util/types'; +import { groupRouterTransformEvents } from '../../v0/util'; import tags from '../../v0/util/tags'; import { DestinationPostTransformationService } from './postTransformation'; @@ -112,46 +112,38 @@ export class CDKV2DestinationService implements DestinationService { _version: string, requestMetadata: NonNullable, ): Promise { - const allDestEvents: object = groupBy( - events, - (ev: RouterTransformationRequestData) => ev.destination?.ID, - ); + const groupedEvents: RouterTransformationRequestData[][] = groupRouterTransformEvents(events); const response: RouterTransformationResponse[][] = await Promise.all( - Object.values(allDestEvents).map( - async (destInputArray: RouterTransformationRequestData[]) => { - const metaTo = this.getTags( - destinationType, - destInputArray[0].metadata.destinationId, - destInputArray[0].metadata.workspaceId, - tags.FEATURES.ROUTER, - ); - metaTo.metadata = destInputArray[0].metadata; - try { - const doRouterTransformationResponse: RouterTransformationResponse[] = - await processCdkV2Workflow( - destinationType, - destInputArray, - tags.FEATURES.ROUTER, - requestMetadata, - ); - return DestinationPostTransformationService.handleRouterTransformSuccessEvents( - doRouterTransformationResponse, - undefined, - metaTo, - tags.IMPLEMENTATIONS.CDK_V2, - destinationType.toUpperCase(), + groupedEvents.map(async (destInputArray: RouterTransformationRequestData[]) => { + const metaTo = this.getTags( + destinationType, + destInputArray[0].metadata.destinationId, + destInputArray[0].metadata.workspaceId, + tags.FEATURES.ROUTER, + ); + metaTo.metadata = destInputArray[0].metadata; + try { + const doRouterTransformationResponse: RouterTransformationResponse[] = + await processCdkV2Workflow( + destinationType, + destInputArray, + tags.FEATURES.ROUTER, + requestMetadata, ); - } catch (error: CatchErr) { - metaTo.metadatas = destInputArray.map((input) => input.metadata); - const erroredResp = - DestinationPostTransformationService.handleRouterTransformFailureEvents( - error, - metaTo, - ); - return [erroredResp]; - } - }, - ), + return DestinationPostTransformationService.handleRouterTransformSuccessEvents( + doRouterTransformationResponse, + undefined, + metaTo, + tags.IMPLEMENTATIONS.CDK_V2, + destinationType.toUpperCase(), + ); + } catch (error: CatchErr) { + metaTo.metadatas = destInputArray.map((input) => input.metadata); + const erroredResp = + DestinationPostTransformationService.handleRouterTransformFailureEvents(error, metaTo); + return [erroredResp]; + } + }), ); return response.flat(); } diff --git a/src/services/destination/nativeIntegration.ts b/src/services/destination/nativeIntegration.ts index 38a27ea71da..38ec934ff7a 100644 --- a/src/services/destination/nativeIntegration.ts +++ b/src/services/destination/nativeIntegration.ts @@ -26,6 +26,7 @@ import { import stats from '../../util/stats'; import tags from '../../v0/util/tags'; import { DestinationPostTransformationService } from './postTransformation'; +import { groupRouterTransformEvents } from '../../v0/util'; export class NativeIntegrationDestinationService implements DestinationService { public init() {} @@ -99,11 +100,7 @@ export class NativeIntegrationDestinationService implements DestinationService { requestMetadata: NonNullable, ): Promise { const destHandler = FetchHandler.getDestHandler(destinationType, version); - const allDestEvents: NonNullable = groupBy( - events, - (ev: RouterTransformationRequestData) => ev.destination?.ID, - ); - const groupedEvents: RouterTransformationRequestData[][] = Object.values(allDestEvents); + const groupedEvents: RouterTransformationRequestData[][] = groupRouterTransformEvents(events); const response: RouterTransformationResponse[][] = await Promise.all( groupedEvents.map(async (destInputArray: RouterTransformationRequestData[]) => { const metaTO = this.getTags( diff --git a/src/v0/util/index.js b/src/v0/util/index.js index c3b9570bc44..6eb63125890 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -2281,8 +2281,14 @@ const validateEventAndLowerCaseConversion = (event, isMandatory, convertToLowerC return convertToLowerCase ? event.toString().toLowerCase() : event.toString(); }; -const applyCustomMappings = (message, mappings) => - JsonTemplateEngine.createAsSync(mappings, { defaultPathType: PathType.JSON }).evaluate(message); +/** + * This function applies custom mappings to the event. + * @param {*} event The event to be transformed. + * @param {*} mappings The custom mappings to be applied. + * @returns {object} The transformed event. + */ +const applyCustomMappings = (event, mappings) => + JsonTemplateEngine.createAsSync(mappings, { defaultPathType: PathType.JSON }).evaluate(event); const applyJSONStringTemplate = (message, template) => JsonTemplateEngine.createAsSync(template.replace(/{{/g, '${').replace(/}}/g, '}'), { @@ -2290,6 +2296,17 @@ const applyJSONStringTemplate = (message, template) => }).evaluate(message); /** + * This groups the events by destination ID and source ID. + * Note: sourceID is only used for rETL events. + * @param {*} events The events to be grouped. + * @returns {array} The array of grouped events. + */ +const groupRouterTransformEvents = (events) => + Object.values( + lodash.groupBy(events, (ev) => [ev.destination?.ID, ev.context?.sources?.job_id || 'default']), + ); + +/* * Gets url path omitting the hostname & protocol * * **Note**: @@ -2364,6 +2381,7 @@ module.exports = { getValueFromMessage, getValueFromPropertiesOrTraits, getValuesAsArrayFromConfig, + groupRouterTransformEvents, handleSourceKeysOperation, hashToSha256, isAppleFamily, diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 1b99e5ebb7e..6bf689eca72 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -1,4 +1,4 @@ -const { TAG_NAMES, InstrumentationError } = require('@rudderstack/integrations-lib'); +const { InstrumentationError } = require('@rudderstack/integrations-lib'); const utilities = require('.'); const { getFuncTestData } = require('../../../test/testHelper'); const { FilteredEventsError } = require('./errorTypes'); @@ -8,6 +8,7 @@ const { generateExclusionList, combineBatchRequestsWithSameJobIds, validateEventAndLowerCaseConversion, + groupRouterTransformEvents, isAxiosError, } = require('./index'); const exp = require('constants'); @@ -693,6 +694,114 @@ describe('extractCustomFields', () => { }); }); +describe('groupRouterTransformEvents', () => { + it('should group events by destination.ID and context.sources.job_id', () => { + const events = [ + { + destination: { ID: 'dest1' }, + context: { sources: { job_id: 'job1' } }, + }, + { + destination: { ID: 'dest1' }, + context: { sources: { job_id: 'job2' } }, + }, + { + destination: { ID: 'dest2' }, + context: { sources: { job_id: 'job1' } }, + }, + ]; + const result = groupRouterTransformEvents(events); + + expect(result.length).toBe(3); // 3 unique groups + expect(result).toEqual([ + [{ destination: { ID: 'dest1' }, context: { sources: { job_id: 'job1' } } }], + [{ destination: { ID: 'dest1' }, context: { sources: { job_id: 'job2' } } }], + [{ destination: { ID: 'dest2' }, context: { sources: { job_id: 'job1' } } }], + ]); + }); + + it('should group events by default job_id if context.sources.job_id is missing', () => { + const events = [ + { + destination: { ID: 'dest1' }, + context: { sources: {} }, + }, + { + destination: { ID: 'dest1' }, + context: { sources: { job_id: 'job1' } }, + }, + ]; + const result = groupRouterTransformEvents(events); + + expect(result.length).toBe(2); // 2 unique groups + expect(result).toEqual([ + [{ destination: { ID: 'dest1' }, context: { sources: {} } }], + [{ destination: { ID: 'dest1' }, context: { sources: { job_id: 'job1' } } }], + ]); + }); + + it('should group events by default job_id if context or context.sources is missing', () => { + const events = [ + { + destination: { ID: 'dest1' }, + }, + { + destination: { ID: 'dest1' }, + context: { sources: { job_id: 'job1' } }, + }, + ]; + const result = groupRouterTransformEvents(events); + + expect(result.length).toBe(2); // 2 unique groups + expect(result).toEqual([ + [{ destination: { ID: 'dest1' } }], + [{ destination: { ID: 'dest1' }, context: { sources: { job_id: 'job1' } } }], + ]); + }); + + it('should use "default" when destination.ID is missing', () => { + const events = [ + { + context: { sources: { job_id: 'job1' } }, + }, + { + destination: { ID: 'dest1' }, + context: { sources: { job_id: 'job1' } }, + }, + ]; + const result = groupRouterTransformEvents(events); + + expect(result.length).toBe(2); // 2 unique groups + expect(result).toEqual([ + [{ context: { sources: { job_id: 'job1' } } }], + [{ destination: { ID: 'dest1' }, context: { sources: { job_id: 'job1' } } }], + ]); + }); + + it('should return an empty array when there are no events', () => { + const events = []; + const result = groupRouterTransformEvents(events); + + expect(result).toEqual([]); + }); + + it('should handle events with completely missing context and destination', () => { + const events = [ + {}, + { destination: { ID: 'dest1' } }, + { context: { sources: { job_id: 'job1' } } }, + ]; + const result = groupRouterTransformEvents(events); + + expect(result.length).toBe(3); // 3 unique groups + expect(result).toEqual([ + [{}], + [{ destination: { ID: 'dest1' } }], + [{ context: { sources: { job_id: 'job1' } } }], + ]); + }); +}); + describe('applyJSONStringTemplate', () => { it('should apply JSON string template to the payload', () => { const payload = { From 16598edd55320a57a7079b0db6ee460a5a8a9c99 Mon Sep 17 00:00:00 2001 From: BonapartePC Date: Thu, 12 Sep 2024 15:31:17 +0530 Subject: [PATCH 009/147] chore: check if object is converted to string and stringify it --- src/warehouse/index.js | 64 ++++++++++++++++++++++++++++++++ test/__tests__/warehouse.test.js | 18 ++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index f62f02af792..5018969e2a3 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -208,6 +208,20 @@ function setDataFromInputAndComputeColumnTypes( level = 0, ) { if (!input || !isObject(input)) return; + if (completePrefix.endsWith('context_traits_') && isStringLikeObject(input)) { + if (prefix === 'context_traits_') { + appendColumnNameAndType( + utils, + eventType, + `${prefix}`, + stringLikeObjectToString(input), + output, + columnTypes, + options, + ); + } + return; + } Object.keys(input).forEach((key) => { const isValidLegacyJSONPath = isValidLegacyJsonPathKey( eventType, @@ -272,6 +286,56 @@ function setDataFromInputAndComputeColumnTypes( }); } +function isNonNegativeInteger(str) { + if (str.length === 0) return false; + for (let i = 0; i < str.length; i++) { + const charCode = str.charCodeAt(i); + if (charCode < 48 || charCode > 57) return false; + } + return true; +} + +function isStringLikeObject(obj) { + if (typeof obj !== 'object' || obj === null) return false; + + const keys = Object.keys(obj); + if (keys.length === 0) return false; + + let minKey = Infinity; + let maxKey = -Infinity; + + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = obj[key]; + + if (!isNonNegativeInteger(key)) return false; + if (typeof value !== 'string' || value.length !== 1) return false; + + const numKey = parseInt(key, 10); + if (numKey < minKey) minKey = numKey; + if (numKey > maxKey) maxKey = numKey; + } + + return (minKey === 0 || minKey === 1) && maxKey - minKey + 1 === keys.length; +} + +function stringLikeObjectToString(obj) { + if (!isStringLikeObject(obj)) { + return obj; // Return the original input if it's not a valid string-like object + } + + const keys = Object.keys(obj) + .map(Number) + .sort((a, b) => a - b); + let result = ''; + + for (let i = 0; i < keys.length; i++) { + result += obj[keys[i].toString()]; + } + + return result; +} + /* * uuid_ts and loaded_at datatypes are passed from here to create appropriate columns. * Corresponding values are inserted when loading into the warehouse diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 2c89120686b..98c40da5624 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1233,4 +1233,20 @@ describe("isBlank", () => { expect(isBlank(testCase.input)).toEqual(testCase.expected); }); } -}); \ No newline at end of file +}); + +describe("context traits", () => { + for (const e of eventTypes) { + let i = input(e); + i.message.context= {"traits": {1: "f", 2: "o"}}; + i.message.traits = "bar"; + if (i.metadata) delete i.metadata.sourceCategory; + transformers.forEach((transformer, index) => { + const received = transformer.process(i); + let columns = Object.keys(received[0].metadata.columns); + console.log(columns); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual("string"); + expect(received[0].data[integrationCasedString(integrations[index], "context_traits")]).toEqual("fo"); + }); + } +}) \ No newline at end of file From e8f82fc336a9adb686e7a38c8593a20636bed4a2 Mon Sep 17 00:00:00 2001 From: BonapartePC Date: Thu, 12 Sep 2024 19:13:30 +0530 Subject: [PATCH 010/147] add more tests --- src/warehouse/index.js | 4 ++ test/__tests__/warehouse.test.js | 100 +++++++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 11 deletions(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 5018969e2a3..eb95fc8c88b 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -316,6 +316,10 @@ function isStringLikeObject(obj) { if (numKey > maxKey) maxKey = numKey; } + for (let i = minKey; i <= maxKey; i++) { + if (!keys.includes(i.toString())) return false; + } + return (minKey === 0 || minKey === 1) && maxKey - minKey + 1 === keys.length; } diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 98c40da5624..a0094a3703a 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1236,17 +1236,95 @@ describe("isBlank", () => { }); describe("context traits", () => { - for (const e of eventTypes) { - let i = input(e); - i.message.context= {"traits": {1: "f", 2: "o"}}; - i.message.traits = "bar"; - if (i.metadata) delete i.metadata.sourceCategory; - transformers.forEach((transformer, index) => { - const received = transformer.process(i); - let columns = Object.keys(received[0].metadata.columns); - console.log(columns); - expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual("string"); - expect(received[0].data[integrationCasedString(integrations[index], "context_traits")]).toEqual("fo"); + const testCases = [ + { + name: "context traits with string like object", + input: {"1":"f","2":"o", "3":"o"}, + expectedData: "foo", + expectedMetadata: "string", + expectedColumns: ["context_traits"] + }, + { + name: "context traits with string like object with missing keys", + input: {"1":"a","3":"a"}, + expectedData: "a", + expectedMetadata: "string", + expectedColumns: ["context_traits_1", "context_traits_3"] + }, + { + name: "context traits with empty object", + input: {}, + expectedData: {}, + expectedColumns: [], + }, + { + name: "context traits with empty array", + input: [], + expectedData: [], + expectedMetadata: "array", + expectedColumns: [] + }, + { + name: "context traits with null", + input: null, + expectedData: null, + expectedMetadata: "null", + expectedColumns: [] + }, + { + name: "context traits with undefined", + input: undefined, + expectedData: undefined, + expectedMetadata: "undefined", + expectedColumns: [] + }, + { + name: "context traits with string", + input: "already a string", + expectedData: "already a string", + expectedMetadata: "string", + expectedColumns: ["context_traits"] + }, + { + name: "context traits with number", + input: 42, + expectedData: 42, + expectedMetadata: "int", + expectedColumns: ["context_traits"] + }, + { + name: "context traits with boolean", + input: true, + expectedData: true, + expectedMetadata: "boolean", + expectedColumns: ["context_traits"] + }, + { + name: "context traits with array", + input: ["a", "b", "cd"], + expectedData: ["a", "b", "cd"], + expectedMetadata: "string", + expectedColumns: ["context_traits"] + } + ]; + for (const t of testCases) { + it(`should return ${t.expectedData} for ${t.name}`, () => { + for (const e of eventTypes) { + let i = input(e); + i.message.context = {"traits": t.input}; + if (i.metadata) delete i.metadata.sourceCategory; + transformers.forEach((transformer, index) => { + const received = transformer.process(i); + if(t.expectedColumns.length === 0) { + expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual(undefined); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual(undefined); + } + for (const column of t.expectedColumns) { + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); + } + }); + } }); } }) \ No newline at end of file From 632d9af27a5f18de83d699f4464e86f028932e4f Mon Sep 17 00:00:00 2001 From: Jayachand Mopidevi Date: Thu, 12 Sep 2024 19:54:03 +0530 Subject: [PATCH 011/147] chore: adding a new violation type Advance-Rules-Violation (#3715) --- src/util/eventValidation.js | 23 +++++++++++++++++++++++ test/__tests__/eventValidation.test.js | 6 ++++-- test/__tests__/trackingPlan.test.js | 4 ++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/util/eventValidation.js b/src/util/eventValidation.js index 9f3ecd859d8..46a494ee5ce 100644 --- a/src/util/eventValidation.js +++ b/src/util/eventValidation.js @@ -30,6 +30,7 @@ const violationTypes = { AdditionalProperties: 'Additional-Properties', UnknownViolation: 'Unknown-Violation', UnplannedEvent: 'Unplanned-Event', + AdvanceRulesViolation: 'Advance-Rules-Violation', }; const supportedEventTypes = { @@ -227,6 +228,28 @@ async function validate(event) { }, }; break; + case 'minLength': + case 'maxLength': + case 'pattern': + case 'format': + case 'multipleOf': + case 'minimum': + case 'maximum': + case 'exclusiveMinimum': + case 'exclusiveMaximum': + case 'minItems': + case 'maxItems': + case 'uniqueItems': + case 'enum': + rudderValidationError = { + type: violationTypes.AdvanceRulesViolation, + message: error.message, + meta: { + instancePath: error.instancePath, + schemaPath: error.schemaPath, + }, + }; + break; default: rudderValidationError = { type: violationTypes.UnknownViolation, diff --git a/test/__tests__/eventValidation.test.js b/test/__tests__/eventValidation.test.js index b802b6f886a..9f284164571 100644 --- a/test/__tests__/eventValidation.test.js +++ b/test/__tests__/eventValidation.test.js @@ -266,7 +266,8 @@ const validationErrorsTestCases = [ validationErrors: [ { type: "Datatype-Mismatch" }, { type: "Unplanned-Event" }, - { type: "Additional-Properties" } + { type: "Additional-Properties" }, + { type: "Advance-Rules-Violation" } ], output: true }, @@ -283,7 +284,8 @@ const validationErrorsTestCases = [ validationErrors: [ { type: "Datatype-Mismatch" }, { type: "Unplanned-Event" }, - { type: "Additional-Properties" } + { type: "Additional-Properties" }, + { type: "Advance-Rules-Violation" } ], output: true }, diff --git a/test/__tests__/trackingPlan.test.js b/test/__tests__/trackingPlan.test.js index 19606b38b9f..1c5db08bd48 100644 --- a/test/__tests__/trackingPlan.test.js +++ b/test/__tests__/trackingPlan.test.js @@ -614,7 +614,7 @@ const eventValidationTestCases = [ trackingPlan, output: [ { - type: "Unknown-Violation", + type: "Advance-Rules-Violation", message: "must be <= 4", meta: { instancePath: "/properties/revenue", @@ -665,7 +665,7 @@ const eventValidationTestCases = [ instancePath: "/properties/dateString", schemaPath: "#/properties/properties/properties/dateString/format", }, - type: "Unknown-Violation", + type: "Advance-Rules-Violation", } ] }, From 44b5ea3338e86c99f34b416ceb710fc73095b606 Mon Sep 17 00:00:00 2001 From: BonapartePC Date: Fri, 13 Sep 2024 15:00:49 +0530 Subject: [PATCH 012/147] add support for group --- src/warehouse/index.js | 6 ++--- test/__tests__/warehouse.test.js | 39 ++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index eb95fc8c88b..d79a12c40b2 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -208,12 +208,12 @@ function setDataFromInputAndComputeColumnTypes( level = 0, ) { if (!input || !isObject(input)) return; - if (completePrefix.endsWith('context_traits_') && isStringLikeObject(input)) { - if (prefix === 'context_traits_') { + if ((completePrefix.endsWith('context_traits_') || completePrefix === 'group_traits_') && isStringLikeObject(input)) { + if (prefix === 'context_traits_' || completePrefix === 'group_traits_') { appendColumnNameAndType( utils, eventType, - `${prefix}`, + `${prefix.length > 0 ? prefix : completePrefix}`, stringLikeObjectToString(input), output, columnTypes, diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index a0094a3703a..05e3eb1482a 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1242,69 +1242,79 @@ describe("context traits", () => { input: {"1":"f","2":"o", "3":"o"}, expectedData: "foo", expectedMetadata: "string", - expectedColumns: ["context_traits"] + expectedColumns: ["context_traits"], + groupTypeColumns: ["group_traits"] }, { name: "context traits with string like object with missing keys", input: {"1":"a","3":"a"}, expectedData: "a", expectedMetadata: "string", - expectedColumns: ["context_traits_1", "context_traits_3"] + expectedColumns: ["context_traits_1", "context_traits_3"], + groupTypeColumns: ["_1", "_3"] }, { name: "context traits with empty object", input: {}, expectedData: {}, expectedColumns: [], + groupTypeColumns: [] }, { name: "context traits with empty array", input: [], expectedData: [], expectedMetadata: "array", - expectedColumns: [] + expectedColumns: [], + groupTypeColumns: [] }, { name: "context traits with null", input: null, expectedData: null, expectedMetadata: "null", - expectedColumns: [] + expectedColumns: [], + groupTypeColumns: [] }, { name: "context traits with undefined", input: undefined, expectedData: undefined, expectedMetadata: "undefined", - expectedColumns: [] + expectedColumns: [], + groupTypeColumns: [] }, { name: "context traits with string", input: "already a string", expectedData: "already a string", expectedMetadata: "string", - expectedColumns: ["context_traits"] + expectedColumns: ["context_traits"], + groupTypeColumns: [] }, { name: "context traits with number", input: 42, expectedData: 42, expectedMetadata: "int", - expectedColumns: ["context_traits"] + expectedColumns: ["context_traits"], + groupTypeColumns: [] }, { name: "context traits with boolean", input: true, expectedData: true, expectedMetadata: "boolean", - expectedColumns: ["context_traits"] + expectedColumns: ["context_traits"], + groupTypeColumns: [] }, { name: "context traits with array", input: ["a", "b", "cd"], expectedData: ["a", "b", "cd"], expectedMetadata: "string", - expectedColumns: ["context_traits"] + expectedColumns: ["context_traits"], + groupTypeColumns: [] } ]; for (const t of testCases) { @@ -1312,6 +1322,7 @@ describe("context traits", () => { for (const e of eventTypes) { let i = input(e); i.message.context = {"traits": t.input}; + i.message.traits = t.input; if (i.metadata) delete i.metadata.sourceCategory; transformers.forEach((transformer, index) => { const received = transformer.process(i); @@ -1323,6 +1334,16 @@ describe("context traits", () => { expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } + if(e==="group") { + if(t.groupTypeColumns.length === 0) { + expect(received[0].metadata.columns[integrationCasedString(integrations[index], "group_traits")]).toEqual(undefined); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], "group_traits")]).toEqual(undefined); + } + for (const column of t.groupTypeColumns) { + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); + } + } }); } }); From 5a2d4de172e31866b8ef2704befc078ec1d6db39 Mon Sep 17 00:00:00 2001 From: BonapartePC Date: Fri, 13 Sep 2024 15:42:20 +0530 Subject: [PATCH 013/147] fix tests for group --- src/warehouse/index.js | 7 +++++-- test/__tests__/warehouse.test.js | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index d79a12c40b2..c64f9c5ec3b 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -208,8 +208,11 @@ function setDataFromInputAndComputeColumnTypes( level = 0, ) { if (!input || !isObject(input)) return; - if ((completePrefix.endsWith('context_traits_') || completePrefix === 'group_traits_') && isStringLikeObject(input)) { - if (prefix === 'context_traits_' || completePrefix === 'group_traits_') { + if ( + (completePrefix.endsWith('context_traits_') || completePrefix === 'group_traits_') && + isStringLikeObject(input) + ) { + if (prefix === 'context_traits_') { appendColumnNameAndType( utils, eventType, diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 05e3eb1482a..bc93363672b 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1235,18 +1235,18 @@ describe("isBlank", () => { } }); -describe("context traits", () => { +describe("context/group traits", () => { const testCases = [ { - name: "context traits with string like object", + name: "traits with string like object", input: {"1":"f","2":"o", "3":"o"}, expectedData: "foo", expectedMetadata: "string", expectedColumns: ["context_traits"], - groupTypeColumns: ["group_traits"] + groupTypeColumns: [] }, { - name: "context traits with string like object with missing keys", + name: "traits with string like object with missing keys", input: {"1":"a","3":"a"}, expectedData: "a", expectedMetadata: "string", @@ -1254,14 +1254,14 @@ describe("context traits", () => { groupTypeColumns: ["_1", "_3"] }, { - name: "context traits with empty object", + name: "traits with empty object", input: {}, expectedData: {}, expectedColumns: [], groupTypeColumns: [] }, { - name: "context traits with empty array", + name: "traits with empty array", input: [], expectedData: [], expectedMetadata: "array", @@ -1269,7 +1269,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with null", + name: "traits with null", input: null, expectedData: null, expectedMetadata: "null", @@ -1277,7 +1277,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with undefined", + name: "traits with undefined", input: undefined, expectedData: undefined, expectedMetadata: "undefined", @@ -1285,7 +1285,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with string", + name: "traits with string", input: "already a string", expectedData: "already a string", expectedMetadata: "string", @@ -1293,7 +1293,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with number", + name: "traits with number", input: 42, expectedData: 42, expectedMetadata: "int", @@ -1301,7 +1301,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with boolean", + name: "traits with boolean", input: true, expectedData: true, expectedMetadata: "boolean", @@ -1309,7 +1309,7 @@ describe("context traits", () => { groupTypeColumns: [] }, { - name: "context traits with array", + name: "traits with array", input: ["a", "b", "cd"], expectedData: ["a", "b", "cd"], expectedMetadata: "string", From 37b02f06a65265a25ec6a43326cf09f0a1de1351 Mon Sep 17 00:00:00 2001 From: BonapartePC Date: Fri, 13 Sep 2024 16:27:01 +0530 Subject: [PATCH 014/147] fix tests and address review comments --- src/warehouse/index.js | 2 +- test/__tests__/warehouse.test.js | 120 ++++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 25 deletions(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index c64f9c5ec3b..3c2b04079d9 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -216,7 +216,7 @@ function setDataFromInputAndComputeColumnTypes( appendColumnNameAndType( utils, eventType, - `${prefix.length > 0 ? prefix : completePrefix}`, + `${prefix}`, stringLikeObjectToString(input), output, columnTypes, diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index bc93363672b..83b24aee159 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1235,7 +1235,7 @@ describe("isBlank", () => { } }); -describe("context/group traits", () => { +describe("context traits", () => { const testCases = [ { name: "traits with string like object", @@ -1243,7 +1243,6 @@ describe("context/group traits", () => { expectedData: "foo", expectedMetadata: "string", expectedColumns: ["context_traits"], - groupTypeColumns: [] }, { name: "traits with string like object with missing keys", @@ -1251,14 +1250,12 @@ describe("context/group traits", () => { expectedData: "a", expectedMetadata: "string", expectedColumns: ["context_traits_1", "context_traits_3"], - groupTypeColumns: ["_1", "_3"] }, { name: "traits with empty object", input: {}, expectedData: {}, expectedColumns: [], - groupTypeColumns: [] }, { name: "traits with empty array", @@ -1266,7 +1263,6 @@ describe("context/group traits", () => { expectedData: [], expectedMetadata: "array", expectedColumns: [], - groupTypeColumns: [] }, { name: "traits with null", @@ -1274,7 +1270,6 @@ describe("context/group traits", () => { expectedData: null, expectedMetadata: "null", expectedColumns: [], - groupTypeColumns: [] }, { name: "traits with undefined", @@ -1290,7 +1285,6 @@ describe("context/group traits", () => { expectedData: "already a string", expectedMetadata: "string", expectedColumns: ["context_traits"], - groupTypeColumns: [] }, { name: "traits with number", @@ -1298,7 +1292,6 @@ describe("context/group traits", () => { expectedData: 42, expectedMetadata: "int", expectedColumns: ["context_traits"], - groupTypeColumns: [] }, { name: "traits with boolean", @@ -1306,7 +1299,6 @@ describe("context/group traits", () => { expectedData: true, expectedMetadata: "boolean", expectedColumns: ["context_traits"], - groupTypeColumns: [] }, { name: "traits with array", @@ -1314,7 +1306,6 @@ describe("context/group traits", () => { expectedData: ["a", "b", "cd"], expectedMetadata: "string", expectedColumns: ["context_traits"], - groupTypeColumns: [] } ]; for (const t of testCases) { @@ -1322,30 +1313,111 @@ describe("context/group traits", () => { for (const e of eventTypes) { let i = input(e); i.message.context = {"traits": t.input}; - i.message.traits = t.input; if (i.metadata) delete i.metadata.sourceCategory; transformers.forEach((transformer, index) => { const received = transformer.process(i); if(t.expectedColumns.length === 0) { - expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual(undefined); - expect(received[0].metadata.columns[integrationCasedString(integrations[index], "context_traits")]).toEqual(undefined); + expect(Object.keys(received[0].metadata.columns).join()).not.toMatch(/context_traits/g); + expect(Object.keys(received[0].data).join()).not.toMatch(/context_traits/g); } for (const column of t.expectedColumns) { expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } - if(e==="group") { - if(t.groupTypeColumns.length === 0) { - expect(received[0].metadata.columns[integrationCasedString(integrations[index], "group_traits")]).toEqual(undefined); - expect(received[0].metadata.columns[integrationCasedString(integrations[index], "group_traits")]).toEqual(undefined); - } - for (const column of t.groupTypeColumns) { - expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); - } - } }); } }); } -}) \ No newline at end of file +}) + +describe("group traits", () => { + const testCases = [ + { + name: "traits with string like object", + input: {"1":"f","2":"o", "3":"o"}, + expectedData: "foo", + expectedMetadata: "string", + expectedColumns: [], + }, + { + name: "traits with string like object with missing keys", + input: {"1":"a","3":"a"}, + expectedData: "a", + expectedMetadata: "string", + expectedColumns: ["_1", "_3"], + }, + { + name: "traits with empty object", + input: {}, + expectedData: {}, + expectedColumns: [], + }, + { + name: "traits with empty array", + input: [], + expectedData: [], + expectedMetadata: "array", + expectedColumns: [], + }, + { + name: "traits with null", + input: null, + expectedData: null, + expectedMetadata: "null", + expectedColumns: [], + }, + { + name: "traits with undefined", + input: undefined, + expectedData: undefined, + expectedMetadata: "undefined", + expectedColumns: [], + }, + { + name: "traits with string", + input: "already a string", + expectedData: "already a string", + expectedMetadata: "string", + expectedColumns: [], + }, + { + name: "traits with number", + input: 42, + expectedData: 42, + expectedMetadata: "int", + expectedColumns: [], + }, + { + name: "traits with boolean", + input: true, + expectedData: true, + expectedMetadata: "boolean", + expectedColumns: [], + }, + { + name: "traits with array", + input: ["a", "b", "cd"], + expectedData: ["a", "b", "cd"], + expectedMetadata: "string", + expectedColumns: [], + } + ]; + for (const t of testCases){ + it(`should return ${t.expectedData} for ${t.name}`, () => { + let i = input("group"); + i.message.traits = t.input; + if (i.metadata) delete i.metadata.sourceCategory; + transformers.forEach((transformer, index) => { + const received = transformer.process(i); + if(t.expectedColumns.length === 0) { + expect(Object.keys(received[0].metadata.columns).join()).not.toMatch(/group_traits/g); + expect(Object.keys(received[0].data).join()).not.toMatch(/group_traits/g); + } + for (const column of t.expectedColumns) { + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); + } + }); + }); + } +}) From f2e6937551f742d2a8187219ea595a5e132541b4 Mon Sep 17 00:00:00 2001 From: Jayachand Mopidevi Date: Mon, 16 Sep 2024 11:54:02 +0530 Subject: [PATCH 015/147] chore: add configurable ivm execution timeout (#3732) --- src/util/customTransformer-v1.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/customTransformer-v1.js b/src/util/customTransformer-v1.js index b6ed8f9654f..ddc1cacd173 100644 --- a/src/util/customTransformer-v1.js +++ b/src/util/customTransformer-v1.js @@ -6,6 +6,7 @@ const logger = require('../logger'); const stats = require('./stats'); const userTransformTimeout = parseInt(process.env.USER_TRANSFORM_TIMEOUT || '600000', 10); +const ivmExecutionTimeout = parseInt(process.env.IVM_EXECUTION_TIMEOUT || '4000', 10); async function transform(isolatevm, events) { const transformationPayload = {}; @@ -24,7 +25,7 @@ async function transform(isolatevm, events) { new ivm.Reference(reject), sharedTransformationPayload, ], - { timeout: 4000 }, + { timeout: ivmExecutionTimeout }, ); } catch (error) { reject(error.message); From aa1289d8e5d6d735b1469db9b12a1c90f319926b Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 16 Sep 2024 08:59:02 +0000 Subject: [PATCH 016/147] chore(release): 1.78.0 --- CHANGELOG.md | 18 ++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2f0ba14a2..6c63fb4310c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.78.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.77.1...v1.78.0) (2024-09-16) + + +### Features + +* add source id isolation for reverse etl ([#3496](https://github.com/rudderlabs/rudder-transformer/issues/3496)) ([b4f4dd1](https://github.com/rudderlabs/rudder-transformer/commit/b4f4dd1c43f8fd4b4f744413d79cfe8f5f77708b)) +* add util for applying json string template ([#3699](https://github.com/rudderlabs/rudder-transformer/issues/3699)) ([b2f5654](https://github.com/rudderlabs/rudder-transformer/commit/b2f56540148066a40770e1506faadb4f3f5a296b)) +* onboard X(Twiiter) Audience ([#3696](https://github.com/rudderlabs/rudder-transformer/issues/3696)) ([f77d2ab](https://github.com/rudderlabs/rudder-transformer/commit/f77d2ab4125a1a44bba95bebbee25bb4fac032da)) +* webhook v2 path variables support ([#3705](https://github.com/rudderlabs/rudder-transformer/issues/3705)) ([f7783d8](https://github.com/rudderlabs/rudder-transformer/commit/f7783d8fb30093a847f450ee7ddd9449f272b112)) + + +### Bug Fixes + +* added support for window stabilization fix through envs ([#3720](https://github.com/rudderlabs/rudder-transformer/issues/3720)) ([8dcf1b3](https://github.com/rudderlabs/rudder-transformer/commit/8dcf1b3c5aff424d39bece8c9912ec4a1eb221ea)) +* circular json bugsnag ([#3713](https://github.com/rudderlabs/rudder-transformer/issues/3713)) ([263d075](https://github.com/rudderlabs/rudder-transformer/commit/263d0758be828402068278c7c5356b65119e7e9a)) +* error messages in gaec ([#3702](https://github.com/rudderlabs/rudder-transformer/issues/3702)) ([441fb57](https://github.com/rudderlabs/rudder-transformer/commit/441fb57a537592cc1cc45dc8f31fa8be98e18320)) +* gaoc bugsnag alert for email.trim ([#3693](https://github.com/rudderlabs/rudder-transformer/issues/3693)) ([6ba16f6](https://github.com/rudderlabs/rudder-transformer/commit/6ba16f6e5d9bb0de773ebcb8be13a78af325a4a1)) + ### [1.77.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.77.0...v1.77.1) (2024-09-05) diff --git a/package-lock.json b/package-lock.json index 7cad035e75f..cf0af8c3253 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.77.1", + "version": "1.78.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.77.1", + "version": "1.78.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 7aec18b268d..c96d436b3d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.77.1", + "version": "1.78.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 5dd382b2c2826f576a7a6000015498ae2fc3c1fb Mon Sep 17 00:00:00 2001 From: gitcommitshow <56937085+gitcommitshow@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:31:58 +0530 Subject: [PATCH 017/147] docs: add contribution guide for source integration (#3724) * docs: add contribution guide for source integration * docs: contribution guide for destination integration --- CONTRIBUTING.md | 1102 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1102 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48055816e4e..f735f4f04b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,1108 @@ committed to main branch as a single commit. All pull requests are squashed when merged, but rebasing prior to merge gives you better control over the commit message. +---- + +Now, that you have a basic overview of the contibution guidelines. Let's dive into a detailed guide to contribute by creating a new custom RudderStack integration. + +## Building your first custom RudderStack **source** integration + +Before starting to work on your first RudderStack integration, it is highly recommended to get a high-level overview of [RudderStack Event Specification](https://www.rudderstack.com/docs/event-spec/standard-events/). + + + +* When developing a **source integration**, you’ll be transforming your events data received from the source to this specification. +* When developing a **destination integration**, you’ll be parsing the event data according to this event spec and transforming it to your destination’s data spec. + + +### Overview of integration development journey + + + +1. Add integration code to [rudder-transformer](https://github.com/rudderlabs/rudder-transformer) `src/v1/sources` or `src/cdk/v2/destinations` folder \ +This is the codebase that controls how raw event data (received from the source) is transformed to RudderStack Event Data Specification and then finally to the destination specific data format +2. Add RudderStack UI configurations in [rudder-integrations-config](https://github.com/rudderlabs/rudder-integrations-config) `src/configurations/sources` or `src/configurations/destinations` folder \ +This enables your integration users to setup/configure the integration via RudderStack Dashboard +3. Write the documentation for your integration (or share the [integration plan document](https://rudderstacks.notion.site/Integration-planning-document-example-Slack-Source-integration-46863d6041ec48258f9c5433eab93b28?pvs=25) with the RudderStack team) +4. RudderStack team will deploy your integration to production and post an announcement in the [Release Notes](https://www.rudderstack.com/docs/releases/) + +RudderStack team will be available to help you by giving feedback and answering questions either directly on your GitHub PR or the [RudderStack Slack community](https://www.rudderstack.com/join-rudderstack-slack-community/). Before diving into code, writing an integration plan document helps a lot, here’s an [example document](https://rudderstacks.notion.site/Integration-planning-document-example-Slack-Source-integration-46863d6041ec48258f9c5433eab93b28?pvs=25). + + +### 1. Setup rudder-transformer and understand the code structure + +Setup [rudder-transformer](https://github.com/rudderlabs/rudder-transformer) on your local machine + + + +* Clone [this repository](https://github.com/rudderlabs/rudder-transformer) +* Setup the repository with `npm run setup` +* Build the service with `npm run build:clean` +* Start the server with `npm start` + +Understand the code structure + + + +* `src/v1/sources` - Source integrations +* `src/cdk/v2/destinations` - Destination integrations +* `src/v0` and `src/v1` have older integrations, will be useful only if you’re fixing a bug or adding feature in older integrations +* `test/integrations/sources` - Integration tests for source integrations +* `test/integrations/destinations` - Integration tests for destination integrations + + +### 2. Write code for a v0 source integration {#2-write-code-for-a-v0-source-integration} + +Here, we will explain the code for a v0 source integration but most of the learning will apply to other integrations as well (destination and v1). + + + +* Create a new directory with the integration name under `src/v0` (follow the snake case naming convention) +* Add `transform.js`, add a `process(eventData)` function and export it. This is the function which will be called to transform the event data received from the source +* Add `config.js` to separate the source configuration and mapping + +A simple example of `process` function and `transform.js` file looks like this + +```javascript +/** + * src/v0/sources/slack/transform.js + * An example transform.js file for Slack integration with v0 integration method + */ + +const Message = require('../message'); // Standard RudderStacj event message object +const { TransformationError } = require('@rudderstack/integrations-lib'); // Standard errors +const { generateUUID, removeUndefinedAndNullValues } = require('../../util'); // Common utilities for v0 source integrations + +/** + * Transform the input event data to RudderStack Standard Event Specification - https://www.rudderstack.com/docs/event-spec/standard-events/ + * @param {Object} eventPayload - The event object received from the source. + * For example, Slack sends this payload which Slack source integration transforms to match the RudderStack Event Specs (e.g. Slack's team_join event to RudderStack's IDENTIFY event spec) + * { + * "event": { + "type": "team_join", + * "user": { + * "id": "W012CDE", + * "real_name": "John Doe" + * } + * }, + * "type": "event_callback", + * ...restOfTheEventPayload + * } + * @returns {Object} transformedEvent - Transformed event + */ +function process(eventPayload) { + const transformedEvent = new Message(`SLACK`); // SLACK is the integration name here. It will be different for your integration. + if (!eventPayload?.event) { + throw new TransformationError('Missing the required event data'); + } + switch (eventPayload.event.type) { + case 'team_join': + // Transform Slack's team_join event to RudderStack's standard IDENTIFY event schema + transformedEvent.setEventType(EventType.IDENTIFY); + break; + } + // Normalize event names e.g. "team_join" to "Team Join" + transformedEvent.setEventName(normalizeEventName(eventPayload.event.type)); + const stringifiedUserId = eventPayload?.event?.user?.id; + // anonymousId is an important property of RudderStack event specification to identify user across different user events + transformedEvent.setProperty( + 'anonymousId', + stringifiedUserId ? sha256(stringifiedUserId).toString().substring(0, 36) : generateUUID(), + ); + // externalId is another important property of RudderStack event specification that helps connect user identities from different channels + transformedEvent.context.externalId = [ + { + type: 'slackUserId', + id: stringifiedUserId, + }, + ]; + // Set the standard common event fields. More info at https://www.rudderstack.com/docs/event-spec/standard-events/common-fields/ + // originalTimestamp - The actual time (in UTC) when the event occurred + transformedEvent.setProperty( + 'originalTimestamp', + tsToISODate(eventPayload.event.ts) + ); + // Map the remaining standard event properties according to mappings for the payload properties + const mapping = [ + { + "sourceKeys": "event.type", + "destKeys": "event" + }, + { + "sourceKeys": "event.user.profile.real_name", + "destKeys": "context.traits.name" + }, + ] + // Using a fixed json mapping structure (sourceKeys <> destKeys), it is the quickest way to map source fields with the destination fields + transformedEvent.setPropertiesV2(eventPayload, mapping); + // Copy the complete event payload to transformedEvent.properties + Object.assign(transformedEvent.properties, eventPayload.event); + return removeUndefinedAndNullValues(transformedEvent); +} + +// Make sure to export the `process` function. All other details of the integration code can remain hidden. +exports.process = process; +``` + +### 3. Test your v0 source integration + + +#### Manual testing + +You’ll need some API request client (e.g. Postman, Bruno, etc.) to make a POST test request to + +`/{$integration-version-type e.g. v0 or v1}/{$integration-type e.g. sources or destinations}/{$integration-name e.g. slack}` + + + +* Request endpoint example for Slack source developed under v0 folder - `POST /v0/sources/slack` +* Body - An array of event data object received from the source i.e. `[{ …eventData }]` +* Headers - `Content-Type: application/json` + +Depending upon your integration behavior for different types of event, you can get different types of output. + + +##### Testing standard event response + +This is what you’d want to do most of the time. The standard case, when you only transform the incoming event and hand it over to RudderStack to deliver to the destination. + +For a successful event processing in such case, you should receive HTTP 200 OK response status with data in the following structure + +```javascript +[ + { + "output": { + "batch": [ + { + ...transformedEventData + } + ] + } + } +] +``` + +##### Testing custom event response + +You can customize the response to the HTTP request from the source beyond the standard event response format sent by RudderStack. You can customize the response body, content type header, status code, etc. Such customization is useful in some cases when you do not want to receive the standard response from RudderStack e.g. url_verification event for Slack webhook url ownership verification needs to respond back with the challenge parameter in the response body and the HTTP response status code to be 200. + +In such a case, you need to return the response in a specific format containing `outputToSource` and `statusCode`. Your integration code can send the `outputToSource.body` and `outputToSource.contentType` as per your requirements. + +In this case, a successful event response should match the following structure + + +```javascript +[ + { + outputToSource: { + body: ...base64EncodedResponseBody, // e.g. eyJjaGFsbG2UiOiIzZVpicncxYUIxMEZFTUFHQVpkNEZ5RlEifQ (base64 encoding of the response body) + contentType: ...contentType // e.g. application/json + }, + statusCode: ...httpStatusCode, // e.g. 200 + } +] +``` + +### 4. Write automated tests + +Follow the test structure similar to other integrations in `test/integrations/sources` or `test/integrations/destinations`. + +You may reuse the same request data from the manual tests i.e. use them in place of `replaceThisWithYourEventPayloadProps` and `replaceThisWithYourTransformedEventOutput` (including the enclosing `[{ }]`). But make sure to redact any personal or secret information. + +Here’s an example + +```javascript +/** test/sources/slack/data.ts **/ + +export const data = [ + +/** Test 1 - Testing standard event response **/ + + { + name: 'slack', // Replace with your integration name + description: 'Team joined event', // Replace with your event description + module: 'source', // Replace with your integration type - destination or source + version: 'v0', // Replace with your integration approach - v0 or v1 + input: { + request: { + body: ...replaceThisWithYourEventPayload + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: ...replaceThisWithYourTransformedEventOutput + }, + }, + ], + }, + }, + }, + +/** Test 2 - Testing custom event response **/ + + { + name: 'slack', // Replace with your integration name + description: 'Webhook url verificatin event (not a standard RudderStack event, returns a custom response)', // Replace with your event description + module: 'source', // Replace with your integration type - destination or source + version: 'v0', // Replace with your integration approach - v0 or v1 + input: { + request: { + body: ...replaceThisWithYourEventPayload + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + outputToSource: { + body: 'eyJjaGFsb2UiOiIzZVpicncxYUIxMEZFTUFHQVpkNEZ5RlEifQ==', // Replace this with the Base64 encoding of the response body your integrations sends + contentType: 'application/json', // Replace this with the content type your integration sends + }, + statusCode: 200, // Replace this with the custom response status your integration sends for this event + }, + ], + }, + }, + }, +]; +``` + +#### Running automated tests + +You can run tests only for the specific integration, for example + + + +* To test Slack destination - `npm run test:ts -- component --destination=slack` +* To test Slack source - `npm run test:ts -- component --source=slack` + +These tests will automatically be run on each commit, making sure that any new development does not break the existing integrations. + + +### 5. Add RudderStack UI configurations in integrations-config + +Add configuration for your integration in [rudder-integrations-config](https://github.com/rudderlabs/rudder-integrations-config) repo under `src/configurations/sources/` or `src.configurations/destinations`. At bare minimum, a db-config file is needed, here’s [an example](https://github.com/rudderlabs/rudder-integrations-config/blob/develop/src/configurations/sources/slack/db-config.json) of the same for Slack source. Duplicate it in the directory for your integration config folder and change the relevant values for your integration. + +Alternatively, the easier path to do this is by running a script which will generate these files for you. For this, first create a copy of this `[test/configData/inputData.json](https://github.com/rudderlabs/rudder-integrations-config/blob/develop/test/configData/inputData.json)` and adjust it to what you want to see in the RudderStack dashboard ui. And use that placeholder file in the following command + +`python3 scripts/configGenerator.py <path of the placeholder file>` + +Run this command from the root directory of the rudder-integrations-config repo. The PR can then be raised after checking if everything looks good. + + +### 6. Run the transformer locally + +```bash + +nvm use v20 + +npm ci + +npm run build:start + +``` + + +### References + + +* [Contributing.md](https://github.com/rudderlabs/rudder-server/blob/master/CONTRIBUTING.md\) in all github repositories +* [https://www.rudderstack.com/docs/resources/community/](https://www.rudderstack.com/docs/resources/community/) +* [https://www.rudderstack.com/docs/event-spec/standard-events/](https://www.rudderstack.com/docs/event-spec/standard-events/) +* [Recording of the community event for new contributors](https://youtu.be/OD2vCYG-P7k?feature=shared) + + + +## Building your first custom RudderStack **destination** integration + +Before diving into this tutorial, it is highly recommended to get a high-level overview of [RudderStack Event Specification](https://www.rudderstack.com/docs/event-spec/standard-events/). + +* When developing a **destination integration**, you’ll be transforming the data from RudderStack Event Specification to your target destination’s data specification. +* When developing a **source integration**, you’ll be transforming your events data received from the source to RudderStack Event Specification. + +In this tutorial, we will specifically focus on developing a destination integration. + + +### Overview of integration development journey + + +1. Add integration code to [rudder-transformer](https://github.com/rudderlabs/rudder-transformer) `src/cdk/v2/destinations` folder. This is the codebase that controls how raw event data from [RudderStack Event Data Specification](https://www.rudderstack.com/docs/event-spec/standard-events/) to destination specific data format +2. Add RudderStack UI configurations in [rudder-integrations-config](https://github.com/rudderlabs/rudder-integrations-config) `src/configurations/destinations` folder \ +This enables your integration users to setup/configure the integration via RudderStack Dashboard +3. Write the documentation for your integration (or share the [integration plan document](https://rudderstacks.notion.site/Integration-planning-document-example-Slack-Source-integration-46863d6041ec48258f9c5433eab93b28?pvs=25) with the RudderStack team) +4. RudderStack team will deploy your integration to production and post an announcement in the [Release Notes](https://www.rudderstack.com/docs/releases/) + +RudderStack team will be available to help you by giving feedback and answering questions either directly on your GitHub PR or the [RudderStack Slack community](https://www.rudderstack.com/join-rudderstack-slack-community/). Before diving into code, writing an integration plan document helps a lot, here’s an [example document](https://rudderstacks.notion.site/Integration-planning-document-example-Slack-Source-integration-46863d6041ec48258f9c5433eab93b28?pvs=25). + + +### 1. Setup rudder-transformer and understand the code structure + +Setup [rudder-transformer](https://github.com/rudderlabs/rudder-transformer) on your local machine + + + +* Clone [this repository](https://github.com/rudderlabs/rudder-transformer) +* Setup the repository with `npm run setup` +* Build the service with `npm run build:clean` +* Start the server with `npm start` + +Understand the code structure + + +* `src/cdk/v2/destinations` - Destination integrations +* `src/v1/sources` - Source integrations +* `src/v0` and `src/v1` - Older integrations. If you’re fixing bugs in one of the older integrations, you might find your integration in these folders if it is an older integration. +* `test/integrations/sources` - Integration tests for source integrations +* `test/integrations/destinations` - Integration tests for destination integrations + + +### 2. Write code for a destination integration + +Here, we will explain the code for a destination integration for single event processing as well as batch events processing. + +Before diving into the code, we recommend exploring the code for different destinations under the `src/cdk/v2/destinations` folder. This is the same structure you'll follow for your integration. This is a high-level overview of the code structure which you’ll be creating + + + +* `src/cdk/v2/destinations/**my_destination**` (follow the snake_case naming convention) - Your integration code for `my_destination` +* `src/cdk/v2/destinations/**my_destination/procWorkflow.yaml**` (processor workflow) - This is where you write the `yaml` configuration specifying how to transform an event from standard RudderStack format to destination format. This `yaml` code will later automatically get converted to javascript code using our RudderStack Workflow Engine. You will need to familiarize yourself with [RudderStack Workflow Engine](https://github.com/rudderlabs/rudder-workflow-engine) to understand what key/value you should be using. We will cover a quickstart for the same in this tutorial but whenever in doubt, refer to the [RudderStack Workflow Engine docs/readme](https://github.com/rudderlabs/rudder-workflow-engine). +* `src/cdk/v2/destinations/**my_destination/rtWorflow.yaml**` (router workflow) - For batch events integration code. This will call the processor workflow to process individual events. +* `src/cdk/v2/destinations/**my_destination/config.js**` - Configurations for the integration + +Before we dive into the code for a simple transformation for a destination, let’s address the potential questions you might have at this point + +**Why is the integration code for destination transformation written in `yaml` instead of `javascript`?** + +`yaml` is a great language for data serialization. It also makes the code short and consistent to read. This is why we moved from `javascript` to `yaml` for the data transformation code. It helped us move to a config-driven approach. + +**Does using `yaml` limit our flexibility to write complex transformation logic?** + +No. We use a templating language to support any kind of complex transformation logic in `yaml`, so we have the extensibility as well as the key benefit - concise and simple `yaml` for common transformation requirements. This was made possible by the RudderStack Workflow Engine. + +**What exactly is RudderStack Workflow Engine?** + +In the [rudder-transformer](https://github.com/rudderlabs/rudder-transformer/) service, we handle data transformation from customer events to destination events. The rudder-transformer service uses the [RudderStack Workflow Engine](https://github.com/rudderlabs/rudder-workflow-engine) to organize this transformation process into clear, manageable steps. This includes validation, data mapping, enriching with API calls, and handling various event types. These steps were earlier implemented in JavaScript, which, while flexible, was challenging to maintain and standardize. To improve readability, testability, and development speed, we transitioned to a config-driven workflow engine using template languages like JSONata and JsonTemplate, with the capability to extend to additional languages. In short, this is what helped us move transformation code from `javascript` to `yaml`. + +**To develop an integration, how much do I need to understand about RudderStack Workflow Engine?** + +Not more than what can not be covered in 10 mins. The RudderStack Workflow Engine will convert the `yaml` file to `javascript` for transformation. The key question is - how to write this `yaml` file? And the answer lies in the `keys` you can use in the `yaml`. Get familiar following keys, and you should be able to write your first integration + + + +1. `bindings` - To import external javascript functions and data + 1. `path` - The file path where we want to import from e.g. `./config` (can omit the extension `.js`) + 2. `name` - The name by which we want import e.g. `Config` (can be accessed as `$Config` or `$Config.something`) + 3. `exportAll` - If `true`, imports everything from the file. Default: `false` i.e. imports only the object matching the `name` +2. **`steps` - To express the destination transformation logic as a series of steps. If you have used GitHub action, this will sound familiar.** + 4. `name` (mandatory) - A name to track outputs + 5. `description` - Mention what does this step do + 6. `functionName` - The function we want to execute in this step. This function must be defined in the bindings and must have following definition \ + ```javascript + (input: any, bindings: Record<string, any>) => { + error?: any, + output?: any + } + ``` + + 7. `condition` - The step will get executed only when this condition is satisfied + 8. `inputTemplate` - To customize the input. Passed while executing the step. By default, all steps receive the same input as the workflow input, but when we want to modify the input before executing the step, we can use this feature. + 9. `contextTemplate` - By default, all steps receive the current context, but we can use this feature when we want to modify the context before executing the step. This is useful when using external workflows, workflow steps, or template paths. + 10. `loopOverInput` - We can use this feature when the input is an array, and we want to execute the step logic for each element independently. This is mainly used for batch processing. + 11. `steps` - You may define a series of steps inside a step. We will call such a step a `WorkflowStep` as opposed to `SimpleStep`. + 12. `workflowStepPath` - We can import the steps from another `yaml` file + 13. `batches` - To batch the inputs using filter and by length + 1. `key` - The input name e.g. “heroes” + 2. `filter` - The filter logic e.g. `.type === “hero”` + 3. `size` - The size of the batch + +A simple example of `procWorkflow.yaml` looks like this: + +```yaml +bindings: + - name: EventType + path: ../../../../constants + - path: ../../bindings/jsontemplate + exportAll: true + - name: removeUndefinedAndNullValues + path: ../../../../v0/util + +steps: + - name: validateInput + template: | + $.assert(.message.type, "message Type is not present. Aborting message."); + $.assert(.message.type in {{$.EventType.([.TRACK, .IDENTIFY])}}, + "message type " + .message.type + " is not supported"); + - name: prepareContext + template: | + $.context.messageType = .message.type.toLowerCase(); + $.context.payload = {}; + $.context.finalHeaders = { + "authorization": "Basic " + .destination.Config.apiKey, + "content-type": "application/json" + }; + - name: identifyPayload + condition: $.context.messageType == "identify" + template: | + $.context.endpoint = "https://api.fullstory.com/v2/users"; + $.context.payload.properties = .message.traits ?? .message.context.traits; + $.context.payload.uid = .message.userId; + $.context.payload.email = .message.context.traits.email; + $.context.payload.display_name = .message.context.traits.name; + + - name: trackPayload + condition: $.context.messageType == "track" + template: | + $.context.endpoint = "https://api.fullstory.com/v2/events"; + $.context.payload.name = .message.event; + $.context.payload.properties = .message.properties; + $.context.payload.timestamp = .message.originalTimestamp; + $.context.payload.context = {}; + + - name: validateEventName + condition: $.context.messageType == "track" + template: | + $.assert(.message.event, "event is required for track call") + + - name: mapContextFieldsForTrack + condition: $.context.messageType == "track" + template: | + $.context.payload.context.browser = { + "url": .message.context.page.url, + "user_agent": .message.context.userAgent, + "initial_referrer": .message.context.page.initial_referrer, + }; + $.context.payload.context.mobile = { + "app_name": .message.context.app.name, + "app_version": .message.context.app.version, + }; + $.context.payload.context.device = { + "manufacturer": .message.context.device.manufacturer, + "model": .message.context.device.model, + }; + $.context.payload.context.location = { + "ip_address": .message.context.ip, + "latitude": .message.properties.latitude, + "longitude": .message.properties.longitude, + "city": .message.properties.city, + "region": .message.properties.region, + "country": .message.properties.country, + }; + + - name: mapIdsForTrack + condition: $.context.messageType == "track" + template: | + $.context.payload.session = { + "id": .message.properties.sessionId, + "use_most_recent": .message.properties.useMostRecent, + }; + $.context.payload.user = { + "uid": .message.properties.userId ?? .message.userId, + } + + - name: cleanPayload + template: | + $.context.payload = $.removeUndefinedAndNullValues($.context.payload); + - name: buildResponseForProcessTransformation + template: | + $.context.payload.({ + "body": { + "JSON": ., + "JSON_ARRAY": {}, + "XML": {}, + "FORM": {} + }, + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": $.context.endpoint, + "headers": $.context.finalHeaders, + "params": {}, + "files": {} + }) +``` + +### 3. Test your destination integration + + +#### Manual testing + +You’ll need some API request client (e.g. Postman, Bruno, curl, etc.) for manual testing. + + + +* Make a `POST` request to this endpoint - `POST /v1/destinations/my_integration` +* Body - An array of event data object received from the source i.e. `[{ …eventData }]` +* Headers - `Content-Type: application/json` + +Depending upon your integration behavior for different types of event, you can get different types of output. + + +##### Testing standard event response + +This is what you’d want to do most of the time. The standard case, when you only transform the incoming event and hand it over to RudderStack to deliver to the destination. + +For a successful event processing in such case, you should receive HTTP 200 OK response status with data in the following structure + +```javascript +[ + { + "output": { + "batch": [ + { + ...transformedEventData + } + ] + } + } +] +``` + + +##### Testing custom event response + +You can customize the response to the HTTP request from the source beyond the standard event response format sent by RudderStack. You can customize the response body, content type header, status code, etc. Such customization is useful in some cases when you do not want to receive the standard response from RudderStack e.g. you want a custom response body and the HTTP response status code. + + +### 4. Write automated tests for your destination integration {#4-write-automated-tests-for-your-destination-integration} + +Follow the test structure similar to other integrations in `test/integrations/destinations`. Here’s an overview of the test code structure which you will be creating + + + +* `test/integrations/destinations/my_destination` - To contain all your test code for `my_destination` +* `test/integrations/destinations/my_destination/processor` - Test code for single event processing logic + * `data.ts` + * `identify.ts` - Test for [`identify`](https://www.rudderstack.com/docs/event-spec/standard-events/identify/) event + * `track.ts` - Test for [`track`](https://www.rudderstack.com/docs/event-spec/standard-events/track/) event +* `test/integrations/destinations/my_destination/router` - Test code for batch events processing logic + +You may reuse the same request data from the manual tests i.e. use them in place of `replaceThisWithYourEventPayloadProps` and `replaceThisWithYourTransformedEventOutput` (including the enclosing `[{ }]`). But make sure to redact any personal or secret information. + +Here’s an example + +```javascript +export const data = [ + { + name: 'fullstory', + description: 'Complete track event', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + anonymousId: '78c53c15-32a1-4b65-adac-bec2d7bb8fab', + channel: 'web', + context: { + app: { + name: 'RSPM', + version: '1.9.0', + }, + campaign: { + name: 'sales campaign', + source: 'google', + medium: 'medium', + term: 'event data', + content: 'Make sense of the modern data stack', + }, + ip: '192.0.2.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '2.9.1', + }, + locale: 'en-US', + device: { + manufacturer: 'Nokia', + model: 'N2023', + }, + page: { + path: '/best-seller/1', + initial_referrer: 'https://www.google.com/search', + initial_referring_domain: 'google.com', + referrer: 'https://www.google.com/search?q=estore+bestseller', + referring_domain: 'google.com', + search: 'estore bestseller', + title: 'The best sellers offered by EStore', + url: 'https://www.estore.com/best-seller/1', + }, + screen: { + density: 420, + height: 1794, + width: 1080, + innerHeight: 200, + innerWidth: 100, + }, + userAgent: + 'Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)', + }, + event: 'Product Reviewed', + integrations: { + All: true, + }, + messageId: '1578564113557-af022c68-429e-4af4-b99b-2b9174056383', + properties: { + userId: 'u001', + sessionId: 's001', + review_id: 'review_id_1', + product_id: 'product_id_1', + rating: 5, + review_body: 'Sample Review Body', + latitude: 44.56, + longitude: 54.46, + region: 'Atlas', + city: 'NY', + country: 'USA', + }, + originalTimestamp: '2020-01-09T10:01:53.558Z', + type: 'track', + sentAt: '2020-01-09T10:02:03.257Z', + }, + destination: { + ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + Name: 'Fullstory', + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + apiKey: 'dummyfullstoryAPIKey', + }, + Enabled: true, + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + JSON: { + name: 'Product Reviewed', + properties: { + userId: 'u001', + sessionId: 's001', + review_id: 'review_id_1', + product_id: 'product_id_1', + rating: 5, + review_body: 'Sample Review Body', + latitude: 44.56, + longitude: 54.46, + region: 'Atlas', + city: 'NY', + country: 'USA', + }, + timestamp: '2020-01-09T10:01:53.558Z', + context: { + browser: { + url: 'https://www.estore.com/best-seller/1', + user_agent: + 'Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)', + initial_referrer: 'https://www.google.com/search', + }, + mobile: { + app_name: 'RSPM', + app_version: '1.9.0', + }, + device: { + manufacturer: 'Nokia', + model: 'N2023', + }, + location: { + ip_address: '192.0.2.0', + latitude: 44.56, + longitude: 54.46, + city: 'NY', + region: 'Atlas', + country: 'USA', + }, + }, + session: { + id: 's001', + }, + user: { + uid: 'u001', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.fullstory.com/v2/events', + headers: { + authorization: 'Basic dummyfullstoryAPIKey', + 'content-type': 'application/json', + }, + params: {}, + files: {}, + userId: '', + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'fullstory', + description: 'Missing event name', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + device: { + manufacturer: 'Nokia', + model: 'N2023', + }, + userAgent: + 'Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)', + }, + integrations: { + All: true, + }, + properties: { + userId: 'u001', + latitude: 44.56, + longitude: 54.46, + region: 'Atlas', + city: 'NY', + country: 'USA', + }, + originalTimestamp: '2020-01-09T10:01:53.558Z', + type: 'track', + sentAt: '2020-01-09T10:02:03.257Z', + }, + destination: { + ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + Name: 'Fullstory', + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + apiKey: 'dummyfullstoryAPIKey', + }, + Enabled: true, + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + statusCode: 400, + error: + 'event is required for track call: Workflow: procWorkflow, Step: validateEventName, ChildStep: undefined, OriginalError: event is required for track call', + statTags: { + errorCategory: 'dataValidation', + errorType: 'instrumentation', + implementation: 'cdkV2', + destType: 'FULLSTORY', + module: 'destination', + feature: 'processor', + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, + { + name: 'fullstory', + description: 'Complete identify event', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + userId: 'dummy-user001', + channel: 'web', + context: { + traits: { + company: 'Initech', + address: { + country: 'USA', + state: 'CA', + street: '101 dummy street', + }, + email: 'dummyuser@domain.com', + name: 'dummy user', + phone: '099-999-9999', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', + }, + integrations: { + All: true, + }, + originalTimestamp: '2020-01-27T12:20:55.301Z', + receivedAt: '2020-01-27T17:50:58.657+05:30', + request_ip: '14.98.244.60', + sentAt: '2020-01-27T12:20:56.849Z', + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + }, + destination: { + ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + Name: 'Fullstory', + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + apiKey: 'fullstoryAPIKey', + }, + Enabled: true, + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + JSON: { + properties: { + company: 'Initech', + address: { + country: 'USA', + state: 'CA', + street: '101 dummy street', + }, + email: 'dummyuser@domain.com', + name: 'dummy user', + phone: '099-999-9999', + }, + uid: 'dummy-user001', + email: 'dummyuser@domain.com', + display_name: 'dummy user', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.fullstory.com/v2/users', + headers: { + authorization: 'Basic fullstoryAPIKey', + 'content-type': 'application/json', + }, + params: {}, + files: {}, + userId: '', + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'fullstory', + description: 'Identify event with needed traits', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + userId: 'dummy-user001', + channel: 'web', + context: { + traits: { + email: 'dummyuser@domain.com', + name: 'dummy user', + phone: '099-999-9999', + }, + }, + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + }, + destination: { + ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + Name: 'Fullstory', + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + apiKey: 'fullstoryAPIKey', + }, + Enabled: true, + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + JSON: { + properties: { + email: 'dummyuser@domain.com', + name: 'dummy user', + phone: '099-999-9999', + }, + uid: 'dummy-user001', + email: 'dummyuser@domain.com', + display_name: 'dummy user', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.fullstory.com/v2/users', + headers: { + authorization: 'Basic fullstoryAPIKey', + 'content-type': 'application/json', + }, + params: {}, + files: {}, + userId: '', + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; +``` + +#### Running automated tests + +You can run tests only for the specific integration, for example + + + +* To test Slack destination - `npm run test:ts -- component --destination=my_destination` + +These tests will automatically be run on each commit, making sure that any new development does not break the existing integrations. + + +### 5. Add RudderStack UI configurations in integrations-config + +Add configuration for your destination integration in [rudder-integrations-config](https://github.com/rudderlabs/rudder-integrations-config) repo under `src.configurations/destinations`. At bare minimum, a db-config file is needed, here’s [an example](https://github.com/rudderlabs/rudder-integrations-config/blob/develop/src/configurations/destinations/fullstory/db-config.json) of the same for FullStory destination. Duplicate it in the directory for your integration config folder and change the relevant values for your integration. + +Alternatively, the easier path to do this is by running a script which will generate these files for you. For this, first create a copy of this `[test/configData/inputData.json](https://github.com/rudderlabs/rudder-integrations-config/blob/develop/test/configData/inputData.json)` and adjust it to what you want to see in the RudderStack dashboard ui. And use that placeholder file in the following command + +`python3 scripts/configGenerator.py <path of the placeholder file>` + +Run this command from the root directory of the rudder-integrations-config repo. The PR can then be raised after checking if everything looks good. + + +### 6. Run the transformer locally + +```bash + +nvm use v20 + +npm ci + +npm run build:start + +``` + +### References + +* [Contributing.md](https://github.com/rudderlabs/rudder-server/blob/master/CONTRIBUTING.md\) in all github repositories +* [https://www.rudderstack.com/docs/resources/community/](https://www.rudderstack.com/docs/resources/community/) +* [https://www.rudderstack.com/docs/event-spec/standard-events/](https://www.rudderstack.com/docs/event-spec/standard-events/) +* [RudderStack Workflow Engine](https://github.com/rudderlabs/rudder-workflow-engine) +* [RudderStack JSON Templating Engine](https://github.com/rudderlabs/rudder-json-template-engine) +* [Recording of the community event for new contributors](https://youtu.be/OD2vCYG-P7k?feature=shared) + We look forward to your feedback on improving this project. From a05e3397dadcf35c70fd00f531e8b93352533c8d Mon Sep 17 00:00:00 2001 From: Gauravudia <60897972+Gauravudia@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:44:07 +0530 Subject: [PATCH 018/147] chore: enable router transform for http destination (#3736) --- src/features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features.json b/src/features.json index 503df3eccfc..097e4a8aa0b 100644 --- a/src/features.json +++ b/src/features.json @@ -80,7 +80,7 @@ "X_AUDIENCE": true, "BLOOMREACH_CATALOG": true, "SMARTLY": true, - "WEBHOOK_V2": true + "HTTP": true }, "regulations": [ "BRAZE", From f33f52503679be9271751aaa2fdca0661fed62e9 Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:59:34 +0530 Subject: [PATCH 019/147] feat: add support for vdm next to fb custom audiences (#3729) * feat: add support for vdm next to fb custom audiences Add support record v2 format for vdm next. * chore: add missing tests * chore: refactor fbca * chore: update docs * chore: update docs --- package-lock.json | 6115 +- package.json | 1 + src/types/index.ts | 11 + .../destinations/fb_custom_audience/config.js | 6 +- .../fb_custom_audience/recordTransform.js | 140 +- .../fb_custom_audience/transform.js | 42 +- .../destinations/fb_custom_audience/util.js | 9 +- src/v0/util/constant.js | 3 + src/v0/util/index.js | 8 +- test/integrations/component.test.ts | 2 +- .../destinations/fb_custom_audience/mocks.ts | 4 + .../fb_custom_audience/processor/data.ts | 52263 +--------------- .../fb_custom_audience/router/audienceList.ts | 123 - .../router/batchingRecord.ts | 130 - .../fb_custom_audience/router/data.ts | 437 +- .../fb_custom_audience/router/eventStream.ts | 137 +- .../router/{record.ts => rETL.ts} | 185 +- test/integrations/testUtils.ts | 4 +- 18 files changed, 2439 insertions(+), 57181 deletions(-) create mode 100644 test/integrations/destinations/fb_custom_audience/mocks.ts delete mode 100644 test/integrations/destinations/fb_custom_audience/router/audienceList.ts delete mode 100644 test/integrations/destinations/fb_custom_audience/router/batchingRecord.ts rename test/integrations/destinations/fb_custom_audience/router/{record.ts => rETL.ts} (57%) diff --git a/package-lock.json b/package-lock.json index cf0af8c3253..fadfe7df1bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,6 +86,7 @@ "@types/koa-bodyparser": "^4.3.10", "@types/lodash": "^4.14.197", "@types/node": "^20.2.5", + "@types/supertest": "^6.0.2", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.59.2", "axios-mock-adapter": "^1.22.0", @@ -449,19 +450,6 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-crypto/ie11-detection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@aws-crypto/sha1-browser": { "version": "5.2.0", "license": "Apache-2.0", @@ -515,6 +503,235 @@ "tslib": "^2.6.2" } }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.650.0.tgz", + "integrity": "sha512-ng9Ta7emTgIAnUW52wi2KcNbAudGQPiXuPKJwtw67WQei3gHMpxvgCCRXP7AiB+LyB/fBURxraDkO5N+sPZp0w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.650.0", + "@aws-sdk/client-sts": "3.650.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.650.0.tgz", + "integrity": "sha512-6J7IS0f8ovhvbIAZaynOYP+jPX8344UlTjwHxjaXHgFvI8axu3+NslKtEEV5oHLhgzDvrKbinsu5lgE2n4Sqng==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/client-sts": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.650.0.tgz", + "integrity": "sha512-ISK0ZQYA7O5/WYgslpWy956lUBudGC9d7eL0FFbiL0j50N80Gx3RUv22ezvZgxJWE0W3DqNr4CE19sPYn4Lw8g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.650.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.649.0.tgz", + "integrity": "sha512-IY43r256LhKAvdEVQO/FPdUyVpcZS5EVxh/WHVdNzuN1bNLoUK2rIzuZqVA0EGguvCxoXVmQv9m50GvG7cGktg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.649.0.tgz", + "integrity": "sha512-x5DiLpZDG/AJmCIBnE3Xhpwy35QIo3WqNiOpw6ExVs1NydbM/e90zFPSfhME0FM66D/WorigvluBxxwjxDm/GA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-personalize": { "version": "3.642.0", "license": "Apache-2.0", @@ -1349,50 +1566,52 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.485.0.tgz", - "integrity": "sha512-apN2bEn0PZs0jD4jAfvwO3dlWqw9YIQJ6TAudM1bd3S5vzWqlBBcLfQpK6taHoQaI+WqgUWXLuOf7gRFbGXKPg==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.650.0.tgz", + "integrity": "sha512-YKm14gCMChD/jlCisFlsVqB8HJujR41bl4Fup2crHwNJxhD/9LTnzwMiVVlBqlXr41Sfa6fSxczX2AMP8NM14A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, "node_modules/@aws-sdk/client-sso-oidc": { @@ -1790,92 +2009,31 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/sha256-js/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/util/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", - "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.649.0.tgz", + "integrity": "sha512-IY43r256LhKAvdEVQO/FPdUyVpcZS5EVxh/WHVdNzuN1bNLoUK2rIzuZqVA0EGguvCxoXVmQv9m50GvG7cGktg==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", "bowser": "^2.11.0", - "tslib": "^2.5.0" + "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", - "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.649.0.tgz", + "integrity": "sha512-x5DiLpZDG/AJmCIBnE3Xhpwy35QIo3WqNiOpw6ExVs1NydbM/e90zFPSfhME0FM66D/WorigvluBxxwjxDm/GA==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" }, "peerDependencies": { "aws-crt": ">=1.0.0" @@ -1886,3598 +2044,266 @@ } } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/config-resolver": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.2.0.tgz", - "integrity": "sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-config-provider": "^2.3.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.4.2.tgz", - "integrity": "sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-retry": "^2.3.1", - "@smithy/middleware-serde": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "tslib": "^2.6.2" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/hash-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.2.0.tgz", - "integrity": "sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==", + "node_modules/@aws-sdk/client-sts": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.637.0.tgz", + "integrity": "sha512-xUi7x4qDubtA8QREtlblPuAcn91GS/09YVEY/RwU7xCY0aqGuFwgszAANlha4OUIqva8oVj2WO4gJuG+iaSnhw==", "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.637.0", + "@aws-sdk/core": "3.635.0", + "@aws-sdk/credential-provider-node": "3.637.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.637.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.637.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.4.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.15", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.15", + "@smithy/util-defaults-mode-node": "^3.0.15", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/hash-node/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/hash-node/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/hash-node/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/invalid-dependency": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.2.0.tgz", - "integrity": "sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-content-length": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.2.0.tgz", - "integrity": "sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", - "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-retry": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/service-error-classification": "^2.1.5", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-retry": "^2.2.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", - "dependencies": { - "@smithy/types": "^2.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-base64/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-base64/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-base64/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-body-length-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.2.0.tgz", - "integrity": "sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-body-length-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.3.0.tgz", - "integrity": "sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.2.1.tgz", - "integrity": "sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-defaults-mode-node": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.3.1.tgz", - "integrity": "sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==", - "dependencies": { - "@smithy/config-resolver": "^2.2.0", - "@smithy/credential-provider-imds": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-endpoints": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", - "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-stream/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-stream/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-stream/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.637.0.tgz", - "integrity": "sha512-xUi7x4qDubtA8QREtlblPuAcn91GS/09YVEY/RwU7xCY0aqGuFwgszAANlha4OUIqva8oVj2WO4gJuG+iaSnhw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.637.0", - "@aws-sdk/core": "3.635.0", - "@aws-sdk/credential-provider-node": "3.637.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.637.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.637.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.4.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.15", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.15", - "@smithy/util-defaults-mode-node": "^3.0.15", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/client-sso": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.637.0.tgz", - "integrity": "sha512-+KjLvgX5yJYROWo3TQuwBJlHCY0zz9PsLuEolmXQn0BVK1L/m9GteZHtd+rEdAoDGBpE0Xqjy1oz5+SmtsaRUw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.635.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.637.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.637.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.4.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.15", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.15", - "@smithy/util-defaults-mode-node": "^3.0.15", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/core": { - "version": "3.635.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.635.0.tgz", - "integrity": "sha512-i1x/E/sgA+liUE1XJ7rj1dhyXpAKO1UKFUcTTHXok2ARjWTvszHnSXMOsB77aPbmn0fUp1JTx2kHUAZ1LVt5Bg==", - "dependencies": { - "@smithy/core": "^2.4.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.635.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.635.0.tgz", - "integrity": "sha512-iJyRgEjOCQlBMXqtwPLIKYc7Bsc6nqjrZybdMDenPDa+kmLg7xh8LxHsu9088e+2/wtLicE34FsJJIfzu3L82g==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.637.0.tgz", - "integrity": "sha512-h+PFCWfZ0Q3Dx84SppET/TFpcQHmxFW8/oV9ArEvMilw4EBN+IlxgbL0CnHwjHW64szcmrM0mbebjEfHf4FXmw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.635.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.637.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.637.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.637.0.tgz", - "integrity": "sha512-yoEhoxJJfs7sPVQ6Is939BDQJZpZCoUgKr/ySse4YKOZ24t4VqgHA6+wV7rYh+7IW24Rd91UTvEzSuHYTlxlNA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.635.0", - "@aws-sdk/credential-provider-ini": "3.637.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.637.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.637.0.tgz", - "integrity": "sha512-Mvz+h+e62/tl+dVikLafhv+qkZJ9RUb8l2YN/LeKMWkxQylPT83CPk9aimVhCV89zth1zpREArl97+3xsfgQvA==", - "dependencies": { - "@aws-sdk/client-sso": "3.637.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.637.0.tgz", - "integrity": "sha512-EYo0NE9/da/OY8STDsK2LvM4kNa79DBsf4YVtaG4P5pZ615IeFsD8xOHZeuJmUrSMlVQ8ywPRX7WMucUybsKug==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.637.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.614.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-endpoints": { - "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.637.0.tgz", - "integrity": "sha512-pAqOKUHeVWHEXXDIp/qoMk/6jyxIb6GGjnK1/f8dKHtKIEs4tKsnnL563gceEvdad53OPXIt86uoevCcCzmBnw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.485.0.tgz", - "integrity": "sha512-Yvi80DQcbjkYCft471ClE3HuetuNVqntCs6eFOomDcrJaqdOFrXv2kJAxky84MRA/xb7bGlDGAPbTuj1ICputg==", - "dependencies": { - "@smithy/core": "^1.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/signature-v4": "^2.0.0", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.4.2.tgz", - "integrity": "sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-retry": "^2.3.1", - "@smithy/middleware-serde": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", - "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-retry": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/service-error-classification": "^2.1.5", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-retry": "^2.2.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", - "dependencies": { - "@smithy/types": "^2.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/signature-v4": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.3.0.tgz", - "integrity": "sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-uri-escape": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", - "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.485.0.tgz", - "integrity": "sha512-XIy5h1AcDiY3V286X7KrLA5HAxLfzLGrUGBPFY+GTJGYetDhlJwFz12q6BOkIfeAhUbT2Umb4ptujX9eqpZJHQ==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/sha256-js/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-crypto/util/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.485.0.tgz", - "integrity": "sha512-1SYhvRu/dNqQ5HcIgm7wIpyn1FsthbgG04o6QyVAnfOxmawFt4nqCEtNCwsmlX7o1ZCTYY+qNrozb7XZy+GKSQ==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.485.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-signing": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/client-sts": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.485.0.tgz", - "integrity": "sha512-PI4q36kVF0fpIPZyeQhrwwJZ6SRkOGvU3rX5Qn4b5UY5X+Ct1aLhqSX8/OB372UZIcnh6eSvERu8POHleDO7Jw==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-middleware": "^2.0.9", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", - "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", - "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/config-resolver": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.2.0.tgz", - "integrity": "sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-config-provider": "^2.3.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.4.2.tgz", - "integrity": "sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-retry": "^2.3.1", - "@smithy/middleware-serde": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/hash-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.2.0.tgz", - "integrity": "sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/invalid-dependency": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.2.0.tgz", - "integrity": "sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/middleware-content-length": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.2.0.tgz", - "integrity": "sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", - "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/middleware-retry": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/service-error-classification": "^2.1.5", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-retry": "^2.2.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", - "dependencies": { - "@smithy/types": "^2.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-body-length-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.2.0.tgz", - "integrity": "sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-body-length-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.3.0.tgz", - "integrity": "sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.2.1.tgz", - "integrity": "sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-defaults-mode-node": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.3.1.tgz", - "integrity": "sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==", - "dependencies": { - "@smithy/config-resolver": "^2.2.0", - "@smithy/credential-provider-imds": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-endpoints": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", - "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/fast-xml-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", - "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.485.0.tgz", - "integrity": "sha512-3XkFgwVU1XOB33dV7t9BKJ/ptdl2iS+0dxE7ecq8aqT2/gsfKmLCae1G17P8WmdD3z0kMDTvnqM2aWgUnSOkmg==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.485.0.tgz", - "integrity": "sha512-2/2Y3Z7cpKf8vbQ+FzoBPxRyb0hGJZB1YrnH7hptVi5gSVe1NiwV5ZtsDnv4cwUfOBqEu97nMXw5IrRO26S0DA==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/util-stream": "^2.0.24", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", - "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.485.0.tgz", - "integrity": "sha512-cFYF/Bdw7EnT4viSxYpNIv3IBkri/Yb+JpQXl8uDq7bfVJfAN5qZmK07vRkg08xL6TC4F41wshhMSAucGdTwIw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.485.0.tgz", - "integrity": "sha512-2DwzO2azkSzngifKDT61W/DL0tSzewuaFHiLJWdfc8Et3mdAQJ9x3KAj8u7XFpjIcGNqk7FiKjN+zeGUuNiEhA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-ini": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.485.0.tgz", - "integrity": "sha512-X9qS6ZO/rDKYDgWqD1YmSX7sAUUHax9HbXlgGiTTdtfhZvQh1ZmnH6wiPu5WNliafHZFtZT2W07kgrDLPld/Ug==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.485.0.tgz", - "integrity": "sha512-l0oC8GTrWh+LFQQfSmG1Jai1PX7Mhj9arb/CaS1/tmeZE0hgIXW++tvljYs/Dds4LGXUlaWG+P7BrObf6OyIXA==", - "dependencies": { - "@aws-sdk/client-sso": "3.485.0", - "@aws-sdk/token-providers": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.485.0.tgz", - "integrity": "sha512-WpBFZFE0iXtnibH5POMEKITj/hR0YV5l2n9p8BEvKjdJ63s3Xke1RN20ZdIyKDaRDwj8adnKDgNPEnAKdS4kLw==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.485.0.tgz", - "integrity": "sha512-SpGEmiVr+C9Dtc5tZFfFYXSNxbl1jShLlyZPWERHBn4QwGvdXcgPB96I0yvUuitBKrM0winHsCWH7CR/z24kmg==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.485.0", - "@aws-sdk/client-sso": "3.485.0", - "@aws-sdk/client-sts": "3.485.0", - "@aws-sdk/credential-provider-cognito-identity": "3.485.0", - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-http": "3.485.0", - "@aws-sdk/credential-provider-ini": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/sha256-js/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-crypto/util/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.485.0.tgz", - "integrity": "sha512-1SYhvRu/dNqQ5HcIgm7wIpyn1FsthbgG04o6QyVAnfOxmawFt4nqCEtNCwsmlX7o1ZCTYY+qNrozb7XZy+GKSQ==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.485.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-signing": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-sts": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.485.0.tgz", - "integrity": "sha512-PI4q36kVF0fpIPZyeQhrwwJZ6SRkOGvU3rX5Qn4b5UY5X+Ct1aLhqSX8/OB372UZIcnh6eSvERu8POHleDO7Jw==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-middleware": "^2.0.9", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", - "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", - "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/config-resolver": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.2.0.tgz", - "integrity": "sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-config-provider": "^2.3.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.4.2.tgz", - "integrity": "sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-retry": "^2.3.1", - "@smithy/middleware-serde": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/hash-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.2.0.tgz", - "integrity": "sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/invalid-dependency": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.2.0.tgz", - "integrity": "sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/middleware-content-length": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.2.0.tgz", - "integrity": "sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==", - "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", - "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/middleware-retry": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/service-error-classification": "^2.1.5", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-retry": "^2.2.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", - "dependencies": { - "@smithy/types": "^2.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", - "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-body-length-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.2.0.tgz", - "integrity": "sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-body-length-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.3.0.tgz", - "integrity": "sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.2.1.tgz", - "integrity": "sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==", - "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-defaults-mode-node": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.3.1.tgz", - "integrity": "sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==", - "dependencies": { - "@smithy/config-resolver": "^2.2.0", - "@smithy/credential-provider-imds": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-endpoints": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", - "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/fast-xml-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", - "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/@aws-sdk/lib-storage": { + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/client-sso": { "version": "3.637.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.637.0.tgz", - "integrity": "sha512-HiNGOP4a1QrCWwO1joKw4mCp19nLXoF9K52PislBaYDI35IlHC3DP6MeOg5zmElwtL1GtEHFBy5olfPWPsLyLg==", - "dependencies": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/smithy-client": "^3.2.0", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.637.0" - } - }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.620.0.tgz", - "integrity": "sha512-eGLL0W6L3HDb3OACyetZYOWpHJ+gLo0TehQKeQyy2G8vTYXqNTeqYhuI6up9HVjBzU9eQiULVQETmgQs7TFaRg==", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.637.0.tgz", + "integrity": "sha512-+KjLvgX5yJYROWo3TQuwBJlHCY0zz9PsLuEolmXQn0BVK1L/m9GteZHtd+rEdAoDGBpE0Xqjy1oz5+SmtsaRUw==", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.635.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.637.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-arn-parser": "3.568.0", + "@aws-sdk/util-endpoints": "3.637.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.4.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.15", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.620.0.tgz", - "integrity": "sha512-QXeRFMLfyQ31nAHLbiTLtk0oHzG9QLMaof5jIfqcUwnOkO8YnQdeqzakrg1Alpy/VQ7aqzIi8qypkBe2KXZz0A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.620.0.tgz", - "integrity": "sha512-ftz+NW7qka2sVuwnnO1IzBku5ccP+s5qZGeRTPgrKB7OzRW85gthvIo1vQR2w+OwHFk7WJbbhhWwbCbktnP4UA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@aws-crypto/crc32c": "5.2.0", - "@aws-sdk/types": "3.609.0", - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.15", + "@smithy/util-defaults-mode-node": "^3.0.15", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/core": { + "version": "3.635.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.635.0.tgz", + "integrity": "sha512-i1x/E/sgA+liUE1XJ7rj1dhyXpAKO1UKFUcTTHXok2ARjWTvszHnSXMOsB77aPbmn0fUp1JTx2kHUAZ1LVt5Bg==", "dependencies": { + "@smithy/core": "^2.4.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.635.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.635.0.tgz", + "integrity": "sha512-iJyRgEjOCQlBMXqtwPLIKYc7Bsc6nqjrZybdMDenPDa+kmLg7xh8LxHsu9088e+2/wtLicE34FsJJIfzu3L82g==", "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.485.0.tgz", - "integrity": "sha512-1mAUX9dQNGo2RIKseVj7SI/D5abQJQ/Os8hQ0NyVAyyVYF+Yjx5PphKgfhM5yoBwuwZUl6q71XPYEGNx7be6SA==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.637.0.tgz", + "integrity": "sha512-h+PFCWfZ0Q3Dx84SppET/TFpcQHmxFW8/oV9ArEvMilw4EBN+IlxgbL0CnHwjHW64szcmrM0mbebjEfHf4FXmw==", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.635.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.637.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.637.0" } }, - "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.637.0.tgz", + "integrity": "sha512-yoEhoxJJfs7sPVQ6Is939BDQJZpZCoUgKr/ySse4YKOZ24t4VqgHA6+wV7rYh+7IW24Rd91UTvEzSuHYTlxlNA==", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.635.0", + "@aws-sdk/credential-provider-ini": "3.637.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.637.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.609.0.tgz", - "integrity": "sha512-xzsdoTkszGVqGVPjUmgoP7TORiByLueMHieI1fhQL888WPdqctwAx3ES6d/bA9Q/i8jnc6hs+Fjhy8UvBTkE9A==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.637.0.tgz", + "integrity": "sha512-Mvz+h+e62/tl+dVikLafhv+qkZJ9RUb8l2YN/LeKMWkxQylPT83CPk9aimVhCV89zth1zpREArl97+3xsfgQvA==", "dependencies": { + "@aws-sdk/client-sso": "3.637.0", + "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -5485,131 +2311,117 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.485.0.tgz", - "integrity": "sha512-O8IgJ0LHi5wTs5GlpI7nqmmSSagkVdd1shpGgQWY2h0kMSCII8CJZHBG97dlFFpGTvx5EDlhPNek7rl/6F4dRw==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" }, - "engines": { - "node": ">=14.0.0" + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/middleware-logger/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.485.0.tgz", - "integrity": "sha512-ZeVNATGNFcqkWDut3luVszROTUzkU5u+rJpB/xmeMoenlDAjPRiHt/ca3WkI5wAnIJ1VSNGpD2sOFLMCH+EWag==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.637.0.tgz", + "integrity": "sha512-EYo0NE9/da/OY8STDsK2LvM4kNa79DBsf4YVtaG4P5pZ615IeFsD8xOHZeuJmUrSMlVQ8ywPRX7WMucUybsKug==", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.637.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.635.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.635.0.tgz", - "integrity": "sha512-RLdYJPEV4JL/7NBoFUs7VlP90X++5FlJdxHz0DzCjmiD3qCviKy+Cym3qg1gBgHwucs5XisuClxDrGokhAdTQw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", "dependencies": { - "@aws-sdk/core": "3.635.0", "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-arn-parser": "3.568.0", - "@smithy/core": "^2.4.0", "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", "@smithy/types": "^3.3.0", "@smithy/util-config-provider": "^3.0.0", "@smithy/util-middleware": "^3.0.3", - "@smithy/util-stream": "^3.1.3", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/core": { - "version": "3.635.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.635.0.tgz", - "integrity": "sha512-i1x/E/sgA+liUE1XJ7rj1dhyXpAKO1UKFUcTTHXok2ARjWTvszHnSXMOsB77aPbmn0fUp1JTx2kHUAZ1LVt5Bg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", "dependencies": { - "@smithy/core": "^2.4.0", - "@smithy/node-config-provider": "^3.1.4", + "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", + "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/types": { + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/types": { "version": "3.609.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" @@ -5618,462 +2430,560 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-endpoints": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.637.0.tgz", + "integrity": "sha512-pAqOKUHeVWHEXXDIp/qoMk/6jyxIb6GGjnK1/f8dKHtKIEs4tKsnnL563gceEvdad53OPXIt86uoevCcCzmBnw==", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-buffer-from": { + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-utf8": { + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-buffer-from": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.485.0.tgz", - "integrity": "sha512-41xzT2p1sOibhsLkdE5rwPJkNbBtKD8Gp36/ySfu0KE415wfXKacElSVxAaBw39/j7iSWDYqqybeEYbAzk+3GQ==", - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.8.0", - "@smithy/util-middleware": "^2.0.9", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/signature-v4": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.3.0.tgz", - "integrity": "sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==", + "node_modules/@aws-sdk/core": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.649.0.tgz", + "integrity": "sha512-dheG/X2y25RHE7K+TlS32kcy7TgDg1OpWV44BQRoE0OBPAWmFR1D1qjjTZ7WWrdqRPKzcnDj1qED8ncyncOX8g==", + "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-uri-escape": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", + "@smithy/core": "^2.4.1", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/property-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.1", + "@smithy/signature-v4": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/util-middleware": "^3.0.4", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.650.0.tgz", + "integrity": "sha512-QwtRKWKE6vv78Be3Lm5GmFkSl2DGWSOXPZYgkbo8GsD6SP0ParUvJvUE8wsPS5c4tUXC9KuvJAwYAYNFN10Fnw==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/client-cognito-identity": "3.650.0", + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.649.0.tgz", + "integrity": "sha512-tViwzM1dauksA3fdRjsg0T8mcHklDa8EfveyiQKK6pUJopkqV6FQx+X5QNda0t/LrdEVlFZvwHNdXqOEfc83TA==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.649.0.tgz", + "integrity": "sha512-ODAJ+AJJq6ozbns6ejGbicpsQ0dyMOpnGlg0J9J0jITQ05DKQZ581hdB8APDOZ9N8FstShP6dLZflSj8jb5fNA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.649.0", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/util-stream": "^3.1.4", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.650.0.tgz", + "integrity": "sha512-uBra5YjzS/gWSekAogfqJfY6c+oKQkkou7Cjc4d/cpMNvQtF1IBdekJ7NaE1RfsDEz3uH1+Myd07YWZAJo/2Qw==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/credential-provider-env": "3.649.0", + "@aws-sdk/credential-provider-http": "3.649.0", + "@aws-sdk/credential-provider-ini": "3.650.0", + "@aws-sdk/credential-provider-process": "3.649.0", + "@aws-sdk/credential-provider-sso": "3.650.0", + "@aws-sdk/credential-provider-web-identity": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@smithy/credential-provider-imds": "^3.2.1", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.609.0.tgz", - "integrity": "sha512-GZSD1s7+JswWOTamVap79QiDaIV7byJFssBW68GYjyRS5EBjNfwA/8s+6uE6g39R3ojyTbYOmvcANoZEhSULXg==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.650.0.tgz", + "integrity": "sha512-6J7IS0f8ovhvbIAZaynOYP+jPX8344UlTjwHxjaXHgFvI8axu3+NslKtEEV5oHLhgzDvrKbinsu5lgE2n4Sqng==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" } }, - "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/client-sts": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.650.0.tgz", + "integrity": "sha512-ISK0ZQYA7O5/WYgslpWy956lUBudGC9d7eL0FFbiL0j50N80Gx3RUv22ezvZgxJWE0W3DqNr4CE19sPYn4Lw8g==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/types": "^3.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.650.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.485.0.tgz", - "integrity": "sha512-CddCVOn+OPQ0CcchketIg+WF6v+MDLAf3GOYTR2htUxxIm7HABuRd6R3kvQ5Jny9CV8gMt22G1UZITsFexSJlQ==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.650.0.tgz", + "integrity": "sha512-x2M9buZxIsKuUbuDgkGHhAKYBpn0/rYdKlwuFuOhXyyAcnhvPj0lgNF2KE4ld/GF1mKr7FF/uV3G9lM6PFaYmA==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/credential-provider-env": "3.649.0", + "@aws-sdk/credential-provider-http": "3.649.0", + "@aws-sdk/credential-provider-process": "3.649.0", + "@aws-sdk/credential-provider-sso": "3.650.0", + "@aws-sdk/credential-provider-web-identity": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@smithy/credential-provider-imds": "^3.2.1", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" } }, - "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.649.0.tgz", + "integrity": "sha512-XVk3WsDa0g3kQFPmnCH/LaCtGY/0R2NDv7gscYZSXiBZcG/fixasglTprgWSp8zcA0t7tEIGu9suyjz8ZwhymQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.649.0" } }, - "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.649.0.tgz", + "integrity": "sha512-IY43r256LhKAvdEVQO/FPdUyVpcZS5EVxh/WHVdNzuN1bNLoUK2rIzuZqVA0EGguvCxoXVmQv9m50GvG7cGktg==", + "license": "Apache-2.0", + "peer": true, "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", + "bowser": "^2.11.0", "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.485.0.tgz", - "integrity": "sha512-2FB2EQ0sIE+YgFqGtkE1lDIMIL6nYe6MkOHBwBM7bommadKIrbbr2L22bPZGs3ReTsxiJabjzxbuCAVhrpHmhg==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.649.0.tgz", + "integrity": "sha512-x5DiLpZDG/AJmCIBnE3Xhpwy35QIo3WqNiOpw6ExVs1NydbM/e90zFPSfhME0FM66D/WorigvluBxxwjxDm/GA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "@smithy/util-config-provider": "^2.1.0", - "@smithy/util-middleware": "^2.0.9", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.649.0.tgz", + "integrity": "sha512-6VYPQpEVpU+6DDS/gLoI40ppuNM5RPIEprK30qZZxnhTr5wyrGOeJ7J7wbbwPOZ5dKwta290BiJDU2ipV8Y9BQ==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/util-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.650.0.tgz", + "integrity": "sha512-069nkhcwximbvyGiAC6Fr2G+yrG/p1S3NQ5BZ2cMzB1hgUKo6TvgFK7nriYI4ljMQ+UWxqPwIdTqiUmn2iJmhg==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/client-sso": "3.650.0", + "@aws-sdk/token-providers": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.650.0.tgz", + "integrity": "sha512-6J7IS0f8ovhvbIAZaynOYP+jPX8344UlTjwHxjaXHgFvI8axu3+NslKtEEV5oHLhgzDvrKbinsu5lgE2n4Sqng==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" } }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.635.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.635.0.tgz", - "integrity": "sha512-J6QY4/invOkpogCHjSaDON1hF03viPpOnsrzVuCvJMmclS/iG62R4EY0wq1alYll0YmSdmKlpJwHMWwGtqK63Q==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/client-sts": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.650.0.tgz", + "integrity": "sha512-ISK0ZQYA7O5/WYgslpWy956lUBudGC9d7eL0FFbiL0j50N80Gx3RUv22ezvZgxJWE0W3DqNr4CE19sPYn4Lw8g==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.635.0", - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.650.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.649.0.tgz", + "integrity": "sha512-ZBqr+JuXI9RiN+4DSZykMx5gxpL8Dr3exIfFhxMiwAP3DQojwl0ub8ONjMuAjq9OvmX6n+jHZL6fBnNgnNFC8w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.485.0.tgz", - "integrity": "sha512-kOXA1WKIVIFNRqHL8ynVZ3hCKLsgnEmGr2iDR6agDNw5fYIlCO/6N2xR6QdGcLTvUUbwOlz4OvKLUQnWMKAnnA==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/sha256-js/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.649.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-crypto/util/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", - "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.649.0.tgz", + "integrity": "sha512-IY43r256LhKAvdEVQO/FPdUyVpcZS5EVxh/WHVdNzuN1bNLoUK2rIzuZqVA0EGguvCxoXVmQv9m50GvG7cGktg==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", "bowser": "^2.11.0", - "tslib": "^2.5.0" + "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", - "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.649.0.tgz", + "integrity": "sha512-x5DiLpZDG/AJmCIBnE3Xhpwy35QIo3WqNiOpw6ExVs1NydbM/e90zFPSfhME0FM66D/WorigvluBxxwjxDm/GA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" }, "peerDependencies": { "aws-crt": ">=1.0.0" @@ -6084,555 +2994,739 @@ } } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/types": "^2.12.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/config-resolver": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.2.0.tgz", - "integrity": "sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-config-provider": "^2.3.0", - "@smithy/util-middleware": "^2.2.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/credential-provider-imds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/fetch-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", + "node_modules/@aws-sdk/credential-providers": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.650.0.tgz", + "integrity": "sha512-e99xHtzfL3fwS5j2gzMXRikoux/vNO3JKlxYSTnz/yfcReYRtRIz4iNrbqOzYFIQFlPS11ToXXXcwl6FOzNM7Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", + "@aws-sdk/client-cognito-identity": "3.650.0", + "@aws-sdk/client-sso": "3.650.0", + "@aws-sdk/client-sts": "3.650.0", + "@aws-sdk/credential-provider-cognito-identity": "3.650.0", + "@aws-sdk/credential-provider-env": "3.649.0", + "@aws-sdk/credential-provider-http": "3.649.0", + "@aws-sdk/credential-provider-ini": "3.650.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/credential-provider-process": "3.649.0", + "@aws-sdk/credential-provider-sso": "3.650.0", + "@aws-sdk/credential-provider-web-identity": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@smithy/credential-provider-imds": "^3.2.1", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/hash-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.2.0.tgz", - "integrity": "sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.650.0.tgz", + "integrity": "sha512-6J7IS0f8ovhvbIAZaynOYP+jPX8344UlTjwHxjaXHgFvI8axu3+NslKtEEV5oHLhgzDvrKbinsu5lgE2n4Sqng==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/invalid-dependency": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.2.0.tgz", - "integrity": "sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-sts": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.650.0.tgz", + "integrity": "sha512-ISK0ZQYA7O5/WYgslpWy956lUBudGC9d7eL0FFbiL0j50N80Gx3RUv22ezvZgxJWE0W3DqNr4CE19sPYn4Lw8g==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.650.0", + "@aws-sdk/core": "3.649.0", + "@aws-sdk/credential-provider-node": "3.650.0", + "@aws-sdk/middleware-host-header": "3.649.0", + "@aws-sdk/middleware-logger": "3.649.0", + "@aws-sdk/middleware-recursion-detection": "3.649.0", + "@aws-sdk/middleware-user-agent": "3.649.0", + "@aws-sdk/region-config-resolver": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@aws-sdk/util-user-agent-browser": "3.649.0", + "@aws-sdk/util-user-agent-node": "3.649.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/core": "^2.4.1", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/hash-node": "^3.0.4", + "@smithy/invalid-dependency": "^3.0.4", + "@smithy/middleware-content-length": "^3.0.6", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.16", + "@smithy/util-defaults-mode-node": "^3.0.16", + "@smithy/util-endpoints": "^2.1.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/middleware-content-length": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.2.0.tgz", - "integrity": "sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.650.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.650.0.tgz", + "integrity": "sha512-x2M9buZxIsKuUbuDgkGHhAKYBpn0/rYdKlwuFuOhXyyAcnhvPj0lgNF2KE4ld/GF1mKr7FF/uV3G9lM6PFaYmA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", + "@aws-sdk/credential-provider-env": "3.649.0", + "@aws-sdk/credential-provider-http": "3.649.0", + "@aws-sdk/credential-provider-process": "3.649.0", + "@aws-sdk/credential-provider-sso": "3.650.0", + "@aws-sdk/credential-provider-web-identity": "3.649.0", + "@aws-sdk/types": "3.649.0", + "@smithy/credential-provider-imds": "^3.2.1", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.650.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/middleware-endpoint": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.649.0.tgz", + "integrity": "sha512-XVk3WsDa0g3kQFPmnCH/LaCtGY/0R2NDv7gscYZSXiBZcG/fixasglTprgWSp8zcA0t7tEIGu9suyjz8ZwhymQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", - "@smithy/url-parser": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", + "@aws-sdk/types": "3.649.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.649.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/middleware-retry": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", - "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/service-error-classification": "^2.1.5", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-retry": "^2.2.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14.0.0" + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.649.0.tgz", + "integrity": "sha512-IY43r256LhKAvdEVQO/FPdUyVpcZS5EVxh/WHVdNzuN1bNLoUK2rIzuZqVA0EGguvCxoXVmQv9m50GvG7cGktg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/middleware-serde": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.649.0.tgz", + "integrity": "sha512-x5DiLpZDG/AJmCIBnE3Xhpwy35QIo3WqNiOpw6ExVs1NydbM/e90zFPSfhME0FM66D/WorigvluBxxwjxDm/GA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/middleware-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", + "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", + "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", + "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", + "node_modules/@aws-sdk/lib-storage": { + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.637.0.tgz", + "integrity": "sha512-HiNGOP4a1QrCWwO1joKw4mCp19nLXoF9K52PislBaYDI35IlHC3DP6MeOg5zmElwtL1GtEHFBy5olfPWPsLyLg==", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/abort-controller": "^3.1.1", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/smithy-client": "^3.2.0", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.637.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.620.0.tgz", + "integrity": "sha512-eGLL0W6L3HDb3OACyetZYOWpHJ+gLo0TehQKeQyy2G8vTYXqNTeqYhuI6up9HVjBzU9eQiULVQETmgQs7TFaRg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-arn-parser": "3.568.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/querystring-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.620.0.tgz", + "integrity": "sha512-QXeRFMLfyQ31nAHLbiTLtk0oHzG9QLMaof5jIfqcUwnOkO8YnQdeqzakrg1Alpy/VQ7aqzIi8qypkBe2KXZz0A==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.620.0.tgz", + "integrity": "sha512-ftz+NW7qka2sVuwnnO1IzBku5ccP+s5qZGeRTPgrKB7OzRW85gthvIo1vQR2w+OwHFk7WJbbhhWwbCbktnP4UA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-sdk/types": "3.609.0", + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/smithy-client": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^2.5.1", - "@smithy/middleware-stack": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/types": "^2.12.0", - "@smithy/util-stream": "^2.2.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/url-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^2.2.0", - "@smithy/types": "^2.12.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-base64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-body-length-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.2.0.tgz", - "integrity": "sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==", + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.649.0.tgz", + "integrity": "sha512-PjAe2FocbicHVgNNwdSZ05upxIO7AgTPFtQLpnIAmoyzMcgv/zNB5fBn3uAnQSAeEPPCD+4SYVEUD1hw1ZBvEg==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-body-length-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.3.0.tgz", - "integrity": "sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==", + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.609.0.tgz", + "integrity": "sha512-xzsdoTkszGVqGVPjUmgoP7TORiByLueMHieI1fhQL888WPdqctwAx3ES6d/bA9Q/i8jnc6hs+Fjhy8UvBTkE9A==", + "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", + "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.2.1.tgz", - "integrity": "sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==", + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.649.0.tgz", + "integrity": "sha512-qdqRx6q7lYC6KL/NT9x3ShTL0TBuxdkCczGzHzY3AnOoYUjnCDH7Vlq867O6MAvb4EnGNECFzIgtkZkQ4FhY5w==", + "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", - "bowser": "^2.11.0", + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-defaults-mode-node": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.3.1.tgz", - "integrity": "sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==", - "dependencies": { - "@smithy/config-resolver": "^2.2.0", - "@smithy/credential-provider-imds": "^2.3.0", - "@smithy/node-config-provider": "^2.3.0", - "@smithy/property-provider": "^2.2.0", - "@smithy/smithy-client": "^2.5.1", - "@smithy/types": "^2.12.0", + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.649.0.tgz", + "integrity": "sha512-IPnO4wlmaLRf6IYmJW2i8gJ2+UPXX0hDRv1it7Qf8DpBW+lGyF2rnoN7NrFX0WIxdGOlJF1RcOr/HjXb2QeXfQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.649.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-endpoints": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.635.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.635.0.tgz", + "integrity": "sha512-RLdYJPEV4JL/7NBoFUs7VlP90X++5FlJdxHz0DzCjmiD3qCviKy+Cym3qg1gBgHwucs5XisuClxDrGokhAdTQw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", + "@aws-sdk/core": "3.635.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-arn-parser": "3.568.0", + "@smithy/core": "^2.4.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-stream": "^3.1.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/core": { + "version": "3.635.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.635.0.tgz", + "integrity": "sha512-i1x/E/sgA+liUE1XJ7rj1dhyXpAKO1UKFUcTTHXok2ARjWTvszHnSXMOsB77aPbmn0fUp1JTx2kHUAZ1LVt5Bg==", + "license": "Apache-2.0", "dependencies": { + "@smithy/core": "^2.4.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^2.5.0", - "@smithy/node-http-handler": "^2.5.0", - "@smithy/types": "^2.12.0", - "@smithy/util-base64": "^2.3.0", - "@smithy/util-buffer-from": "^2.2.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/types": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.485.0.tgz", - "integrity": "sha512-+QW32YQdvZRDOwrAQPo/qCyXoSjgXB6RwJwCwkd8ebJXRXw6tmGKIHaZqYHt/LtBymvnaBgBBADNa4+qFvlOFw==", + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.609.0.tgz", + "integrity": "sha512-GZSD1s7+JswWOTamVap79QiDaIV7byJFssBW68GYjyRS5EBjNfwA/8s+6uE6g39R3ojyTbYOmvcANoZEhSULXg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/types/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz", - "integrity": "sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==", + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.649.0.tgz", + "integrity": "sha512-q6sO10dnCXoxe9thobMJxekhJumzd1j6dxcE1+qJdYKHJr6yYgWbogJqrLCpWd30w0lEvnuAHK8lN2kWLdJxJw==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.649.0", + "@aws-sdk/util-endpoints": "3.649.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.485.0.tgz", - "integrity": "sha512-dTd642F7nJisApF8YjniqQ6U59CP/DCtar11fXf1nG9YNBCBsNNVw5ZfZb5nSNzaIdy27mQioWTCV18JEj1mxg==", + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.649.0.tgz", + "integrity": "sha512-xURBvdQXvRvca5Du8IlC5FyCj3pkw8Z75+373J3Wb+vyg8GjD14HfKk1Je1HCCQDyIE9VB/scYDcm9ri0ppePw==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/util-endpoints": "^1.0.8", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.649.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.4", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/node-config-provider": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.3.0.tgz", - "integrity": "sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==", + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.635.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.635.0.tgz", + "integrity": "sha512-J6QY4/invOkpogCHjSaDON1hF03viPpOnsrzVuCvJMmclS/iG62R4EY0wq1alYll0YmSdmKlpJwHMWwGtqK63Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^2.2.0", - "@smithy/shared-ini-file-loader": "^2.4.0", - "@smithy/types": "^2.12.0", + "@aws-sdk/middleware-sdk-s3": "3.635.0", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", + "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/shared-ini-file-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.4.0.tgz", - "integrity": "sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==", + "node_modules/@aws-sdk/types": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.649.0.tgz", + "integrity": "sha512-PuPw8RysbhJNlaD2d/PzOTf8sbf4Dsn2b7hwyGh7YVG3S75yTpxSAZxrnhKsz9fStgqFmnw/jUfV/G+uQAeTVw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.568.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz", + "integrity": "sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/util-endpoints": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.649.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.649.0.tgz", + "integrity": "sha512-bZI1Wc3R/KibdDVWFxX/N4AoJFG4VJ92Dp4WYmOrVD6VPkb8jPz7ZeiYc7YwPl8NoDjYyPneBV0lEoK/V8OKAA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^2.3.0", - "@smithy/types": "^2.12.0", + "@aws-sdk/types": "3.649.0", + "@smithy/types": "^3.4.0", + "@smithy/util-endpoints": "^2.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 14.0.0" + "node": ">=16.0.0" } }, "node_modules/@aws-sdk/util-locate-window": { @@ -6700,14 +3794,6 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dependencies": { - "tslib": "^2.3.1" - } - }, "node_modules/@aws-sdk/xml-builder": { "version": "3.609.0", "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.609.0.tgz", @@ -9595,11 +6681,12 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.2.tgz", + "integrity": "sha512-b5g+PNujlfqIib9BjkNB108NyO5aZM/RXjfOCXRCqXQ1oPnIkfvdORrztbGgCZdPe/BN/MKDlrGA7PafKPM2jw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -9626,13 +6713,15 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "3.0.5", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.6.tgz", + "integrity": "sha512-j7HuVNoRd8EhcFp0MzcUb4fG40C7BcyshH+fAd3Jhd8bINNFvEQYBrZoS/SK6Pun9WPlfoI8uuU2SMz8DsEGlA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", + "@smithy/util-middleware": "^3.0.4", "tslib": "^2.6.2" }, "engines": { @@ -9640,17 +6729,19 @@ } }, "node_modules/@smithy/core": { - "version": "2.4.0", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.1.tgz", + "integrity": "sha512-7cts7/Oni7aCHebHGiBeWoz5z+vmH+Vx2Z/UW3XtXMslcxI3PEwBZxNinepwZjixS3n12fPc247PHWmjU7ndsQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.15", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-retry": "^3.0.16", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/protocol-http": "^4.1.1", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", + "@smithy/util-middleware": "^3.0.4", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -9691,13 +6782,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.0", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.1.tgz", + "integrity": "sha512-4z/oTWpRF2TqQI3aCM89/PWu3kim58XU4kOCTtuTJnoaS4KT95cPWMxbQfTN2vzcOe96SOKO8QouQW/+ESB1fQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/property-provider": "^3.1.4", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", "tslib": "^2.6.2" }, "engines": { @@ -9770,13 +6863,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.5.tgz", + "integrity": "sha512-DjRtGmK8pKQMIo9+JlAKUt14Z448bg8nAN04yKIvlrrpmpRSG57s5d2Y83npks1r4gPtTRNbAFdQCoj9l3P2KQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/querystring-builder": "^3.0.4", + "@smithy/types": "^3.4.0", "@smithy/util-base64": "^3.0.0", "tslib": "^2.6.2" } @@ -9794,10 +6888,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "3.0.3", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.4.tgz", + "integrity": "sha512-6FgTVqEfCr9z/7+Em8BwSkJKA2y3krf1em134x3yr2NHWVCo2KYI8tcA53cjeO47y41jwF84ntsEE0Pe6pNKlg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -9891,10 +6987,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "3.0.3", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.4.tgz", + "integrity": "sha512-MJBUrojC4SEXi9aJcnNOE3oNAuYNphgCGFXscaCj2TA/59BTcXhzHACP8jnnEU3n4yir/NSLKzxqez0T4x4tjA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" } }, @@ -9959,11 +7057,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "3.0.5", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.6.tgz", + "integrity": "sha512-AFyHCfe8rumkJkz+hCOVJmBagNBj05KypyDwDElA4TgMSA4eYDZRjVePFZuyABrJZFDc7uVj3dpFIDCEhf59SA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -9971,16 +7071,17 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.1.tgz", + "integrity": "sha512-Irv+soW8NKluAtFSEsF8O3iGyLxa5oOevJb/e1yNacV9H7JP/yHyJuKST5YY2ORS1+W34VR8EuUrOF+K29Pl4g==", + "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", + "@smithy/middleware-serde": "^3.0.4", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", + "@smithy/url-parser": "^3.0.4", + "@smithy/util-middleware": "^3.0.4", "tslib": "^2.6.2" }, "engines": { @@ -9988,16 +7089,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.15", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.16.tgz", + "integrity": "sha512-08kI36p1yB4CWO3Qi+UQxjzobt8iQJpnruF0K5BkbZmA/N/sJ51A1JJGJ36GgcbFyPfWw2FU48S5ZoqXt0h0jw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/protocol-http": "^4.1.1", + "@smithy/service-error-classification": "^3.0.4", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", + "@smithy/util-middleware": "^3.0.4", + "@smithy/util-retry": "^3.0.4", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -10006,11 +7109,12 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.4.tgz", + "integrity": "sha512-1lPDB2O6IJ50Ucxgn7XrvZXbbuI48HmPCcMTuSoXT1lDzuTUfIuBjgAjpD8YLVMfnrjdepi/q45556LA51Pubw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10018,11 +7122,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.4.tgz", + "integrity": "sha512-sLMRjtMCqtVcrOqaOZ10SUnlFE25BSlmLsi4bRSGFD7dgR54eqBjfqkVkPBQyrKBortfGM0+2DJoUPcGECR+nQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10030,13 +7135,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.5.tgz", + "integrity": "sha512-dq/oR3/LxgCgizVk7in7FGTm0w9a3qM4mg3IIXLTCHeW3fV+ipssSvBZ2bvEx1+asfQJTyCnVLeYf7JKfd9v3Q==", + "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10044,14 +7150,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.2.0.tgz", + "integrity": "sha512-5TFqaABbiY7uJMKbqR4OARjwI/l4TRoysDJ75pLpVQyO3EcmeloKYwDGyCtgB9WJniFx3BMkmGCB9+j+QiB+Ww==", + "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", + "@smithy/abort-controller": "^3.1.2", + "@smithy/protocol-http": "^4.1.1", + "@smithy/querystring-builder": "^3.0.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10059,11 +7166,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.4.tgz", + "integrity": "sha512-BmhefQbfkSl9DeU0/e6k9N4sT5bya5etv2epvqLUz3eGyfRBhtQq60nDkc1WPp4c+KWrzK721cUc/3y0f2psPQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10071,11 +7179,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.1.tgz", + "integrity": "sha512-Fm5+8LkeIus83Y8jTL1XHsBGP8sPvE1rEVyKf/87kbOPTbzEDMcgOlzcmYXat2h+nC3wwPtRy8hFqtJS71+Wow==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10083,11 +7192,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.4.tgz", + "integrity": "sha512-NEoPAsZPdpfVbF98qm8i5k1XMaRKeEnO47CaL5ja6Y1Z2DgJdwIJuJkTJypKm/IKfp8gc0uimIFLwhml8+/pAw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, @@ -10096,11 +7206,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.4.tgz", + "integrity": "sha512-7CHPXffFcakFzhO0OZs/rn6fXlTHrSDdLhIT6/JIk1u2bvwguTL3fMCc1+CfcbXA7TOhjWXu3TcB1EGMqJQwHg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10108,21 +7219,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "3.0.3", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.4.tgz", + "integrity": "sha512-KciDHHKFVTb9A1KlJHBt2F26PBaDtoE23uTZy5qRvPzHPqrooXFi6fmx98lJb3Jl38PuUTqIuCUmmY3pacuMBQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0" + "@smithy/types": "^3.4.0" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.5.tgz", + "integrity": "sha512-6jxsJ4NOmY5Du4FD0enYegNJl4zTSuKLiChIMqIkh+LapxiP7lmz5lYUNLE9/4cvA65mbBmtdzZ8yxmcqM5igg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10130,14 +7244,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "4.1.0", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.1.tgz", + "integrity": "sha512-SH9J9be81TMBNGCmjhrgMWu4YSpQ3uP1L06u/K9SDrE2YibUix1qxedPCxEQu02At0P0SrYDjvz+y91vLG0KRQ==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", + "@smithy/util-middleware": "^3.0.4", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -10179,15 +7295,16 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.2.0.tgz", - "integrity": "sha512-pDbtxs8WOhJLJSeaF/eAbPgXg4VVYFlRcL/zoNYA5WbG3wBL06CHtBSg53ppkttDpAJ/hdiede+xApip1CwSLw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.3.0.tgz", + "integrity": "sha512-H32nVo8tIX82kB0xI2LBrIcj8jx/3/ITotNLbeG1UL0b3b440YPR/hUvqjFJiaB24pQrMjRbU8CugqH5sV0hkw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", + "@smithy/middleware-endpoint": "^3.1.1", + "@smithy/middleware-stack": "^3.0.4", + "@smithy/protocol-http": "^4.1.1", + "@smithy/types": "^3.4.0", + "@smithy/util-stream": "^3.1.4", "tslib": "^2.6.2" }, "engines": { @@ -10195,9 +7312,10 @@ } }, "node_modules/@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.4.0.tgz", + "integrity": "sha512-0shOWSg/pnFXPcsSU8ZbaJ4JBHZJPPzLCJxafJvbMVFo9l1w81CqpgUqjlKGNHVrVB7fhIs+WS82JDTyzaLyLA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -10206,12 +7324,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.4.tgz", + "integrity": "sha512-XdXfObA8WrloavJYtDuzoDhJAYc5rOt+FirFmKBRKaihu7QtU/METAxJgSo7uMK6hUkx0vFnqxV75urtRaLkLg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", + "@smithy/querystring-parser": "^3.0.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" } }, @@ -10303,12 +7422,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.15", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.16.tgz", + "integrity": "sha512-Os8ddfNBe7hmc5UMWZxygIHCyAqY0aWR8Wnp/aKbti3f8Df/r0J9ttMZIxeMjsFgtVjEryB0q7SGcwBsHk8WEw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", + "@smithy/property-provider": "^3.1.4", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -10317,15 +7438,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.15", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.16.tgz", + "integrity": "sha512-rNhFIYRtrOrrhRlj6RL8jWA6/dcwrbGYAmy8+OAHjjzQ6zdzUBB1P+3IuJAgwWN6Y5GxI+mVXlM/pOjaoIgHow==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^3.0.5", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.2.0", - "@smithy/types": "^3.3.0", + "@smithy/config-resolver": "^3.0.6", + "@smithy/credential-provider-imds": "^3.2.1", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/property-provider": "^3.1.4", + "@smithy/smithy-client": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10333,11 +7456,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "2.0.5", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.0.tgz", + "integrity": "sha512-ilS7/0jcbS2ELdg0fM/4GVvOiuk8/U3bIFXUW25xE1Vh1Ol4DP6vVHQKqM40rCMizCLmJ9UxK+NeJrKlhI3HVA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", + "@smithy/node-config-provider": "^3.1.5", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10356,11 +7481,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.4.tgz", + "integrity": "sha512-uSXHTBhstb1c4nHdmQEdkNMv9LiRNaJ/lWV2U/GO+5F236YFpdPw+hyWI9Zc0Rp9XKzwD9kVZvhZmEgp0UCVnA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10368,11 +7494,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "3.0.3", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.4.tgz", + "integrity": "sha512-JJr6g0tO1qO2tCQyK+n3J18r34ZpvatlFN5ULcLranFIBZPxqoivb77EPyNTVwTGMEvvq2qMnyjm4jMIxjdLFg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", + "@smithy/service-error-classification": "^3.0.4", + "@smithy/types": "^3.4.0", "tslib": "^2.6.2" }, "engines": { @@ -10380,13 +7508,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.4.tgz", + "integrity": "sha512-txU3EIDLhrBZdGfon6E9V6sZz/irYnKFMblz4TLVjyq8hObNHNS2n9a2t7GIrl7d85zgEPhwLE0gANpZsvpsKg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", + "@smithy/fetch-http-handler": "^3.2.5", + "@smithy/node-http-handler": "^3.2.0", + "@smithy/types": "^3.4.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", @@ -10552,6 +7681,13 @@ "version": "0.5.8", "license": "MIT" }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cookies": { "version": "0.7.10", "license": "MIT", @@ -10687,6 +7823,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "license": "MIT" @@ -10741,6 +7884,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.2.tgz", + "integrity": "sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "license": "MIT" @@ -21628,7 +18795,9 @@ } }, "node_modules/path-to-regexp": { - "version": "6.2.1", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "license": "MIT" }, "node_modules/path-type": { diff --git a/package.json b/package.json index c96d436b3d2..da4891e8491 100644 --- a/package.json +++ b/package.json @@ -131,6 +131,7 @@ "@types/koa-bodyparser": "^4.3.10", "@types/lodash": "^4.14.197", "@types/node": "^20.2.5", + "@types/supertest": "^6.0.2", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.59.2", "axios-mock-adapter": "^1.22.0", diff --git a/src/types/index.ts b/src/types/index.ts index 7aa6bd8ebfc..45ec7445c3f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -135,6 +135,14 @@ type Destination = { IsConnectionEnabled?: boolean; }; +type Connection = { + sourceId: string; + destinationId: string; + enabled: boolean; + config: Record; + processorEnabled?: boolean; +}; + type UserTransformationLibrary = { VersionID: string; }; @@ -151,6 +159,7 @@ type ProcessorTransformationRequest = { message: object; metadata: Metadata; destination: Destination; + connection?: Connection; libraries?: UserTransformationLibrary[]; credentials?: Credential[]; }; @@ -160,6 +169,7 @@ type RouterTransformationRequestData = { message: object; metadata: Metadata; destination: Destination; + connection?: Connection; }; type RouterTransformationRequest = { @@ -350,6 +360,7 @@ export { DeliveryJobState, DeliveryV0Response, DeliveryV1Response, + Connection, Destination, ErrorDetailer, MessageIdMetadataMap, diff --git a/src/v0/destinations/fb_custom_audience/config.js b/src/v0/destinations/fb_custom_audience/config.js index 39ca2d04c48..5a3f0742e12 100644 --- a/src/v0/destinations/fb_custom_audience/config.js +++ b/src/v0/destinations/fb_custom_audience/config.js @@ -89,10 +89,11 @@ const subTypeFields = [ 'CONTACT_IMPORTER', 'DATA_FILE', ]; -// as per real time experimentation maximum 500 users can be added at a time -// const MAX_USER_COUNT = 500; (using from destination definition) + const USER_ADD = 'add'; const USER_DELETE = 'remove'; +// https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences/ +const MAX_USER_COUNT = 10000; /* No official Documentation is available for this but using trial and error method we found that 65000 bytes is the maximum payload allowed size but we are 60000 just to be sure batching is done properly */ @@ -102,6 +103,7 @@ module.exports = { schemaFields, USER_ADD, USER_DELETE, + MAX_USER_COUNT, typeFields, subTypeFields, maxPayloadSize, diff --git a/src/v0/destinations/fb_custom_audience/recordTransform.js b/src/v0/destinations/fb_custom_audience/recordTransform.js index 62d4bd568bd..9f48a37fca6 100644 --- a/src/v0/destinations/fb_custom_audience/recordTransform.js +++ b/src/v0/destinations/fb_custom_audience/recordTransform.js @@ -1,9 +1,7 @@ /* eslint-disable no-const-assign */ const lodash = require('lodash'); -const get = require('get-value'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); -const { schemaFields } = require('./config'); -const { MappedToDestinationKey } = require('../../../constants'); +const { schemaFields, MAX_USER_COUNT } = require('./config'); const stats = require('../../../util/stats'); const { getDestinationExternalIDInfoForRetl, @@ -11,6 +9,8 @@ const { checkSubsetOfArray, returnArrayOfSubarrays, getSuccessRespEvents, + isEventSentByVDMV2Flow, + isEventSentByVDMV1Flow, } = require('../../util'); const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { @@ -20,6 +20,7 @@ const { batchingWithPayloadSize, responseBuilderSimple, getDataSource, + generateAppSecretProof, } = require('./util'); const processRecordEventArray = ( @@ -31,7 +32,7 @@ const processRecordEventArray = ( prepareParams, destination, operation, - operationAudienceId, + audienceId, ) => { const toSendEvents = []; const metadata = []; @@ -88,7 +89,7 @@ const processRecordEventArray = ( operationCategory: operation, }; - const builtResponse = responseBuilderSimple(wrappedResponse, operationAudienceId); + const builtResponse = responseBuilderSimple(wrappedResponse, audienceId); toSendEvents.push(builtResponse); }); @@ -99,49 +100,26 @@ const processRecordEventArray = ( return response; }; -async function processRecordInputs(groupedRecordInputs) { - const { destination } = groupedRecordInputs[0]; - const { message } = groupedRecordInputs[0]; - const { - isHashRequired, - accessToken, - disableFormat, - type, - subType, - isRaw, - maxUserCount, - audienceId, - } = destination.Config; +function preparePayload(events, config) { + const { audienceId, userSchema, isRaw, type, subType, isHashRequired, disableFormat } = config; + const { destination } = events[0]; + const { accessToken, appSecret } = destination.Config; const prepareParams = { access_token: accessToken, }; - // maxUserCount validation - const maxUserCountNumber = parseInt(maxUserCount, 10); - if (Number.isNaN(maxUserCountNumber)) { - throw new ConfigurationError('Batch size must be an Integer.'); + if (isDefinedAndNotNullAndNotEmpty(appSecret)) { + const dateNow = Date.now(); + prepareParams.appsecret_time = Math.floor(dateNow / 1000); // Get current Unix time in seconds + prepareParams.appsecret_proof = generateAppSecretProof(accessToken, appSecret, dateNow); } - // audience id validation - let operationAudienceId = audienceId; - const mappedToDestination = get(message, MappedToDestinationKey); - if (mappedToDestination) { - const { objectType } = getDestinationExternalIDInfoForRetl(message, 'FB_CUSTOM_AUDIENCE'); - operationAudienceId = objectType; - } - if (!isDefinedAndNotNullAndNotEmpty(operationAudienceId)) { - throw new ConfigurationError('Audience ID is a mandatory field'); - } + const cleanUserSchema = userSchema.map((field) => field.trim()); - // user schema validation - let { userSchema } = destination.Config; - if (mappedToDestination) { - userSchema = getSchemaForEventMappedToDest(message); - } - if (!Array.isArray(userSchema)) { - userSchema = [userSchema]; + if (!isDefinedAndNotNullAndNotEmpty(audienceId)) { + throw new ConfigurationError('Audience ID is a mandatory field'); } - if (!checkSubsetOfArray(schemaFields, userSchema)) { + if (!checkSubsetOfArray(schemaFields, cleanUserSchema)) { throw new ConfigurationError('One or more of the schema fields are not supported'); } @@ -156,7 +134,7 @@ async function processRecordInputs(groupedRecordInputs) { paramsPayload.data_source = dataSource; } - const groupedRecordsByAction = lodash.groupBy(groupedRecordInputs, (record) => + const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), ); @@ -167,55 +145,55 @@ async function processRecordInputs(groupedRecordInputs) { if (groupedRecordsByAction.delete) { const deleteRecordChunksArray = returnArrayOfSubarrays( groupedRecordsByAction.delete, - maxUserCountNumber, + MAX_USER_COUNT, ); deleteResponse = processRecordEventArray( deleteRecordChunksArray, - userSchema, + cleanUserSchema, isHashRequired, disableFormat, paramsPayload, prepareParams, destination, 'remove', - operationAudienceId, + audienceId, ); } if (groupedRecordsByAction.insert) { const insertRecordChunksArray = returnArrayOfSubarrays( groupedRecordsByAction.insert, - maxUserCountNumber, + MAX_USER_COUNT, ); insertResponse = processRecordEventArray( insertRecordChunksArray, - userSchema, + cleanUserSchema, isHashRequired, disableFormat, paramsPayload, prepareParams, destination, 'add', - operationAudienceId, + audienceId, ); } if (groupedRecordsByAction.update) { const updateRecordChunksArray = returnArrayOfSubarrays( groupedRecordsByAction.update, - maxUserCountNumber, + MAX_USER_COUNT, ); updateResponse = processRecordEventArray( updateRecordChunksArray, - userSchema, + cleanUserSchema, isHashRequired, disableFormat, paramsPayload, prepareParams, destination, 'add', - operationAudienceId, + audienceId, ); } @@ -225,6 +203,7 @@ async function processRecordInputs(groupedRecordInputs) { deleteResponse, insertResponse, updateResponse, + errorResponse, ); if (finalResponse.length === 0) { @@ -235,6 +214,67 @@ async function processRecordInputs(groupedRecordInputs) { return finalResponse; } +function processRecordInputsV1(groupedRecordInputs) { + const { destination } = groupedRecordInputs[0]; + const { message } = groupedRecordInputs[0]; + const { isHashRequired, disableFormat, type, subType, isRaw, audienceId, userSchema } = + destination.Config; + + let operationAudienceId = audienceId; + let updatedUserSchema = userSchema; + if (isEventSentByVDMV1Flow(groupedRecordInputs[0])) { + const { objectType } = getDestinationExternalIDInfoForRetl(message, 'FB_CUSTOM_AUDIENCE'); + operationAudienceId = objectType; + updatedUserSchema = getSchemaForEventMappedToDest(message); + } + + return preparePayload(groupedRecordInputs, { + audienceId: operationAudienceId, + userSchema: updatedUserSchema, + isRaw, + type, + subType, + isHashRequired, + disableFormat, + }); +} + +const processRecordInputsV2 = (groupedRecordInputs) => { + const { connection, message } = groupedRecordInputs[0]; + const { isHashRequired, disableFormat, type, subType, isRaw, audienceId } = + connection.config.destination; + // Ref: https://www.notion.so/rudderstacks/VDM-V2-Final-Config-and-Record-EventPayload-8cc80f3d88ad46c7bc43df4b87a0bbff + const identifiers = message?.identifiers; + let userSchema; + if (identifiers) { + userSchema = Object.keys(identifiers); + } + const events = groupedRecordInputs.map((record) => ({ + ...record, + message: { + ...record.message, + fields: record.message.identifiers, + }, + })); + return preparePayload(events, { + audienceId, + userSchema, + isRaw, + type, + subType, + isHashRequired, + disableFormat, + }); +}; + +function processRecordInputs(groupedRecordInputs) { + const event = groupedRecordInputs[0]; + if (isEventSentByVDMV2Flow(event)) { + return processRecordInputsV2(groupedRecordInputs); + } + return processRecordInputsV1(groupedRecordInputs); +} + module.exports = { processRecordInputs, }; diff --git a/src/v0/destinations/fb_custom_audience/transform.js b/src/v0/destinations/fb_custom_audience/transform.js index c5c340c043d..d7a7b3ef638 100644 --- a/src/v0/destinations/fb_custom_audience/transform.js +++ b/src/v0/destinations/fb_custom_audience/transform.js @@ -1,5 +1,4 @@ const lodash = require('lodash'); -const get = require('get-value'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { checkSubsetOfArray, @@ -7,19 +6,16 @@ const { returnArrayOfSubarrays, flattenMap, simpleProcessRouterDest, - getDestinationExternalIDInfoForRetl, } = require('../../util'); const { prepareDataField, - getSchemaForEventMappedToDest, batchingWithPayloadSize, generateAppSecretProof, responseBuilderSimple, getDataSource, } = require('./util'); -const { schemaFields, USER_ADD, USER_DELETE } = require('./config'); +const { schemaFields, USER_ADD, USER_DELETE, MAX_USER_COUNT } = require('./config'); -const { MappedToDestinationKey } = require('../../../constants'); const { processRecordInputs } = require('./recordTransform'); const logger = require('../../../logger'); @@ -71,14 +67,6 @@ const prepareResponse = ( ) => { const { accessToken, disableFormat, type, subType, isRaw, appSecret } = destination.Config; - const mappedToDestination = get(message, MappedToDestinationKey); - - // If mapped to destination, use the mapped fields instead of destination userschema - if (mappedToDestination) { - // eslint-disable-next-line no-param-reassign - userSchema = getSchemaForEventMappedToDest(message); - } - const prepareParams = {}; // creating the parameters field const paramsPayload = {}; @@ -158,31 +146,17 @@ const processEvent = (message, destination) => { const respList = []; let toSendEvents = []; let { userSchema } = destination.Config; - const { isHashRequired, audienceId, maxUserCount } = destination.Config; + const { isHashRequired, audienceId } = destination.Config; if (!message.type) { throw new InstrumentationError('Message Type is not present. Aborting message.'); } - const maxUserCountNumber = parseInt(maxUserCount, 10); - if (Number.isNaN(maxUserCountNumber)) { - throw new ConfigurationError('Batch size must be an Integer.'); - } if (message.type.toLowerCase() !== 'audiencelist') { throw new InstrumentationError(` ${message.type} call is not supported `); } - let operationAudienceId = audienceId; - const mappedToDestination = get(message, MappedToDestinationKey); - if (!operationAudienceId && mappedToDestination) { - const { objectType } = getDestinationExternalIDInfoForRetl(message, 'FB_CUSTOM_AUDIENCE'); - operationAudienceId = objectType; - } - if (!isDefinedAndNotNullAndNotEmpty(operationAudienceId)) { - throw new ConfigurationError('Audience ID is a mandatory field'); - } - // If mapped to destination, use the mapped fields instead of destination userschema - if (mappedToDestination) { - userSchema = getSchemaForEventMappedToDest(message); + if (!isDefinedAndNotNullAndNotEmpty(audienceId)) { + throw new ConfigurationError('Audience ID is a mandatory field'); } // When one single schema field is added in the webapp, it does not appear to be an array @@ -198,7 +172,7 @@ const processEvent = (message, destination) => { // when "remove" is present in the payload if (isDefinedAndNotNullAndNotEmpty(listData[USER_DELETE])) { - const audienceChunksArray = returnArrayOfSubarrays(listData[USER_DELETE], maxUserCountNumber); + const audienceChunksArray = returnArrayOfSubarrays(listData[USER_DELETE], MAX_USER_COUNT); toSendEvents = prepareToSendEvents( message, destination, @@ -211,7 +185,7 @@ const processEvent = (message, destination) => { // When "add" is present in the payload if (isDefinedAndNotNullAndNotEmpty(listData[USER_ADD])) { - const audienceChunksArray = returnArrayOfSubarrays(listData[USER_ADD], maxUserCountNumber); + const audienceChunksArray = returnArrayOfSubarrays(listData[USER_ADD], MAX_USER_COUNT); toSendEvents.push( ...prepareToSendEvents( message, @@ -225,7 +199,7 @@ const processEvent = (message, destination) => { } toSendEvents.forEach((sendEvent) => { - respList.push(responseBuilderSimple(sendEvent, operationAudienceId)); + respList.push(responseBuilderSimple(sendEvent, audienceId)); }); // When userListAdd or userListDelete is absent or both passed as empty arrays if (respList.length === 0) { @@ -252,7 +226,7 @@ const processRouterDest = async (inputs, reqMetadata) => { } if (groupedInputs.record) { - transformedRecordEvent = await processRecordInputs(groupedInputs.record, reqMetadata); + transformedRecordEvent = processRecordInputs(groupedInputs.record); } if (groupedInputs.audiencelist) { diff --git a/src/v0/destinations/fb_custom_audience/util.js b/src/v0/destinations/fb_custom_audience/util.js index 401b6018697..8ba1f68c934 100644 --- a/src/v0/destinations/fb_custom_audience/util.js +++ b/src/v0/destinations/fb_custom_audience/util.js @@ -1,7 +1,6 @@ const lodash = require('lodash'); const sha256 = require('sha256'); const crypto = require('crypto'); -const get = require('get-value'); const jsonSize = require('json-size'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { TransformationError } = require('@rudderstack/integrations-lib'); @@ -14,7 +13,7 @@ const { const stats = require('../../../util/stats'); const { isDefinedAndNotNull } = require('../../util'); -const { maxPayloadSize } = require('./config'); +const config = require('./config'); /** * Example payload ={ @@ -35,9 +34,9 @@ const { maxPayloadSize } = require('./config'); } */ const batchingWithPayloadSize = (payload) => { const payloadSize = jsonSize(payload); - if (payloadSize > maxPayloadSize) { + if (payloadSize > config.maxPayloadSize) { const revisedPayloadArray = []; - const noOfBatches = Math.ceil(payloadSize / maxPayloadSize); + const noOfBatches = Math.ceil(payloadSize / config.maxPayloadSize); const revisedRecordsPerPayload = Math.floor(payload.data.length / noOfBatches); const revisedDataArray = lodash.chunk(payload.data, revisedRecordsPerPayload); revisedDataArray.forEach((data) => { @@ -49,7 +48,7 @@ const batchingWithPayloadSize = (payload) => { }; const getSchemaForEventMappedToDest = (message) => { - const mappedSchema = get(message, 'context.destinationFields'); + const mappedSchema = message?.context?.destinationFields; if (!mappedSchema) { throw new InstrumentationError( 'context.destinationFields is required property for events mapped to destination ', diff --git a/src/v0/util/constant.js b/src/v0/util/constant.js index 9996f1ea7c6..8f5d6c97a13 100644 --- a/src/v0/util/constant.js +++ b/src/v0/util/constant.js @@ -13,6 +13,8 @@ const JSON_MIME_TYPE = 'application/json'; const FEATURE_FILTER_CODE = 'filter-code'; const FEATURE_GZIP_SUPPORT = 'gzip-support'; +const VDM_V2_SCHEMA_VERSION = '1.1'; + const HTTP_STATUS_CODES = { // 1xx Informational CONTINUE: 100, @@ -91,4 +93,5 @@ module.exports = { USER_LEAD_CACHE_TTL, FEATURE_FILTER_CODE, FEATURE_GZIP_SUPPORT, + VDM_V2_SCHEMA_VERSION, }; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index 6eb63125890..ca81262f88e 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -30,7 +30,7 @@ const logger = require('../../logger'); const stats = require('../../util/stats'); const { DestCanonicalNames, DestHandlerMap } = require('../../constants/destinationCanonicalNames'); const { client: errNotificationClient } = require('../../util/errorNotifier'); -const { HTTP_STATUS_CODES } = require('./constant'); +const { HTTP_STATUS_CODES, VDM_V2_SCHEMA_VERSION } = require('./constant'); const { REFRESH_TOKEN, AUTH_STATUS_INACTIVE, @@ -2322,6 +2322,10 @@ const getRelativePathFromURL = (inputUrl) => { return inputUrl; }; +const isEventSentByVDMV1Flow = (event) => event?.message?.context?.mappedToDestination; + +const isEventSentByVDMV2Flow = (event) => + event?.connection?.config?.destination?.schemaVersion === VDM_V2_SCHEMA_VERSION; // ======================================================================== // EXPORTS // ======================================================================== @@ -2390,6 +2394,8 @@ module.exports = { isDefinedAndNotNull, isDefinedAndNotNullAndNotEmpty, isEmpty, + isEventSentByVDMV1Flow, + isEventSentByVDMV2Flow, isNotEmpty, isNull, isEmptyObject, diff --git a/test/integrations/component.test.ts b/test/integrations/component.test.ts index e7645db64df..daed7c9e1f1 100644 --- a/test/integrations/component.test.ts +++ b/test/integrations/component.test.ts @@ -228,7 +228,7 @@ describe.each(allTestDataFilePaths)('%s Tests', (testDataPath) => { }); } describe(`${testData[0].name} ${testData[0].module}`, () => { - test.each(testData)('$feature -> $description', async (tcData) => { + test.each(testData)('$feature -> $description (index: $#)', async (tcData) => { tcData?.mockFns?.(mockAdapter); switch (tcData.module) { diff --git a/test/integrations/destinations/fb_custom_audience/mocks.ts b/test/integrations/destinations/fb_custom_audience/mocks.ts new file mode 100644 index 00000000000..6dd61a0e1b3 --- /dev/null +++ b/test/integrations/destinations/fb_custom_audience/mocks.ts @@ -0,0 +1,4 @@ +export const mockFns = (_) => { + // @ts-ignore + jest.useFakeTimers().setSystemTime(new Date('2023-10-15')); +}; diff --git a/test/integrations/destinations/fb_custom_audience/processor/data.ts b/test/integrations/destinations/fb_custom_audience/processor/data.ts index 75fa321aca6..44d4ecaa71e 100644 --- a/test/integrations/destinations/fb_custom_audience/processor/data.ts +++ b/test/integrations/destinations/fb_custom_audience/processor/data.ts @@ -1,9 +1,6 @@ -import { getEndPoint } from '../../../../../src/v0/destinations/fb_custom_audience/config'; - -export const mockFns = (_) => { - // @ts-ignore - jest.useFakeTimers().setSystemTime(new Date('2023-10-15')); -}; +import config from '../../../../../src/v0/destinations/fb_custom_audience/config'; +import { mockFns } from '../mocks'; +const getEndPoint = config.getEndPoint; export const data = [ { @@ -84,7 +81,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -197,7 +193,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -231,119 +226,6 @@ export const data = [ }, }, }, - { - name: 'fb_custom_audience', - description: 'Non-Numerical Batch Size Event', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - message: { - userId: 'user 1', - anonymousId: 'anon-id-new', - type: 'audiencelist', - event: 'event1', - properties: { - listData: { - add: [ - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'f', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - ], - remove: [ - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'f', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - ], - }, - }, - context: { - ip: '14.5.67.21', - library: { - name: 'http', - }, - }, - timestamp: '2020-02-02T00:23:09.544Z', - }, - destination: { - Config: { - accessToken: 'ABC', - userSchema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - isHashRequired: false, - disableFormat: false, - audienceId: 'aud1', - isRaw: true, - type: 'UNKNOWN', - subType: 'ANYTHING', - maxUserCount: 'abc50', - }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - libraries: [], - request: { - query: {}, - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - error: 'Batch size must be an Integer.', - statTags: { - destType: 'FB_CUSTOM_AUDIENCE', - errorCategory: 'dataValidation', - errorType: 'configuration', - feature: 'processor', - implementation: 'native', - module: 'destination', - }, - statusCode: 400, - }, - ], - }, - }, - }, { name: 'fb_custom_audience', description: 'Audience ID Empty Event', @@ -423,7 +305,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -536,7 +417,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -747,7 +627,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -946,7 +825,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -1107,7 +985,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -1341,7 +1218,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -1575,7 +1451,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -1786,7 +1661,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -1983,7 +1857,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -2125,7 +1998,6 @@ export const data = [ isRaw: true, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -2254,7 +2126,6 @@ export const data = [ isRaw: false, type: 'UNKNOWN', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -2401,52003 +2272,84 @@ export const data = [ ST: '123abc ', COUNTRY: 'IN', }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - { - EMAIL: 'shrouti@abc.com', - DOBM: '2', - DOBD: '13', - DOBY: '2013', - PHONE: '@09432457768', - GEN: 'female', - FI: 'Ms.', - MADID: 'ABC', - ZIP: 'ZIP ', - ST: '123abc ', - COUNTRY: 'IN', - }, - ], - }, - }, - context: { - ip: '14.5.67.21', - library: { - name: 'http', - }, - }, - timestamp: '2020-02-02T00:23:09.544Z', - }, - destination: { - Config: { - accessToken: 'ABC', - userSchema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - isHashRequired: false, - disableFormat: true, - audienceId: 'aud1', - isRaw: true, - type: 'NA', - subType: 'ANYTHING', - maxUserCount: '1000', - }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - libraries: [], - request: { - query: {}, - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: getEndPoint('aud1'), - headers: {}, - params: { - access_token: 'ABC', - payload: { - is_raw: true, - data_source: { - sub_type: 'ANYTHING', - }, - schema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - data: [ - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - ], - }, - }, - userId: '', - body: { - JSON: {}, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - statusCode: 200, - }, - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: getEndPoint('aud1'), - headers: {}, - params: { - access_token: 'ABC', - payload: { - is_raw: true, - data_source: { - sub_type: 'ANYTHING', - }, - schema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - data: [ - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - ], - }, - }, - userId: '', - body: { - JSON: {}, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - statusCode: 200, - }, - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: getEndPoint('aud1'), - headers: {}, - params: { - access_token: 'ABC', - payload: { - is_raw: true, - data_source: { - sub_type: 'ANYTHING', - }, - schema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - data: [ - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - ], - }, - }, - userId: '', - body: { - JSON: {}, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - statusCode: 200, - }, - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: getEndPoint('aud1'), - headers: {}, - params: { - access_token: 'ABC', - payload: { - is_raw: true, - data_source: { - sub_type: 'ANYTHING', - }, - schema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - data: [ - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], - [ - 'shrouti@abc.com', - '2', - '13', - '2013', - '@09432457768', - 'female', - 'Ms.', - 'ABC', - 'ZIP ', - '123abc ', - 'IN', - ], + ], + }, + }, + context: { + ip: '14.5.67.21', + library: { + name: 'http', + }, + }, + timestamp: '2020-02-02T00:23:09.544Z', + }, + destination: { + Config: { + accessToken: 'ABC', + userSchema: [ + 'EMAIL', + 'DOBM', + 'DOBD', + 'DOBY', + 'PHONE', + 'GEN', + 'FI', + 'MADID', + 'ZIP', + 'ST', + 'COUNTRY', + ], + isHashRequired: false, + disableFormat: true, + audienceId: 'aud1', + isRaw: true, + type: 'NA', + subType: 'ANYTHING', + }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + }, + libraries: [], + request: { + query: {}, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://graph.facebook.com/v20.0/aud1/users', + headers: {}, + params: { + access_token: 'ABC', + payload: { + is_raw: true, + data_source: { + sub_type: 'ANYTHING', + }, + schema: [ + 'EMAIL', + 'DOBM', + 'DOBD', + 'DOBY', + 'PHONE', + 'GEN', + 'FI', + 'MADID', + 'ZIP', + 'ST', + 'COUNTRY', + ], + data: [ [ 'shrouti@abc.com', '2', @@ -54424,6 +2376,48 @@ export const data = [ '123abc ', 'IN', ], + ], + }, + }, + body: { + JSON: {}, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://graph.facebook.com/v20.0/aud1/users', + headers: {}, + params: { + access_token: 'ABC', + payload: { + is_raw: true, + data_source: { + sub_type: 'ANYTHING', + }, + schema: [ + 'EMAIL', + 'DOBM', + 'DOBD', + 'DOBY', + 'PHONE', + 'GEN', + 'FI', + 'MADID', + 'ZIP', + 'ST', + 'COUNTRY', + ], + data: [ [ 'shrouti@abc.com', '2', @@ -54453,20 +2447,24 @@ export const data = [ ], }, }, - userId: '', body: { JSON: {}, - XML: {}, JSON_ARRAY: {}, + XML: {}, FORM: {}, }, files: {}, + userId: '', }, statusCode: 200, }, ], }, }, + mockFns: () => { + jest.useFakeTimers().setSystemTime(new Date('2023-10-15')); + jest.replaceProperty(config, 'maxPayloadSize', 400 as typeof config.maxPayloadSize); + }, }, { name: 'fb_custom_audience', @@ -54534,7 +2532,6 @@ export const data = [ isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -54613,4 +2610,4 @@ export const data = [ }, }, }, -].map((d) => ({ ...d, mockFns })); +].map((d) => ({ ...d, ...{ mockFns: d.mockFns || mockFns } })); diff --git a/test/integrations/destinations/fb_custom_audience/router/audienceList.ts b/test/integrations/destinations/fb_custom_audience/router/audienceList.ts deleted file mode 100644 index c386fbf7826..00000000000 --- a/test/integrations/destinations/fb_custom_audience/router/audienceList.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Destination, RouterTransformationRequest } from '../../../../../src/types'; -import { generateMetadata } from '../../../testUtils'; - -const destination: Destination = { - Config: { - accessToken: 'ABC', - disableFormat: false, - isHashRequired: true, - isRaw: false, - maxUserCount: '50', - oneTrustCookieCategories: [], - skipVerify: false, - subType: 'NA', - type: 'NA', - userSchema: ['EMAIL'], - }, - ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', - Name: 'FB_CUSTOM_AUDIENCE', - Enabled: true, - WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', - DestinationDefinition: { - ID: '1aIXqM806xAVm92nx07YwKbRrO9', - Name: 'FB_CUSTOM_AUDIENCE', - DisplayName: 'FB_CUSTOM_AUDIENCE', - Config: {}, - }, - Transformations: [], - IsConnectionEnabled: true, - IsProcessorEnabled: true, -}; - -export const rETLAudienceRouterRequest: RouterTransformationRequest = { - input: [ - { - message: { - sentAt: '2023-03-30 06:42:55.991938402 +0000 UTC', - userId: '2MUWghI7u85n91dd1qzGyswpZan-2MUWqbQqvctyfMGqU9QCNadpKNy', - channel: 'sources', - messageId: '4d906837-031d-4d34-b97a-62fdf51b4d3a', - event: 'Add_Audience', - context: { - destinationFields: 'EMAIL, FN', - externalId: [{ type: 'FB_CUSTOM_AUDIENCE-23848494844100489', identifierType: 'EMAIL' }], - mappedToDestination: 'true', - sources: { - job_run_id: 'cgiiurt8um7k7n5dq480', - task_run_id: 'cgiiurt8um7k7n5dq48g', - job_id: '2MUWghI7u85n91dd1qzGyswpZan', - version: '895/merge', - }, - }, - recordId: '725ad989-6750-4839-b46b-0ddb3b8e5aa2/1/10', - rudderId: '85c49666-c628-4835-937b-8f1d9ee7a724', - properties: { - listData: { - add: [ - { EMAIL: 'dede@gmail.com', FN: 'vishwa' }, - { EMAIL: 'fchsjjn@gmail.com', FN: 'hskks' }, - { EMAIL: 'fghjnbjk@gmail.com', FN: 'ghfry' }, - { EMAIL: 'gvhjkk@gmail.com', FN: 'hbcwqe' }, - { EMAIL: 'qsdwert@egf.com', FN: 'dsfds' }, - { EMAIL: 'ascscxsaca@com', FN: 'scadscdvcda' }, - { EMAIL: 'abc@gmail.com', FN: 'subscribed' }, - { EMAIL: 'ddwnkl@gmail.com', FN: 'subscribed' }, - { EMAIL: 'subscribed@eewrfrd.com', FN: 'pending' }, - { EMAIL: 'acsdvdf@ddfvf.com', FN: 'pending' }, - ], - }, - }, - type: 'audienceList', - anonymousId: '63228b51-394e-4ca2-97a0-427f6187480b', - }, - destination: destination, - metadata: generateMetadata(3), - }, - { - message: { - sentAt: '2023-03-30 06:42:55.991938402 +0000 UTC', - userId: '2MUWghI7u85n91dd1qzGyswpZan-2MUWqbQqvctyfMGqU9QCNadpKNy', - channel: 'sources', - messageId: '4d906837-031d-4d34-b97a-62fdf51b4d3a', - event: 'Add_Audience', - context: { - externalId: [{ type: 'FB_CUSTOM_AUDIENCE-23848494844100489', identifierType: 'EMAIL' }], - mappedToDestination: 'true', - sources: { - job_run_id: 'cgiiurt8um7k7n5dq480', - task_run_id: 'cgiiurt8um7k7n5dq48g', - job_id: '2MUWghI7u85n91dd1qzGyswpZan', - version: '895/merge', - }, - }, - recordId: '725ad989-6750-4839-b46b-0ddb3b8e5aa2/1/10', - rudderId: '85c49666-c628-4835-937b-8f1d9ee7a724', - properties: { - listData: { - add: [ - { EMAIL: 'dede@gmail.com', FN: 'vishwa' }, - { EMAIL: 'fchsjjn@gmail.com', FN: 'hskks' }, - { EMAIL: 'fghjnbjk@gmail.com', FN: 'ghfry' }, - { EMAIL: 'gvhjkk@gmail.com', FN: 'hbcwqe' }, - { EMAIL: 'qsdwert@egf.com', FN: 'dsfds' }, - { EMAIL: 'ascscxsaca@com', FN: 'scadscdvcda' }, - { EMAIL: 'abc@gmail.com', FN: 'subscribed' }, - { EMAIL: 'ddwnkl@gmail.com', FN: 'subscribed' }, - { EMAIL: 'subscribed@eewrfrd.com', FN: 'pending' }, - { EMAIL: 'acsdvdf@ddfvf.com', FN: 'pending' }, - ], - }, - }, - type: 'audienceList', - anonymousId: '63228b51-394e-4ca2-97a0-427f6187480b', - }, - destination: destination, - metadata: generateMetadata(4), - }, - ], - destType: 'fb_custom_audience', -}; - -module.exports = { - rETLAudienceRouterRequest, -}; diff --git a/test/integrations/destinations/fb_custom_audience/router/batchingRecord.ts b/test/integrations/destinations/fb_custom_audience/router/batchingRecord.ts deleted file mode 100644 index 0ceff5260ec..00000000000 --- a/test/integrations/destinations/fb_custom_audience/router/batchingRecord.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Destination, RouterTransformationRequest } from '../../../../../src/types'; -import { generateMetadata } from '../../../testUtils'; - -const destination: Destination = { - Config: { - accessToken: 'ABC', - disableFormat: false, - isHashRequired: true, - isRaw: false, - maxUserCount: '2', - oneTrustCookieCategories: [], - skipVerify: false, - subType: 'NA', - type: 'NA', - userSchema: ['EMAIL'], - }, - ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', - Name: 'FB_CUSTOM_AUDIENCE', - Enabled: true, - WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', - DestinationDefinition: { - ID: '1aIXqM806xAVm92nx07YwKbRrO9', - Name: 'FB_CUSTOM_AUDIENCE', - DisplayName: 'FB_CUSTOM_AUDIENCE', - Config: {}, - }, - Transformations: [], - IsConnectionEnabled: true, - IsProcessorEnabled: true, -}; - -export const rETLBatchingRouterRequest: RouterTransformationRequest = { - input: [ - { - destination: destination, - message: { - action: 'insert', - context: { - destinationFields: 'EMAIL, FI', - externalId: [ - { - type: 'FB_CUSTOM_AUDIENCE-23848494844100489', - identifierType: 'EMAIL', - }, - ], - mappedToDestination: 'true', - sources: { - job_run_id: 'cgiiurt8um7k7n5dq480', - task_run_id: 'cgiiurt8um7k7n5dq48g', - job_id: '2MUWghI7u85n91dd1qzGyswpZan', - version: '895/merge', - }, - }, - recordId: '2', - rudderId: '2', - fields: { - EMAIL: 'subscribed@eewrfrd.com', - FI: 'ghui', - }, - type: 'record', - }, - metadata: generateMetadata(1), - }, - { - destination: destination, - message: { - action: 'insert', - context: { - destinationFields: 'EMAIL, FI', - externalId: [ - { - type: 'FB_CUSTOM_AUDIENCE-23848494844100489', - identifierType: 'EMAIL', - }, - ], - mappedToDestination: 'true', - sources: { - job_run_id: 'cgiiurt8um7k7n5dq480', - task_run_id: 'cgiiurt8um7k7n5dq48g', - job_id: '2MUWghI7u85n91dd1qzGyswpZan', - version: '895/merge', - }, - }, - recordId: '2', - rudderId: '2', - fields: { - EMAIL: 'subscribed@eewrfrd.com', - FI: 'ghui', - }, - type: 'record', - }, - metadata: generateMetadata(2), - }, - { - destination: destination, - message: { - action: 'insert', - context: { - destinationFields: 'EMAIL, FI', - externalId: [ - { - type: 'FB_CUSTOM_AUDIENCE-23848494844100489', - identifierType: 'EMAIL', - }, - ], - mappedToDestination: 'true', - sources: { - job_run_id: 'cgiiurt8um7k7n5dq480', - task_run_id: 'cgiiurt8um7k7n5dq48g', - job_id: '2MUWghI7u85n91dd1qzGyswpZan', - version: '895/merge', - }, - }, - recordId: '2', - rudderId: '2', - fields: { - EMAIL: 'subscribed@eewrfrd.com', - FI: 'ghui', - }, - type: 'record', - }, - metadata: generateMetadata(3), - }, - ], - destType: 'fb_custom_audience', -}; - -module.exports = { - rETLBatchingRouterRequest, -}; diff --git a/test/integrations/destinations/fb_custom_audience/router/data.ts b/test/integrations/destinations/fb_custom_audience/router/data.ts index ab9bfee973a..cfc24968a89 100644 --- a/test/integrations/destinations/fb_custom_audience/router/data.ts +++ b/test/integrations/destinations/fb_custom_audience/router/data.ts @@ -1,12 +1,20 @@ -import { eventStreamRouterRequest } from './eventStream'; -import { rETLAudienceRouterRequest } from './audienceList'; -import { rETLBatchingRouterRequest } from './batchingRecord'; -import { rETLRecordRouterRequest } from './record'; +import { + eventStreamAudienceListRouterRequest, + eventStreamRecordV1RouterRequest, + esDestinationAudience, + esDestinationRecord, +} from './eventStream'; +import { + rETLRecordV1RouterRequest, + rETLRecordV2RouterRequest, + rETLRecordV2RouterInvalidRequest, +} from './rETL'; +import { mockFns } from '../mocks'; export const data = [ { name: 'fb_custom_audience', - description: 'eventStream tests', + description: 'eventStream using audienceList tests', scenario: 'business', successCriteria: 'event stream events should be batched correctly', feature: 'router', @@ -14,7 +22,7 @@ export const data = [ version: 'v0', input: { request: { - body: eventStreamRouterRequest, + body: eventStreamAudienceListRouterRequest, }, }, output: { @@ -143,43 +151,7 @@ export const data = [ ], batched: false, statusCode: 200, - destination: { - Config: { - accessToken: 'ABC', - userSchema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - isHashRequired: false, - disableFormat: false, - audienceId: 'aud1', - isRaw: true, - type: 'NA', - subType: 'ANYTHING', - maxUserCount: '50', - }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - ID: '123', - Name: 'fb_custom_audience', - DestinationDefinition: { - ID: '123', - Name: 'fb_custom_audience', - DisplayName: 'fb_custom_audience', - Config: {}, - }, - WorkspaceID: '123', - }, + destination: esDestinationAudience, }, { batchedRequest: [ @@ -302,43 +274,7 @@ export const data = [ ], batched: false, statusCode: 200, - destination: { - Config: { - accessToken: 'ABC', - userSchema: [ - 'EMAIL', - 'DOBM', - 'DOBD', - 'DOBY', - 'PHONE', - 'GEN', - 'FI', - 'MADID', - 'ZIP', - 'ST', - 'COUNTRY', - ], - isHashRequired: false, - disableFormat: false, - audienceId: 'aud1', - isRaw: true, - type: 'NA', - subType: 'ANYTHING', - maxUserCount: '50', - }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - ID: '123', - Name: 'fb_custom_audience', - DestinationDefinition: { - ID: '123', - Name: 'fb_custom_audience', - DisplayName: 'fb_custom_audience', - Config: {}, - }, - WorkspaceID: '123', - }, + destination: esDestinationAudience, }, ], }, @@ -347,15 +283,15 @@ export const data = [ }, { name: 'fb_custom_audience', - description: 'rETL tests', + description: 'event stream record V1 tests', scenario: 'business', - successCriteria: 'it should transform audience event correctly', + successCriteria: 'all record events should be transformed correctly based on their operation', feature: 'router', module: 'destination', version: 'v0', input: { request: { - body: rETLAudienceRouterRequest, + body: eventStreamRecordV1RouterRequest, }, }, output: { @@ -368,53 +304,135 @@ export const data = [ { version: '1', type: 'REST', - method: 'POST', + method: 'DELETE', endpoint: 'https://graph.facebook.com/v20.0/23848494844100489/users', headers: {}, params: { access_token: 'ABC', payload: { - schema: ['EMAIL', 'FN'], + schema: ['EMAIL', 'FI'], data: [ [ - '7625cab24612c37df6d2f724721bb38a25095d0295e29b807238ee188b8aca43', - 'e328a0d90d4b5132b2655cf7079b160040d2c1a83d70d4cad9cf1f69310635b3', - ], - [ - 'b2b4abadd72190af54305c0d3abf1977fec4935016bb13ff28040d5712318dfd', - 'f8147eb72c9bb356c362fdb0796b54971ebc983cb60b3cc3ff29582ce2052bad', - ], - [ - 'c4b007d1c3c9a5d31bd4082237a913e8e0db1767225c2a5ef33be2716df005fa', - 'd8bb13b95eaed7f9b6a8af276aa6122e8015e0c466c1a84e49ff7c69ad6ac911', - ], - [ - '94639be1bd9f17c05820164e9d71ef78558f117a9e8bfab43cf8015e08aa0b27', - 'b1661f97721dede0f876dcbf603289ee339f641b9c310deba53c76940f472698', - ], - [ - '39b456cfb4bb07f9e6bb18698aa173171ca49c731fccc4790e9ecea808d24ae6', - '6c882abd6d0aff713cdd6a4a31ee28c9140612fb2627a611f6f9f539bac44f81', + 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], [ - '769f73387add781a481ca08300008a08fb2f1816aaed196137efc2e05976d711', - '2222cb73346f7a01a1d4d3db28b58fd41045782bb66152b92aade379192544c5', + 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], + ], + }, + }, + body: { + JSON: {}, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 1, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 2, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + ], + batched: true, + statusCode: 200, + destination: esDestinationRecord, + }, + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://graph.facebook.com/v20.0/23848494844100489/users', + headers: {}, + params: { + access_token: 'ABC', + payload: { + schema: ['EMAIL', 'FI'], + data: [ [ - '48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08', - 'abc12f8d666517c35280bf220f5390b1f0ef4bdbbc794ac59c95bba0381bf91b', + 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], + ], + }, + }, + body: { + JSON: {}, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 3, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + ], + batched: true, + statusCode: 200, + destination: esDestinationRecord, + }, + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://graph.facebook.com/v20.0/23848494844100489/users', + headers: {}, + params: { + access_token: 'ABC', + payload: { + schema: ['EMAIL', 'FI'], + data: [ [ - 'da2d431121cd10578fd81f8f80344b06db59ea2d05a7b5d27536c8789ddae8f0', - 'abc12f8d666517c35280bf220f5390b1f0ef4bdbbc794ac59c95bba0381bf91b', + 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], [ 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', - '62a2fed3d6e08c44835fce71f02210b1ddabfb066e39edf1e6c261988f824dd3', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], [ - '0c1d1b0ba547a742013366d6fbc8f71dd77f566d94e41ed9f828a74b96928161', - '62a2fed3d6e08c44835fce71f02210b1ddabfb066e39edf1e6c261988f824dd3', + 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', + '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], ], }, @@ -433,7 +451,7 @@ export const data = [ attemptNum: 1, destinationId: 'default-destinationId', dontBatch: false, - jobId: 3, + jobId: 4, secret: { accessToken: 'default-accessToken', }, @@ -441,36 +459,34 @@ export const data = [ userId: 'default-userId', workspaceId: 'default-workspaceId', }, - ], - batched: false, - statusCode: 200, - destination: { - Config: { - accessToken: 'ABC', - disableFormat: false, - isHashRequired: true, - isRaw: false, - maxUserCount: '50', - oneTrustCookieCategories: [], - skipVerify: false, - subType: 'NA', - type: 'NA', - userSchema: ['EMAIL'], + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 5, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', }, - ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', - Name: 'FB_CUSTOM_AUDIENCE', - Enabled: true, - WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', - DestinationDefinition: { - ID: '1aIXqM806xAVm92nx07YwKbRrO9', - Name: 'FB_CUSTOM_AUDIENCE', - DisplayName: 'FB_CUSTOM_AUDIENCE', - Config: {}, + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 6, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', }, - Transformations: [], - IsConnectionEnabled: true, - IsProcessorEnabled: true, - }, + ], + batched: true, + statusCode: 200, + destination: esDestinationRecord, }, { metadata: [ @@ -478,7 +494,7 @@ export const data = [ attemptNum: 1, destinationId: 'default-destinationId', dontBatch: false, - jobId: 4, + jobId: 7, secret: { accessToken: 'default-accessToken', }, @@ -489,44 +505,16 @@ export const data = [ ], batched: false, statusCode: 400, - error: - 'context.destinationFields is required property for events mapped to destination ', + error: 'Invalid action type in record event', statTags: { errorCategory: 'dataValidation', + destinationId: 'default-destinationId', errorType: 'instrumentation', destType: 'FB_CUSTOM_AUDIENCE', - destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', module: 'destination', implementation: 'native', feature: 'router', - workspaceId: 'default-workspaceId', - }, - destination: { - Config: { - accessToken: 'ABC', - disableFormat: false, - isHashRequired: true, - isRaw: false, - maxUserCount: '50', - oneTrustCookieCategories: [], - skipVerify: false, - subType: 'NA', - type: 'NA', - userSchema: ['EMAIL'], - }, - ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', - Name: 'FB_CUSTOM_AUDIENCE', - Enabled: true, - WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', - DestinationDefinition: { - ID: '1aIXqM806xAVm92nx07YwKbRrO9', - Name: 'FB_CUSTOM_AUDIENCE', - DisplayName: 'FB_CUSTOM_AUDIENCE', - Config: {}, - }, - Transformations: [], - IsConnectionEnabled: true, - IsProcessorEnabled: true, }, }, ], @@ -536,7 +524,7 @@ export const data = [ }, { name: 'fb_custom_audience', - description: 'rETL record tests', + description: 'rETL record V1 tests', scenario: 'business', successCriteria: 'all record events should be transformed correctly based on their operation', feature: 'router', @@ -544,7 +532,7 @@ export const data = [ version: 'v0', input: { request: { - body: rETLRecordRouterRequest, + body: rETLRecordV1RouterRequest, }, }, output: { @@ -562,6 +550,9 @@ export const data = [ headers: {}, params: { access_token: 'ABC', + appsecret_proof: + 'd103874f3b5f01f57c4f84edfb96ac94055da8f83c2b45e6f26dafca9188ff4d', + appsecret_time: 1697328000, payload: { schema: ['EMAIL', 'FI'], data: [ @@ -616,10 +607,10 @@ export const data = [ destination: { Config: { accessToken: 'ABC', + appSecret: 'dummySecret', disableFormat: false, isHashRequired: true, isRaw: false, - maxUserCount: '3', oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', @@ -651,6 +642,9 @@ export const data = [ headers: {}, params: { access_token: 'ABC', + appsecret_proof: + 'd103874f3b5f01f57c4f84edfb96ac94055da8f83c2b45e6f26dafca9188ff4d', + appsecret_time: 1697328000, payload: { schema: ['EMAIL', 'FI'], data: [ @@ -689,10 +683,10 @@ export const data = [ destination: { Config: { accessToken: 'ABC', + appSecret: 'dummySecret', disableFormat: false, isHashRequired: true, isRaw: false, - maxUserCount: '3', oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', @@ -724,6 +718,9 @@ export const data = [ headers: {}, params: { access_token: 'ABC', + appsecret_proof: + 'd103874f3b5f01f57c4f84edfb96ac94055da8f83c2b45e6f26dafca9188ff4d', + appsecret_time: 1697328000, payload: { schema: ['EMAIL', 'FI'], data: [ @@ -794,10 +791,10 @@ export const data = [ destination: { Config: { accessToken: 'ABC', + appSecret: 'dummySecret', disableFormat: false, isHashRequired: true, isRaw: false, - maxUserCount: '3', oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', @@ -855,15 +852,15 @@ export const data = [ }, { name: 'fb_custom_audience', - description: 'rETL record batching tests', + description: 'rETL record V2 tests', scenario: 'Framework', - successCriteria: 'All the record events should be batched', + successCriteria: 'all record events should be transformed correctly based on their operation', feature: 'router', module: 'destination', version: 'v0', input: { request: { - body: rETLBatchingRouterRequest, + body: rETLRecordV2RouterRequest, }, }, output: { @@ -892,28 +889,6 @@ export const data = [ 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', ], - ], - }, - }, - body: { - JSON: {}, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://graph.facebook.com/v20.0/23848494844100489/users', - headers: {}, - params: { - access_token: 'ABC', - payload: { - schema: ['EMAIL', 'FI'], - data: [ [ 'b100c2ec0718fe6b4805b623aeec6710719d042ceea55f5c8135b010ec1c7b36', '1e14a2f476f7611a8b22bc85d14237fdc88aac828737e739416c32c5bce3bd16', @@ -976,12 +951,10 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - maxUserCount: '2', oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', - userSchema: ['EMAIL'], }, Name: 'FB_CUSTOM_AUDIENCE', Enabled: true, @@ -1003,4 +976,56 @@ export const data = [ }, }, }, -]; + { + name: 'fb_custom_audience', + description: 'rETL record V2 invalid connection tests', + scenario: 'Framework', + successCriteria: 'All the record V2 events should fail', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: rETLRecordV2RouterInvalidRequest, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + metadata: [ + { + jobId: 1, + attemptNum: 1, + userId: 'default-userId', + sourceId: 'default-sourceId', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + secret: { + accessToken: 'default-accessToken', + }, + dontBatch: false, + }, + ], + batched: false, + statusCode: 400, + error: 'Audience ID is a mandatory field', + statTags: { + errorCategory: 'dataValidation', + errorType: 'configuration', + destType: 'FB_CUSTOM_AUDIENCE', + module: 'destination', + implementation: 'native', + feature: 'router', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, + }, + ], + }, + }, + }, + }, +].map((d) => ({ ...d, mockFns })); diff --git a/test/integrations/destinations/fb_custom_audience/router/eventStream.ts b/test/integrations/destinations/fb_custom_audience/router/eventStream.ts index b4dcebf48bf..97cd472931a 100644 --- a/test/integrations/destinations/fb_custom_audience/router/eventStream.ts +++ b/test/integrations/destinations/fb_custom_audience/router/eventStream.ts @@ -1,7 +1,7 @@ import { Destination, RouterTransformationRequest } from '../../../../../src/types'; import { generateMetadata } from '../../../testUtils'; -const destination: Destination = { +export const esDestinationAudience: Destination = { Config: { accessToken: 'ABC', userSchema: [ @@ -23,7 +23,6 @@ const destination: Destination = { isRaw: true, type: 'NA', subType: 'ANYTHING', - maxUserCount: '50', }, Enabled: true, Transformations: [], @@ -39,7 +38,7 @@ const destination: Destination = { WorkspaceID: '123', }; -export const eventStreamRouterRequest: RouterTransformationRequest = { +export const eventStreamAudienceListRouterRequest: RouterTransformationRequest = { input: [ { message: { @@ -85,7 +84,7 @@ export const eventStreamRouterRequest: RouterTransformationRequest = { timestamp: '2020-02-02T00:23:09.544Z', }, metadata: generateMetadata(1), - destination: destination, + destination: esDestinationAudience, }, { message: { @@ -131,13 +130,137 @@ export const eventStreamRouterRequest: RouterTransformationRequest = { timestamp: '2020-02-02T00:23:09.544Z', }, metadata: generateMetadata(2), - destination: destination, + destination: esDestinationAudience, request: { query: {} }, }, ], destType: 'fb_custom_audience', }; -module.exports = { - eventStreamRouterRequest, +export const esDestinationRecord: Destination = { + Config: { + accessToken: 'ABC', + userSchema: ['EMAIL', 'FI'], + isHashRequired: true, + disableFormat: false, + audienceId: '23848494844100489', + isRaw: false, + type: 'NA', + subType: 'NA', + }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + ID: '123', + Name: 'fb_custom_audience', + DestinationDefinition: { + ID: '123', + Name: 'fb_custom_audience', + DisplayName: 'fb_custom_audience', + Config: {}, + }, + WorkspaceID: '123', +}; +export const eventStreamRecordV1RouterRequest: RouterTransformationRequest = { + input: [ + { + destination: esDestinationRecord, + message: { + action: 'insert', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(3), + }, + { + destination: esDestinationRecord, + message: { + action: 'update', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(4), + }, + { + destination: esDestinationRecord, + message: { + action: 'delete', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(1), + }, + { + destination: esDestinationRecord, + message: { + action: 'delete', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(2), + }, + { + destination: esDestinationRecord, + message: { + action: 'update', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(5), + }, + { + destination: esDestinationRecord, + message: { + action: 'update', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(6), + }, + { + destination: esDestinationRecord, + message: { + action: 'lol', + recordId: '2', + rudderId: '2', + fields: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(7), + }, + ], + destType: 'fb_custom_audience', }; diff --git a/test/integrations/destinations/fb_custom_audience/router/record.ts b/test/integrations/destinations/fb_custom_audience/router/rETL.ts similarity index 57% rename from test/integrations/destinations/fb_custom_audience/router/record.ts rename to test/integrations/destinations/fb_custom_audience/router/rETL.ts index 534c1c40c22..0ba7f8b5317 100644 --- a/test/integrations/destinations/fb_custom_audience/router/record.ts +++ b/test/integrations/destinations/fb_custom_audience/router/rETL.ts @@ -1,13 +1,172 @@ -import { Destination, RouterTransformationRequest } from '../../../../../src/types'; +import { Connection, Destination, RouterTransformationRequest } from '../../../../../src/types'; +import { VDM_V2_SCHEMA_VERSION } from '../../../../../src/v0/util/constant'; import { generateMetadata } from '../../../testUtils'; -const destination: Destination = { +const destinationV2: Destination = { Config: { accessToken: 'ABC', disableFormat: false, isHashRequired: true, isRaw: false, - maxUserCount: '3', + oneTrustCookieCategories: [], + skipVerify: false, + subType: 'NA', + type: 'NA', + }, + ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + Name: 'FB_CUSTOM_AUDIENCE', + Enabled: true, + WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', + DestinationDefinition: { + ID: '1aIXqM806xAVm92nx07YwKbRrO9', + Name: 'FB_CUSTOM_AUDIENCE', + DisplayName: 'FB_CUSTOM_AUDIENCE', + Config: {}, + }, + Transformations: [], + IsConnectionEnabled: true, + IsProcessorEnabled: true, +}; + +const connection: Connection = { + sourceId: '2MUWghI7u85n91dd1qzGyswpZan', + destinationId: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + enabled: true, + config: { + destination: { + schemaVersion: VDM_V2_SCHEMA_VERSION, + disableFormat: false, + isHashRequired: true, + isRaw: false, + subType: 'NA', + type: 'NA', + audienceId: '23848494844100489', + }, + }, +}; + +const missingAudienceIDConnection: Connection = { + sourceId: '2MUWghI7u85n91dd1qzGyswpZan', + destinationId: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + enabled: true, + config: { + destination: { + schemaVersion: VDM_V2_SCHEMA_VERSION, + }, + }, +}; + +export const rETLRecordV2RouterRequest: RouterTransformationRequest = { + input: [ + { + destination: destinationV2, + connection: connection, + message: { + action: 'insert', + context: { + sources: { + job_run_id: 'cgiiurt8um7k7n5dq480', + task_run_id: 'cgiiurt8um7k7n5dq48g', + job_id: '2MUWghI7u85n91dd1qzGyswpZan', + version: '895/merge', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(1), + }, + { + destination: destinationV2, + connection: connection, + message: { + action: 'insert', + context: { + sources: { + job_run_id: 'cgiiurt8um7k7n5dq480', + task_run_id: 'cgiiurt8um7k7n5dq48g', + job_id: '2MUWghI7u85n91dd1qzGyswpZan', + version: '895/merge', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(2), + }, + { + destination: destinationV2, + connection: connection, + message: { + action: 'insert', + context: { + sources: { + job_run_id: 'cgiiurt8um7k7n5dq480', + task_run_id: 'cgiiurt8um7k7n5dq48g', + job_id: '2MUWghI7u85n91dd1qzGyswpZan', + version: '895/merge', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(3), + }, + ], + destType: 'fb_custom_audience', +}; + +export const rETLRecordV2RouterInvalidRequest: RouterTransformationRequest = { + input: [ + { + destination: destinationV2, + connection: missingAudienceIDConnection, + message: { + action: 'insert', + context: { + sources: { + job_run_id: 'cgiiurt8um7k7n5dq480', + task_run_id: 'cgiiurt8um7k7n5dq48g', + job_id: '2MUWghI7u85n91dd1qzGyswpZan', + version: '895/merge', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + EMAIL: 'subscribed@eewrfrd.com', + FI: 'ghui', + }, + type: 'record', + }, + metadata: generateMetadata(1), + }, + ], + destType: 'fb_custom_audience', +}; + +export const destinationV1: Destination = { + Config: { + accessToken: 'ABC', + appSecret: 'dummySecret', + disableFormat: false, + isHashRequired: true, + isRaw: false, oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', @@ -29,10 +188,10 @@ const destination: Destination = { IsProcessorEnabled: true, }; -export const rETLRecordRouterRequest: RouterTransformationRequest = { +export const rETLRecordV1RouterRequest: RouterTransformationRequest = { input: [ { - destination: destination, + destination: destinationV1, message: { action: 'insert', context: { @@ -62,7 +221,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(3), }, { - destination: destination, + destination: destinationV1, message: { action: 'update', context: { @@ -92,7 +251,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(4), }, { - destination: destination, + destination: destinationV1, message: { action: 'delete', context: { @@ -122,7 +281,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(1), }, { - destination: destination, + destination: destinationV1, message: { action: 'delete', context: { @@ -152,7 +311,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(2), }, { - destination: destination, + destination: destinationV1, message: { action: 'update', context: { @@ -182,7 +341,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(5), }, { - destination: destination, + destination: destinationV1, message: { action: 'update', context: { @@ -212,7 +371,7 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { metadata: generateMetadata(6), }, { - destination: destination, + destination: destinationV1, message: { action: 'lol', context: { @@ -244,7 +403,3 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { ], destType: 'fb_custom_audience', }; - -module.exports = { - rETLRecordRouterRequest, -}; diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index 7d1c2a4317f..4eda20a9011 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -33,7 +33,9 @@ export const getTestDataFilePaths = (dirPath: string, opts: OptionValues): strin ); } if (opts.feature) { - filteredTestFilePaths = testFilePaths.filter((testFile) => testFile.includes(opts.feature)); + filteredTestFilePaths = filteredTestFilePaths.filter((testFile) => + testFile.includes(opts.feature), + ); } return filteredTestFilePaths; }; From 27040b06276c2bd1c1a6bd535172b50848a97261 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:45:59 +0530 Subject: [PATCH 020/147] fix: use destination definition name in place of string for custom object (#3746) * fix: use destination definition name in place of string for custom object * chore: add tests * chore: replace with dummy token * fix: remove response comparision typecast * chore: update equality logic, add tests --- src/v0/destinations/salesforce/transform.js | 10 +- .../destinations/salesforce/network.ts | 60 ++- .../destinations/salesforce/processor/data.ts | 30 +- .../destinations/salesforce/router/data.ts | 487 +++++++++++++++++- 4 files changed, 550 insertions(+), 37 deletions(-) diff --git a/src/v0/destinations/salesforce/transform.js b/src/v0/destinations/salesforce/transform.js index 9b7123c2078..1dde1ec65ac 100644 --- a/src/v0/destinations/salesforce/transform.js +++ b/src/v0/destinations/salesforce/transform.js @@ -134,7 +134,10 @@ async function getSaleforceIdForRecord( ); } const searchRecord = processedsfSearchResponse.response?.searchRecords?.find( - (rec) => typeof identifierValue !== 'undefined' && rec[identifierType] === `${identifierValue}`, + (rec) => + typeof identifierValue !== 'undefined' && + // eslint-disable-next-line eqeqeq + rec[identifierType] == identifierValue, ); return searchRecord?.Id; @@ -190,8 +193,9 @@ async function getSalesforceIdFromPayload( 'Invalid externalId. id, type, identifierType must be provided', ); } - - const objectType = type.toLowerCase().replace('salesforce-', ''); + const objectType = type + .toLowerCase() + .replace(`${destination.DestinationDefinition.Name.toLowerCase()}-`, ''); let salesforceId = id; // Fetch the salesforce Id if the identifierType is not ID diff --git a/test/integrations/destinations/salesforce/network.ts b/test/integrations/destinations/salesforce/network.ts index b422271d366..b4cff85d7ba 100644 --- a/test/integrations/destinations/salesforce/network.ts +++ b/test/integrations/destinations/salesforce/network.ts @@ -180,8 +180,7 @@ const transformationMocksData = [ httpRes: { status: 200, data: { - access_token: - '00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + access_token: 'dummy.access.token', instance_url: 'https://ap15.salesforce.com', id: 'https://login.salesforce.com/id/00D2v000002lXbXEAU/0052v00000ga9WqAAI', token_type: 'Bearer', @@ -198,8 +197,7 @@ const transformationMocksData = [ httpRes: { status: 200, data: { - access_token: - '00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + access_token: 'dummy.access.token', instance_url: 'https://ap15.salesforce.com', id: 'https://login.salesforce.com/id/00D2v000002lXbXEAU/0052v00000ga9WqAAI', token_type: 'Bearer', @@ -245,6 +243,18 @@ const transformationMocksData = [ }, }, }, + { + httpReq: { + url: 'https://ap15.salesforce.com/services/data/v50.0/parameterizedSearch/?q=72727&sobject=customobject&in=CustomObject__c&customobject.fields=id,CustomObject__c', + method: 'GET', + }, + httpRes: { + status: 200, + data: { + searchRecords: [], + }, + }, + }, { httpReq: { url: 'https://ap15.salesforce.com/services/data/v50.0/parameterizedSearch/?q=peter.gibbons1%40initech.com&sobject=Lead&Lead.fields=id', @@ -265,6 +275,48 @@ const transformationMocksData = [ }, }, }, + { + httpReq: { + url: 'https://ap15.salesforce.com/services/data/v50.0/parameterizedSearch/?q=72728&sobject=customobject2&in=CustomObject2__c&customobject2.fields=id,CustomObject2__c', + method: 'GET', + }, + httpRes: { + status: 200, + data: { + searchRecords: [ + { + attributes: { + type: 'CustomObject2__c', + url: '/services/data/v50.0/CustomObject2__c/id1101', + }, + Id: 'id1101', + CustomObject2__c: 72728, + }, + ], + }, + }, + }, + { + httpReq: { + url: 'https://ap15.salesforce.com/services/data/v50.0/parameterizedSearch/?q=72729&sobject=customobject2&in=CustomObject2__c&customobject2.fields=id,CustomObject2__c', + method: 'GET', + }, + httpRes: { + status: 200, + data: { + searchRecords: [ + { + attributes: { + type: 'CustomObject2__c', + url: '/services/data/v50.0/CustomObject2__c/id1102', + }, + Id: 'id1102', + CustomObject2__c: '72729', + }, + ], + }, + }, + }, { httpReq: { url: 'https://ap15.salesforce.com/services/data/v50.0/parameterizedSearch/?q=ddv_ua%2B%7B%7B1234*245%7D%7D%40bugFix.com&sobject=Lead&Lead.fields=id,IsConverted,ConvertedContactId,IsDeleted', diff --git a/test/integrations/destinations/salesforce/processor/data.ts b/test/integrations/destinations/salesforce/processor/data.ts index 4ccc8cca79b..7a44b6b8edd 100644 --- a/test/integrations/destinations/salesforce/processor/data.ts +++ b/test/integrations/destinations/salesforce/processor/data.ts @@ -97,8 +97,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -225,8 +224,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -354,8 +352,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -591,8 +588,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -721,8 +717,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -855,8 +850,7 @@ export const data = [ 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Contact/sf-contact-id?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -989,8 +983,7 @@ export const data = [ 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead/sf-contact-id?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, userId: '', @@ -1117,8 +1110,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -1244,8 +1236,7 @@ export const data = [ 'https://ap15.salesforce.com/services/data/v50.0/sobjects/custom_object__c/a005g0000383kmUAAQ?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -1360,8 +1351,7 @@ export const data = [ 'https://ap15.salesforce.com/services/data/v50.0/sobjects/custom_object__c/a005g0000383kmUAAQ?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { diff --git a/test/integrations/destinations/salesforce/router/data.ts b/test/integrations/destinations/salesforce/router/data.ts index 4a37f7ed401..9e26625188f 100644 --- a/test/integrations/destinations/salesforce/router/data.ts +++ b/test/integrations/destinations/salesforce/router/data.ts @@ -92,8 +92,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -239,8 +238,7 @@ export const data = [ 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead/leadId?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -385,8 +383,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -456,8 +453,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -519,8 +515,7 @@ export const data = [ endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/Lead', headers: { 'Content-Type': 'application/json', - Authorization: - 'Bearer 00D2v000002lXbX!ARcAQJBSGNA1Rq.MbUdtmlREscrN_nO3ckBz6kc4jRQGxqAzNkhT1XZIF0yPqyCQSnezWO3osMw1ewpjToO7q41E9.LvedWY', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { @@ -572,4 +567,476 @@ export const data = [ }, }, }, + { + name: 'salesforce', + description: 'Test 4 : Sending custom object for Salesforce-Oauth ', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + channel: 'web', + context: { + externalId: [ + { + id: 72727, + type: 'SALESFORCE_OAUTH-CUSTOMOBJECT', + identifierType: 'CustomObject__c', + }, + ], + mappedToDestination: 'true', + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + locale: 'en-US', + os: { name: '', version: '' }, + screen: { density: 2 }, + traits: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + address: { + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + postalCode: '94115', + }, + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', + }, + integrations: { All: true }, + messageId: 'f19c35da-e9de-4c6e-b6e5-9e60cccc12c8', + originalTimestamp: '2020-01-27T12:20:55.301Z', + receivedAt: '2020-01-27T17:50:58.657+05:30', + request_ip: '14.98.244.60', + sentAt: '2020-01-27T12:20:56.849Z', + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + userId: '1e7673da-9473-49c6-97f7-da848ecafa76', + }, + metadata: { jobId: 1, userId: 'u1' }, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + destType: 'salesforce', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ap15.salesforce.com/services/data/v50.0/sobjects/customobject', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer dummy.access.token', + }, + params: {}, + body: { + JSON: { + CustomObject__c: 72727, + address: { + postalCode: '94115', + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + }, + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + }, + }, + }, + }, + { + name: 'salesforce_oauth', + description: + 'Test 5: Sending custom object with external id of different type for Salesforce-Oauth (extId number, apiResponse string) ', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + channel: 'web', + context: { + externalId: [ + { + id: 72728, + type: 'SALESFORCE_OAUTH-CUSTOMOBJECT2', + identifierType: 'CustomObject2__c', + }, + ], + mappedToDestination: 'true', + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + locale: 'en-US', + os: { name: '', version: '' }, + screen: { density: 2 }, + traits: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + address: { + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + postalCode: '94115', + }, + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', + }, + integrations: { All: true }, + messageId: 'f19c35da-e9de-4c6e-b6e5-9e60cccc12c8', + originalTimestamp: '2020-01-27T12:20:55.301Z', + receivedAt: '2020-01-27T17:50:58.657+05:30', + request_ip: '14.98.244.60', + sentAt: '2020-01-27T12:20:56.849Z', + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + userId: '1e7673da-9473-49c6-97f7-da848ecafa76', + }, + metadata: { jobId: 1, userId: 'u1' }, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + destType: 'salesforce_oauth', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ap15.salesforce.com/services/data/v50.0/sobjects/customobject2/id1101?_HttpMethod=PATCH', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer dummy.access.token', + }, + params: {}, + body: { + JSON: { + CustomObject2__c: 72728, + address: { + postalCode: '94115', + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + }, + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + }, + }, + }, + }, + { + name: 'salesforce_oauth', + description: + 'Test 6: Sending custom object with external id of different type for Salesforce-Oauth (extId string, apiResponse number) ', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + channel: 'web', + context: { + externalId: [ + { + id: '72729', + type: 'SALESFORCE_OAUTH-CUSTOMOBJECT2', + identifierType: 'CustomObject2__c', + }, + ], + mappedToDestination: 'true', + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + locale: 'en-US', + os: { name: '', version: '' }, + screen: { density: 2 }, + traits: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + address: { + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + postalCode: '94115', + }, + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', + }, + integrations: { All: true }, + messageId: 'f19c35da-e9de-4c6e-b6e5-9e60cccc12c8', + originalTimestamp: '2020-01-27T12:20:55.301Z', + receivedAt: '2020-01-27T17:50:58.657+05:30', + request_ip: '14.98.244.60', + sentAt: '2020-01-27T12:20:56.849Z', + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + userId: '1e7673da-9473-49c6-97f7-da848ecafa76', + }, + metadata: { jobId: 1, userId: 'u1' }, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + destType: 'salesforce_oauth', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: + 'https://ap15.salesforce.com/services/data/v50.0/sobjects/customobject2/id1102?_HttpMethod=PATCH', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer dummy.access.token', + }, + params: {}, + body: { + JSON: { + CustomObject2__c: '72729', + address: { + postalCode: '94115', + city: 'east greenwich', + country: 'USA', + state: 'California', + street: '19123 forest lane', + }, + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + company: 'Initech', + email: 'peter.gibbons@initech.com', + name: 'Peter Gibbons', + phone: '570-690-4150', + rating: 'Hot', + title: 'VP of Derp', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + initialAccessToken: 'dummyInitialAccessToken', + password: 'dummyPassword1', + userName: 'testsalesforce1453@gmail.com', + }, + DestinationDefinition: { + DisplayName: 'Salesforce-Oauth', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH', + }, + Enabled: true, + ID: '1WqFFH5esuVPnUgHkvEoYxDcX3y', + Name: 'tst', + Transformations: [], + }, + }, + ], + }, + }, + }, + }, ]; From 855025b71c98adfcf491635dd883c071d4aa064e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 20 Sep 2024 07:33:07 +0000 Subject: [PATCH 021/147] chore(release): 1.79.0 --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c63fb4310c..c860747b6f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.79.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.78.0...v1.79.0) (2024-09-20) + + +### Features + +* add support for vdm next to fb custom audiences ([#3729](https://github.com/rudderlabs/rudder-transformer/issues/3729)) ([f33f525](https://github.com/rudderlabs/rudder-transformer/commit/f33f52503679be9271751aaa2fdca0661fed62e9)) + + +### Bug Fixes + +* use destination definition name in place of string for custom object ([#3746](https://github.com/rudderlabs/rudder-transformer/issues/3746)) ([27040b0](https://github.com/rudderlabs/rudder-transformer/commit/27040b06276c2bd1c1a6bd535172b50848a97261)) + ## [1.78.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.77.1...v1.78.0) (2024-09-16) diff --git a/package-lock.json b/package-lock.json index fadfe7df1bb..98bc41379e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.78.0", + "version": "1.79.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.78.0", + "version": "1.79.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index da4891e8491..c598db805ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.78.0", + "version": "1.79.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From d40e772f1a3741c1c4e9ab2365ed464b3988812e Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:41:54 +0530 Subject: [PATCH 022/147] feat: onboard shopify to v1 (#3665) * feat: onboard shopify to v1, initial commit * chore: refactor, add pixel transformation definitions * feat: add support for all pixel events in v1 shopify source * fix: add customer id check * chore: fix checks * fix: add configs for new webhook topics and events from pixel app * chore: update webhook event topic in mapping * chore: refactor * chore: update cart viewed logic * chore: refactor pixel code logic and tests * fix: library version for old and new serverside events * chore: address comments, refactorx1 * chore: add test * chore: add testsx2 * chore: update version naming from config * chore: keep old v0 logic intact, refactor * chore: sonarcloud reliability check fix * chore: update util file names * chore: move webhook specific logic for v2 pixel, address comments * chore: more refactoring, update userId and anonymousid from customer object * chore: update library name for pixel and webhook events in pixel app flow * chore: refactor pixel tests to seperate directory, remove reduntant test data --------- Co-authored-by: Krishna Chaitanya --- src/v0/sources/shopify/config.js | 52 + src/v0/sources/shopify/transform.js | 8 +- src/v1/sources/shopify/config.js | 76 + .../cartViewedEventMapping.json | 42 + .../checkoutStartedCompletedEventMapping.json | 42 + .../contextualFieldMapping.json | 34 + .../productListViewedEventMapping.json | 38 + .../productToCartEventMapping.json | 42 + .../productViewedEventMapping.json | 46 + src/v1/sources/shopify/pixelTransform.js | 91 + src/v1/sources/shopify/pixelUtils.js | 195 +++ src/v1/sources/shopify/pixelUtils.test.js | 244 +++ .../shopify/pixelWebhookEventTransform.js | 88 + src/v1/sources/shopify/transform.js | 33 + .../integrations/sources/shopify/constants.ts | 155 ++ test/integrations/sources/shopify/data.ts | 14 +- .../pixelTestScenarios/CheckoutEventsTests.ts | 570 +++++++ .../pixelTestScenarios/CheckoutStepsTests.ts | 1517 +++++++++++++++++ .../pixelTestScenarios/ProductEventsTests.ts | 888 ++++++++++ .../shopify/v1ServerSideEventsTests.ts | 598 +++++++ 20 files changed, 4771 insertions(+), 2 deletions(-) create mode 100644 src/v1/sources/shopify/config.js create mode 100644 src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelTransform.js create mode 100644 src/v1/sources/shopify/pixelUtils.js create mode 100644 src/v1/sources/shopify/pixelUtils.test.js create mode 100644 src/v1/sources/shopify/pixelWebhookEventTransform.js create mode 100644 src/v1/sources/shopify/transform.js create mode 100644 test/integrations/sources/shopify/constants.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts create mode 100644 test/integrations/sources/shopify/v1ServerSideEventsTests.ts diff --git a/src/v0/sources/shopify/config.js b/src/v0/sources/shopify/config.js index b8b3cde284d..a5ededf9da9 100644 --- a/src/v0/sources/shopify/config.js +++ b/src/v0/sources/shopify/config.js @@ -36,6 +36,32 @@ const SHOPIFY_TRACK_MAP = { orders_fulfilled: 'Order Fulfilled', orders_paid: 'Order Paid', orders_partially_fullfilled: 'Order Partially Fulfilled', + // following are the events that supported by rudderstack pixel app as generic track events + customer_tags_added: 'Customer Tags Added', + customer_tags_removed: 'Customer Tags Removed', + customer_email_updated: 'Customer Email Updated', + collections_create: 'Collection Created', + collections_update: 'Collection Updated', + collections_delete: 'Collection Deleted', + collection_listings_add: 'Collection Listings Added', + collection_listings_remove: 'Collection Listings Removed', + collection_listings_update: 'Collection Listings Updated', + collection_publications_create: 'Collection Publications Created', + collection_publications_delete: 'Collection Publications Deleted', + collection_publications_update: 'Collection Publications Updated', + discounts_create: 'Discount Created', + discounts_delete: 'Discount Deleted', + discounts_update: 'Discount Updated', + draft_orders_create: 'Draft Order Created', + draft_orders_delete: 'Draft Order Deleted', + draft_orders_update: 'Draft Order Updated', + fulfillment_order_split: 'Fulfillment Order Split', + inventory_items_create: 'Inventory Items Created', + inventory_items_delete: 'Inventory Items Deleted', + inventory_items_update: 'Inventory Items Updated', + inventory_levels_connect: 'Inventory Levels Connected', + inventory_levels_disconnect: 'Inventory Levels Disconnected', + inventory_levels_update: 'Inventory Levels Updated', }; const identifyMappingJSON = JSON.parse( @@ -100,6 +126,32 @@ const SUPPORTED_TRACK_EVENTS = [ 'orders_fulfilled', 'orders_paid', 'orders_partially_fullfilled', + // following are the events that supported by rudderstack pixel app as generic track events + 'customer_tags_added', + 'customer_tags_removed', + 'customer_email_updated', + 'collections_create', + 'collections_update', + 'collections_delete', + 'collection_listings_add', + 'collection_listings_remove', + 'collection_listings_update', + 'collection_publications_create', + 'collection_publications_delete', + 'collection_publications_update', + 'discounts_create', + 'discounts_delete', + 'discounts_update', + 'draft_orders_create', + 'draft_orders_delete', + 'draft_orders_update', + 'fulfillment_order_split', + 'inventory_items_create', + 'inventory_items_delete', + 'inventory_items_update', + 'inventory_levels_connect', + 'inventory_levels_disconnect', + 'inventory_levels_update', ]; const maxTimeToIdentifyRSGeneratedCall = 10000; // in ms diff --git a/src/v0/sources/shopify/transform.js b/src/v0/sources/shopify/transform.js index b55fc613276..8cf39dfa5c2 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -287,4 +287,10 @@ const process = async (event) => { return response; }; -exports.process = process; +module.exports = { + process, + processEvent, + identifyPayloadBuilder, + ecomPayloadBuilder, + trackPayloadBuilder, +}; diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js new file mode 100644 index 00000000000..5a3ce99b40c --- /dev/null +++ b/src/v1/sources/shopify/config.js @@ -0,0 +1,76 @@ +const path = require('path'); +const fs = require('fs'); + +const PIXEL_EVENT_TOPICS = { + CART_VIEWED: 'cart_viewed', + PRODUCT_ADDED_TO_CART: 'product_added_to_cart', + PRODUCT_REMOVED_FROM_CART: 'product_removed_from_cart', + PAGE_VIEWED: 'page_viewed', + PRODUCT_VIEWED: 'product_viewed', + COLLECTION_VIEWED: 'collection_viewed', + CHECKOUT_STARTED: 'checkout_started', + CHECKOUT_COMPLETED: 'checkout_completed', + CHECKOUT_ADDRESS_INFO_SUBMITTED: 'checkout_address_info_submitted', + CHECKOUT_CONTACT_INFO_SUBMITTED: 'checkout_contact_info_submitted', + CHECKOUT_SHIPPING_INFO_SUBMITTED: 'checkout_shipping_info_submitted', + PAYMENT_INFO_SUBMITTED: 'payment_info_submitted', + SEARCH_SUBMITTED: 'search_submitted', +}; + +const PIXEL_EVENT_MAPPING = { + cart_viewed: 'Cart Viewed', + product_added_to_cart: 'Product Added', + product_removed_from_cart: 'Product Removed', + page_viewed: 'Page Viewed', + product_viewed: 'Product Viewed', + collection_viewed: 'Collection Viewed', + checkout_started: 'Checkout Started', + checkout_completed: 'Checkout Completed', + checkout_address_info_submitted: 'Checkout Address Info Submitted', + checkout_contact_info_submitted: 'Checkout Contact Info Submitted', + checkout_shipping_info_submitted: 'Checkout Shipping Info Submitted', + payment_info_submitted: 'Payment Info Submitted', + search_submitted: 'Search Submitted', +}; + +const contextualFieldMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'contextualFieldMapping.json')), +); + +const cartViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'cartViewedEventMapping.json')), +); + +const productListViewedEventMappingJSON = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'productListViewedEventMapping.json'), + ), +); + +const productViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productViewedEventMapping.json')), +); + +const productToCartEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productToCartEventMapping.json')), +); + +const checkoutStartedCompletedEventMappingJSON = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'checkoutStartedCompletedEventMapping.json'), + ), +); + +const INTEGERATION = 'SHOPIFY'; + +module.exports = { + INTEGERATION, + PIXEL_EVENT_TOPICS, + PIXEL_EVENT_MAPPING, + contextualFieldMappingJSON, + cartViewedEventMappingJSON, + productListViewedEventMappingJSON, + productViewedEventMappingJSON, + productToCartEventMappingJSON, + checkoutStartedCompletedEventMappingJSON, +}; diff --git a/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json new file mode 100644 index 00000000000..b74320c7582 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "merchandise.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "merchandise.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "merchandise.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "merchandise.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "merchandise.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "merchandise.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "merchandise.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "merchandise.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "merchandise.title", + "destKeys": "name" + }, + { + "sourceKeys": "quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json new file mode 100644 index 00000000000..478bcfc270c --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "quantity", + "destKeys": "quantity" + }, + { + "sourceKeys": "title", + "destKeys": "name" + }, + { + "sourceKeys": "variant.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "variant.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "variant.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "variant.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "variant.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "variant.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "variant.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "variant.product.vendor", + "destKeys": "brand" + } +] diff --git a/src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json b/src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json new file mode 100644 index 00000000000..f3146849482 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json @@ -0,0 +1,34 @@ +[ + { + "sourceKeys": "context.document.referrer", + "destKeys": "page.referrer" + }, + { + "sourceKeys": "document.title", + "destKeys": "page.title" + }, + { + "sourceKeys": "navigator.userAgent", + "destKeys": "userAgent" + }, + { + "sourceKeys": "window.location.href", + "destKeys": "page.url" + }, + { + "sourceKeys": "window.location.pathname", + "destKeys": "page.path" + }, + { + "sourceKeys": "window.location.search", + "destKeys": "page.search" + }, + { + "sourceKeys": "window.screen.height", + "destKeys": "screen.height" + }, + { + "sourceKeys": "window.screen.width", + "destKeys": "screen.width" + } +] diff --git a/src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json new file mode 100644 index 00000000000..fb8e8a45671 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json @@ -0,0 +1,38 @@ +[ + { + "sourceKeys": "image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "product.type", + "destKeys": "category" + }, + { + "sourceKeys": "product.url", + "destKeys": "url" + }, + { + "sourceKeys": "product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "sku", + "destKeys": "sku" + }, + { + "sourceKeys": "title", + "destKeys": "name" + } +] diff --git a/src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json new file mode 100644 index 00000000000..2f9d71bc03e --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "cartLine.merchandise.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "cartLine.merchandise.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "cartLine.merchandise.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "cartLine.merchandise.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "cartLine.merchandise.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "cartLine.merchandise.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "cartLine.merchandise.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "cartLine.merchandise.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "cartLine.merchandise.title", + "destKeys": "name" + }, + { + "sourceKeys": "cartLine.quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json new file mode 100644 index 00000000000..becb15acfc4 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json @@ -0,0 +1,46 @@ +[ + { + "sourceKeys": "productVariant.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "productVariant.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "productVariant.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "productVariant.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "productVariant.product.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "productVariant.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "productVariant.price.currencyCode", + "destKeys": "currency" + }, + { + "sourceKeys": "productVariant.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "productVariant.product.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "productVariant.product.title", + "destKeys": "name" + }, + { + "sourceKeys": "cartLine.quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js new file mode 100644 index 00000000000..0ca64b41238 --- /dev/null +++ b/src/v1/sources/shopify/pixelTransform.js @@ -0,0 +1,91 @@ +const stats = require('../../../util/stats'); +const logger = require('../../../logger'); +const { removeUndefinedAndNullValues } = require('../../../v0/util'); +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./pixelUtils'); +const { INTEGERATION, PIXEL_EVENT_TOPICS } = require('./config'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +function processPixelEvent(inputEvent) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { name, query_parameters, clientId, data } = inputEvent; + const { checkout } = data ?? {}; + const { order } = checkout ?? {}; + const { customer } = order ?? {}; + let message = {}; + switch (name) { + case PIXEL_EVENT_TOPICS.PAGE_VIEWED: + message = pageViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CART_VIEWED: + message = cartViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: + message = productListViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_VIEWED: + message = productViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_ADDED_TO_CART: + case PIXEL_EVENT_TOPICS.PRODUCT_REMOVED_FROM_CART: + message = productToCartEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: + if (customer.id) message.userId = customer.id || ''; + message = checkoutEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_CONTACT_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: + if (customer.id) message.userId = customer.id || ''; + message = checkoutStepEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: + message = searchEventBuilder(inputEvent); + break; + default: + logger.debug(`{{SHOPIFY::}} Invalid pixel event ${name}`); + stats.increment('invalid_shopify_event', { + writeKey: query_parameters.writeKey, + source: 'SHOPIFY', + shopifyTopic: name, + }); + return NO_OPERATION_SUCCESS; + } + message.anonymousId = clientId; + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }); + message.setProperty('context.topic', name); + message = removeUndefinedAndNullValues(message); + return message; +} + +const processEventFromPixel = async (event) => { + const pixelEvent = processPixelEvent(event); + return removeUndefinedAndNullValues(pixelEvent); +}; + +module.exports = { + processEventFromPixel, +}; diff --git a/src/v1/sources/shopify/pixelUtils.js b/src/v1/sources/shopify/pixelUtils.js new file mode 100644 index 00000000000..92197a558b2 --- /dev/null +++ b/src/v1/sources/shopify/pixelUtils.js @@ -0,0 +1,195 @@ +/* eslint-disable no-param-reassign */ +const Message = require('../../../v0/sources/message'); +const { EventType } = require('../../../constants'); +const { + INTEGERATION, + PIXEL_EVENT_MAPPING, + contextualFieldMappingJSON, + cartViewedEventMappingJSON, + productListViewedEventMappingJSON, + productViewedEventMappingJSON, + productToCartEventMappingJSON, + checkoutStartedCompletedEventMappingJSON, +} = require('./config'); + +function getNestedValue(object, path) { + const keys = path.split('.'); + return keys.reduce((nestedObject, key) => nestedObject && nestedObject[key], object); +} + +function setNestedValue(object, path, value) { + const keys = path.split('.'); + const lastKeyIndex = keys.length - 1; + keys.reduce((nestedObject, key, index) => { + if (index === lastKeyIndex) { + nestedObject[key] = value; + } else if (!nestedObject[key]) { + nestedObject[key] = {}; + } + return nestedObject[key]; + }, object); +} + +function mapObjectKeys(sourceObject, keyMappings) { + if (!Array.isArray(keyMappings)) { + throw new TypeError('keyMappings should be an array'); + } + const resultObject = { ...sourceObject }; + + // eslint-disable-next-line @typescript-eslint/no-shadow + return keyMappings.reduce((resultObject, { sourceKeys, destKeys }) => { + const value = getNestedValue(sourceObject, sourceKeys); + if (value !== undefined) { + setNestedValue(resultObject, destKeys, value); + } + return resultObject; + }, resultObject); +} + +const createMessage = (eventType, eventName, properties, context) => { + const message = new Message(INTEGERATION); + message.setEventType(eventType); + message.setEventName(eventName); + message.properties = properties; + message.context = context; + return message; +}; + +const pageViewedEventBuilder = (inputEvent) => { + const { data, context } = inputEvent; + const pageEventContextValues = mapObjectKeys(context, contextualFieldMappingJSON); + const message = new Message(INTEGERATION); + message.name = 'Page View'; + message.setEventType(EventType.PAGE); + message.properties = { ...data }; + message.context = { ...pageEventContextValues }; + return message; +}; + +const cartViewedEventBuilder = (inputEvent) => { + const lines = inputEvent?.data?.cart?.lines; + const products = []; + let total; + if (lines) { + lines.forEach((line) => { + const product = mapObjectKeys(line, cartViewedEventMappingJSON); + products.push(product); + total = line.cost.totalAmount.amount; + }); + } + + const properties = { + products, + cart_id: inputEvent.data.cart.id, + total, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Cart Viewed', properties, contextualPayload); +}; + +const productListViewedEventBuilder = (inputEvent) => { + const productVariants = inputEvent?.data?.collection?.productVariants; + const products = []; + + productVariants.forEach((productVariant) => { + const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMappingJSON); + products.push(mappedProduct); + }); + + const properties = { + cart_id: inputEvent.clientId, + list_id: inputEvent.id, + products, + }; + + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product List Viewed', properties, contextualPayload); +}; + +const productViewedEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productViewedEventMappingJSON), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product Viewed', properties, contextualPayload); +}; + +const productToCartEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productToCartEventMappingJSON), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +const checkoutEventBuilder = (inputEvent) => { + const lineItems = inputEvent?.data?.checkout?.lineItems; + const products = []; + + lineItems.forEach((lineItem) => { + const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMappingJSON); + products.push(mappedProduct); + }); + + const properties = { + products, + order_id: inputEvent.id, + checkout_id: inputEvent?.data?.checkout?.token, + total: inputEvent?.data?.checkout?.totalPrice?.amount, + currency: inputEvent?.data?.checkout?.currencyCode, + discount: inputEvent?.data?.checkout?.discountsAmount?.amount, + shipping: inputEvent?.data?.checkout?.shippingLine?.price?.amount, + revenue: inputEvent?.data?.checkout?.subtotalPrice?.amount, + value: inputEvent?.data?.checkout?.totalPrice?.amount, + tax: inputEvent?.data?.checkout?.totalTax?.amount, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +const checkoutStepEventBuilder = (inputEvent) => { + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const properties = { + ...inputEvent.data.checkout, + }; + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +const searchEventBuilder = (inputEvent) => { + const properties = { + query: inputEvent.data.searchResult.query, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +module.exports = { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +}; diff --git a/src/v1/sources/shopify/pixelUtils.test.js b/src/v1/sources/shopify/pixelUtils.test.js new file mode 100644 index 00000000000..cd544568cd1 --- /dev/null +++ b/src/v1/sources/shopify/pixelUtils.test.js @@ -0,0 +1,244 @@ +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./pixelUtils'); +const { EventType } = require('../../../constants'); +const Message = require('../../../v0/sources/message'); +jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +jest.mock('../../../v0/sources/message'); + +describe('utilV2.js', () => { + beforeEach(() => { + Message.mockClear(); + }); + + describe('pageViewedEventBuilder', () => { + it('should build a page viewed event message', () => { + const inputEvent = { + data: { url: 'https://example.com' }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = pageViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.name).toBe('Page View'); + expect(message.properties).toEqual(inputEvent.data); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('cartViewedEventBuilder', () => { + it('should build a cart viewed event message', () => { + const inputEvent = { + data: { + cart: { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + }, + id: '41327143157873', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + attributes: [], + id: '123', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = cartViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + products: [ + { + name: 'Default Title', + price: 629.95, + quantity: 2, + variant: 'The Multi-managed Snowboard', + merchandise: { + id: '41327143157873', + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + }, + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + cost: { + totalAmount: { amount: 1259.9, currencyCode: 'USD' }, + }, + }, + ], + cart_id: '123', + total: 1259.9, + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productListViewedEventBuilder', () => { + it('should build a product list viewed event message', () => { + const inputEvent = { + data: { + collection: { + productVariants: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + }, + }, + clientId: 'client123', + id: 'list123', + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = productListViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + cart_id: 'client123', + list_id: 'list123', + products: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productViewedEventBuilder', () => { + it('should build a product viewed event message', () => { + const inputEvent = { + data: { id: 'product123', name: 'Product 123' }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = productViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productToCartEventBuilder', () => { + it('should build a product to cart event message', () => { + const inputEvent = { + data: { id: 'product123', name: 'Product 123' }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'add_to_cart', + }; + const message = productToCartEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('checkoutEventBuilder', () => { + it('should build a checkout event message', () => { + const inputEvent = { + data: { + checkout: { + lineItems: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + token: 'checkout123', + totalPrice: { amount: 200 }, + currencyCode: 'USD', + discountsAmount: { amount: 10 }, + shippingLine: { price: { amount: 5 } }, + subtotalPrice: { amount: 185 }, + totalTax: { amount: 15 }, + }, + }, + id: 'order123', + context: { userAgent: 'Mozilla/5.0' }, + name: 'checkout_started', + }; + const message = checkoutEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + products: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + order_id: 'order123', + checkout_id: 'checkout123', + total: 200, + currency: 'USD', + discount: 10, + shipping: 5, + revenue: 185, + value: 200, + tax: 15, + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('checkoutStepEventBuilder', () => { + it('should build a checkout step event message', () => { + const inputEvent = { + data: { + checkout: { + step: 1, + action: 'shipping_info_submitted', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'checkout_step', + }; + const message = checkoutStepEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ step: 1, action: 'shipping_info_submitted' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('searchEventBuilder', () => { + it('should build a search event message', () => { + const inputEvent = { + data: { + searchResult: { + query: 'test query', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'search_submitted', + }; + const message = searchEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ query: 'test query' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); +}); diff --git a/src/v1/sources/shopify/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js new file mode 100644 index 00000000000..43b741f8372 --- /dev/null +++ b/src/v1/sources/shopify/pixelWebhookEventTransform.js @@ -0,0 +1,88 @@ +const lodash = require('lodash'); +const get = require('get-value'); +const { isDefinedNotNullNotEmpty } = require('@rudderstack/integrations-lib'); +const stats = require('../../../util/stats'); +const { getShopifyTopic, extractEmailFromPayload } = require('../../../v0/sources/shopify/util'); +const { + identifyPayloadBuilder, + trackPayloadBuilder, + ecomPayloadBuilder, +} = require('../../../v0/sources/shopify/transform'); +const { removeUndefinedAndNullValues, generateUUID } = require('../../../v0/util'); +const Message = require('../../../v0/sources/message'); +const { + INTEGERATION, + IDENTIFY_TOPICS, + ECOM_TOPICS, + SUPPORTED_TRACK_EVENTS, +} = require('../../../v0/sources/shopify/config'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +const processPixelWebhookEvent = async (inputEvent, metricMetadata) => { + let message = new Message(INTEGERATION); + const event = lodash.cloneDeep(inputEvent); + const shopifyTopic = getShopifyTopic(event); + delete event.query_parameters; + switch (shopifyTopic) { + case IDENTIFY_TOPICS.CUSTOMERS_CREATE: + case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: + message = identifyPayloadBuilder(event); + break; + case ECOM_TOPICS.ORDERS_CREATE: + case ECOM_TOPICS.ORDERS_UPDATE: + case ECOM_TOPICS.CHECKOUTS_CREATE: + case ECOM_TOPICS.CHECKOUTS_UPDATE: + message = ecomPayloadBuilder(event, shopifyTopic); + break; + case 'carts_update': + message = trackPayloadBuilder(event, shopifyTopic); + break; + default: + if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { + stats.increment('invalid_shopify_event', { + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + return NO_OPERATION_SUCCESS; + } + message = trackPayloadBuilder(event, shopifyTopic); + break; + } + + if (event.customer && isDefinedNotNullNotEmpty(event?.customer?.id)) { + message.userId = String(event.customer.id); + } + message.anonymousId = generateUUID(); + + if (!get(message, 'traits.email')) { + const email = extractEmailFromPayload(event); + if (email) { + message.setProperty('traits.email', email); + } + } + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', + version: '2.0.0', + }); + message.setProperty('context.topic', shopifyTopic); + // attaching cart, checkout and order tokens in context object + message.setProperty(`context.cart_token`, event.cart_token); + message.setProperty(`context.checkout_token`, event.checkout_token); + if (shopifyTopic === 'orders_updated') { + message.setProperty(`context.order_token`, event.token); + } + message = removeUndefinedAndNullValues(message); + return message; +}; + +module.exports = { processPixelWebhookEvent }; diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js new file mode 100644 index 00000000000..ff9aadbca42 --- /dev/null +++ b/src/v1/sources/shopify/transform.js @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const { isDefinedAndNotNull } = require('../../../v0/util'); +const { processEventFromPixel } = require('./pixelTransform'); +const { processPixelWebhookEvent } = require('./pixelWebhookEventTransform'); +const { process: processLegacyEvents } = require('../../../v0/sources/shopify/transform'); + +const process = async (inputEvent) => { + const { event, source } = inputEvent; + const metricMetadata = { + // eslint-disable-next-line unicorn/consistent-destructuring + writeKey: source?.WriteKey || event.query_parameters?.writeKey?.[0], + sourceId: source?.ID, + source: 'SHOPIFY', + }; + // check on the source Config to identify the event is from the tracker-based (legacy) + // or the pixel-based (latest) implementation. + if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'pixel') { + const { pixelEventLabel: pixelClientEventLabel } = event; + if (pixelClientEventLabel) { + // this is a event fired from the web pixel loaded on the browser + // by the user interactions with the store. + const responseV2 = await processEventFromPixel(event); + return responseV2; + } + const webhookEventResponse = await processPixelWebhookEvent(event, metricMetadata, source); + return webhookEventResponse; + } + // this is for default legacy tracker based server-side events processing + const response = await processLegacyEvents(event); + return response; +}; + +module.exports = { process }; diff --git a/test/integrations/sources/shopify/constants.ts b/test/integrations/sources/shopify/constants.ts new file mode 100644 index 00000000000..f9df3058416 --- /dev/null +++ b/test/integrations/sources/shopify/constants.ts @@ -0,0 +1,155 @@ +export const dummySourceConfig = { + ID: 'dummy-source-id', + OriginalID: '', + Name: 'Shopify v2', + Config: { + disableClientSideIdentifier: false, + eventUpload: false, + version: 'pixel', + }, + Enabled: true, + WorkspaceID: 'dummy-workspace-id', + Destinations: null, + WriteKey: 'dummy-write-key', +}; + +export const dummyBillingAddresses = [ + { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, +]; + +export const dummyContext = { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, +}; + +export const responseDummyContext = { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, +}; diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index f5eb3c148bc..7a74bc4d06a 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,6 +1,10 @@ import { skip } from 'node:test'; +import { pixelCheckoutEventsTestScenarios } from './pixelTestScenarios/CheckoutEventsTests'; +import { pixelCheckoutStepsScenarios } from './pixelTestScenarios/CheckoutStepsTests'; +import { pixelEventsTestScenarios } from './pixelTestScenarios/ProductEventsTests'; +import { v1ServerSideEventsScenarios } from './v1ServerSideEventsTests'; -export const data = [ +const serverSideEventsScenarios = [ { name: 'shopify', description: 'Track Call -> carts_create ', @@ -607,3 +611,11 @@ export const data = [ }, }, ]; + +export const data = [ + ...pixelCheckoutEventsTestScenarios, + ...pixelCheckoutStepsScenarios, + ...pixelEventsTestScenarios, + ...serverSideEventsScenarios, + ...v1ServerSideEventsScenarios, +]; diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts new file mode 100644 index 00000000000..1009fa2d040 --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts @@ -0,0 +1,570 @@ +// This file contains the test scenarios for the pixel checkout events +import { dummySourceConfig, dummyBillingAddresses, dummyContext } from '../constants'; + +export const pixelCheckoutEventsTestScenarios = [ + { + name: 'shopify', + description: 'Track Call -> checkout_started event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_started', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: dummyBillingAddresses[0], + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: dummyBillingAddresses[0], + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, + topic: 'checkout_started', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Started', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> checkout_completed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_completed', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: dummyBillingAddresses[0], + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: dummyBillingAddresses[0], + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, + topic: 'checkout_completed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Completed', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: 'The Multi-managed Snowboard', + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Multi-managed Snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + price: 629.95, + sku: 'sku-managed-1', + product_id: '7234590736497', + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts new file mode 100644 index 00000000000..9d845c1dded --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts @@ -0,0 +1,1517 @@ +import { dummySourceConfig, dummyContext, responseDummyContext } from '../constants'; + +export const pixelCheckoutStepsScenarios = [ + { + name: 'shopify', + description: 'Track Call -> address_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', + name: 'checkout_address_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:45:50.523Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_address_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Address Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> contact_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', + name: 'checkout_contact_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:40:28.498Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_contact_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Contact Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> shipping_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', + name: 'checkout_shipping_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:47:38.576Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_shipping_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Shipping Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> payment_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', + name: 'payment_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:49:13.092Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'payment_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Payment Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts new file mode 100644 index 00000000000..0b8f8c3c1a3 --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts @@ -0,0 +1,888 @@ +// This file contains the test scenarios related to Shopify pixel events, emitted from web pixel on the browser. +import { dummyContext, dummySourceConfig, responseDummyContext } from '../constants'; + +export const pixelEventsTestScenarios = [ + { + name: 'shopify', + description: 'Page Call -> page_view event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', + name: 'page_viewed', + data: {}, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:24:30.373Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['page_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'page_viewed' }, + integrations: { + SHOPIFY: true, + }, + name: 'Page View', + type: 'page', + properties: {}, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', + name: 'product_viewed', + data: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:34:54.889Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['product_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Viewed', + properties: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + brand: 'Hydrogen Vendor', + category: 'snowboard', + price: 749.95, + currency: 'USD', + url: '/products/the-collection-snowboard-liquid', + name: 'The Collection Snowboard: Liquid', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> cart_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', + name: 'cart_viewed', + data: { + cart: { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + attributes: [], + id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:25:30.125Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['cart_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'cart_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Viewed', + properties: { + products: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + product_id: '7234590736497', + variant: 'The Multi-managed Snowboard', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + price: 629.95, + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + sku: 'sku-managed-1', + name: 'Default Title', + }, + ], + cart_id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + total: 1259.9, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> collection_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + name: 'collection_viewed', + data: { + collection: { + id: '', + title: 'Products', + productVariants: [ + { + price: { + amount: 10, + currencyCode: 'USD', + }, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + }, + { + price: { + amount: 24.95, + currencyCode: 'USD', + }, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + }, + { + price: { + amount: 2629.95, + currencyCode: 'USD', + }, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + ], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:27:39.197Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['collection_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'collection_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product List Viewed', + properties: { + cart_id: 'c7b3f99b-4d34-463b-835f-c879482a7750', + list_id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + products: [ + { + price: 10, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + image_url: + '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + product_id: '7234590605425', + variant: 'Gift Card', + category: 'giftcard', + url: '/products/gift-card', + brand: 'Snowboard Vendor', + name: '$10', + }, + { + price: 24.95, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + image_url: + '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + product_id: '7234590802033', + variant: 'Selling Plans Ski Wax', + category: 'accessories', + url: '/products/selling-plans-ski-wax', + brand: 'pixel-testing-rs', + name: 'Selling Plans Ski Wax', + }, + { + price: 2629.95, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + product_id: '7234590703729', + variant: 'The 3p Fulfilled Snowboard', + category: 'snowboard', + url: '/products/the-3p-fulfilled-snowboard', + brand: 'pixel-testing-rs', + name: 'Default Title', + }, + ], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_added_to_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', + name: 'product_added_to_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:34:42.625Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_added_to_cart' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Added', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_removed_from_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', + name: 'product_removed_from_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:56:00.125Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_removed_from_cart' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Removed', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> search_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'search_submitted', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'search_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Search Submitted', + properties: { + query: 'skate', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> unknown event from web pixel, should not be sent to Shopify', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'unknown_event', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + outputToSource: { + body: 'T0s=', + contentType: 'text/plain', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts new file mode 100644 index 00000000000..a91a2138731 --- /dev/null +++ b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts @@ -0,0 +1,598 @@ +// This file contains the test scenarios for the server-side events from the Shopify GraphQL API for +// the v1 transformation flow +import utils from '../../../../src/v0/util'; +const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); +}; +import { dummySourceConfig } from './constants'; + +export const v1ServerSideEventsScenarios = [ + { + name: 'shopify', + description: 'Track Call -> Checkout Updated event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 35374569160817, + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + gateway: null, + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + sms_marketing_phone: null, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + shipping_address: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + taxes_included: false, + total_weight: 0, + currency: 'USD', + completed_at: null, + phone: null, + customer_locale: 'en-US', + line_items: [ + { + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + product_id: 7234590638193, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + variant_id: 41327143059569, + variant_title: '', + variant_price: '729.95', + vendor: 'pixel-testing-rs', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '729.95', + total_price: '736.85', + total_duties: '0.00', + device_id: null, + user_id: null, + location_id: null, + source_identifier: null, + source_url: null, + source: null, + closed_at: null, + customer: { + id: 7188389789809, + email: 'testuser101@gmail.com', + accepts_marketing: false, + created_at: null, + updated_at: null, + first_name: 'testuser', + last_name: 'dummy', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + tags: '', + currency: 'USD', + accepts_marketing_updated_at: null, + admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', + default_address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + last_order_name: null, + marketing_opt_in_level: null, + }, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'checkouts_update', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Updated', + properties: { + order_id: 35374569160817, + value: '736.85', + tax: '0.00', + currency: 'USD', + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + taxes_included: false, + total_weight: 0, + customer_locale: 'en-US', + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_discounts: '0.00', + subtotal_price: '729.95', + total_duties: '0.00', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 1, + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + requires_shipping: true, + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + variant: '41327143059569 729.95 ', + }, + ], + }, + userId: '7188389789809', + traits: { + email: 'testuser101@gmail.com', + firstName: 'testuser', + lastName: 'dummy', + address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + acceptsMarketing: false, + orderCount: 0, + state: 'disabled', + totalSpent: '0.00', + verifiedEmail: true, + taxExempt: false, + tags: '', + currency: 'USD', + adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', + shippingAddress: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + }, + timestamp: '2024-09-17T07:29:02.000Z', + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, + { + name: 'shopify', + description: 'Track Call -> Cart Update event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + line_items: [ + { + id: 41327143059569, + properties: null, + quantity: 3, + variant_id: 41327143059569, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + price: '729.95', + product_id: 7234590638193, + sku: '', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + vendor: 'pixel-testing-rs', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + }, + ], + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + query_parameters: { + topic: ['carts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'carts_update', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Update', + properties: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 3, + id: 41327143059569, + properties: null, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + variant: '41327143059569 ', + }, + ], + }, + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, +]; From 10d914e25203bd6ae95801c2a98c17690bd2d6ef Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:30:34 +0530 Subject: [PATCH 023/147] fix: support different lookup fields and custom_attributes for rETL events (#3751) * fix: support different lookup fields and custom_attributes for rETL events * fix: address comments --------- Co-authored-by: Krishna Chaitanya --- .../destinations/intercom/procWorkflow.yaml | 10 +-- src/cdk/v2/destinations/intercom/utils.js | 25 ++++-- .../destinations/intercom/network.ts | 37 +++++++++ .../intercom/processor/identifyTestData.ts | 78 +++++++++++++++++++ 4 files changed, 137 insertions(+), 13 deletions(-) diff --git a/src/cdk/v2/destinations/intercom/procWorkflow.yaml b/src/cdk/v2/destinations/intercom/procWorkflow.yaml index 0f2ac18fbc0..db1ed02d570 100644 --- a/src/cdk/v2/destinations/intercom/procWorkflow.yaml +++ b/src/cdk/v2/destinations/intercom/procWorkflow.yaml @@ -77,8 +77,8 @@ steps: template: | const payload = .message.context.mappedToDestination ? $.outputs.rEtlPayload : $.outputs.identifyTransformationForLatestVersion; payload.name = $.getName(.message); - payload.custom_attributes = .message.context.traits || {}; - payload.custom_attributes = $.filterCustomAttributes(payload, "user", .destination); + payload.custom_attributes = (.message.context.mappedToDestination ? .message.traits.custom_attributes : .message.context.traits) || {}; + payload.custom_attributes = $.filterCustomAttributes(payload, "user", .destination, .message); payload.external_id = !payload.external_id && .destination.Config.sendAnonymousId && .message.anonymousId ? .message.anonymousId : payload.external_id; $.context.payload = payload; $.assert($.context.payload.external_id || $.context.payload.email, "Either email or userId is required for Identify call"); @@ -114,7 +114,7 @@ steps: update_last_request_at: typeof .destination.Config.updateLastRequestAt === 'boolean' ? .destination.Config.updateLastRequestAt : true } payload.companies = $.getCompaniesList(payload); - payload.custom_attributes = !.message.context.mappedToDestination ? $.filterCustomAttributes(payload, "user", .destination); + payload.custom_attributes = !.message.context.mappedToDestination ? $.filterCustomAttributes(payload, "user", .destination,.message); payload.user_id = !payload.user_id && .destination.Config.sendAnonymousId && .message.anonymousId ? .message.anonymousId : payload.user_id; $.context.payload = payload; $.assert($.context.payload.user_id || $.context.payload.email, "Either of `email` or `userId` is required for Identify call"); @@ -175,7 +175,7 @@ steps: $.assert(.message.groupId, "groupId is required for group call"); const payload = .message.context.mappedToDestination ? $.outputs.rEtlPayload : $.outputs.groupTransformation; payload.custom_attributes = .message.traits || {}; - payload.custom_attributes = $.filterCustomAttributes(payload, "company", .destination); + payload.custom_attributes = $.filterCustomAttributes(payload, "company", .destination,.message); $.context.payload = payload; - name: whenSearchContactFound condition: $.isDefinedAndNotNull($.outputs.searchContact) @@ -214,7 +214,7 @@ steps: ...payload, custom_attributes : $.getFieldValueFromMessage(.message, "traits") || {} } - payload.custom_attributes = $.filterCustomAttributes(payload, "company", .destination); + payload.custom_attributes = $.filterCustomAttributes(payload, "company", .destination, .message); response.body.JSON = $.removeUndefinedAndNullValues(payload); response.endpoint = $.getBaseEndpoint(.destination) + "/" + "companies"; response.headers = $.getHeaders(.destination, $.outputs.apiVersion); diff --git a/src/cdk/v2/destinations/intercom/utils.js b/src/cdk/v2/destinations/intercom/utils.js index dc483e040bc..22af726e846 100644 --- a/src/cdk/v2/destinations/intercom/utils.js +++ b/src/cdk/v2/destinations/intercom/utils.js @@ -233,20 +233,26 @@ const attachUserAndCompany = (message, Config) => { * @param {*} type * @returns */ -const filterCustomAttributes = (payload, type, destination) => { +const filterCustomAttributes = (payload, type, destination, message) => { let ReservedAttributesList; let { apiVersion } = destination.Config; apiVersion = isDefinedAndNotNull(apiVersion) ? apiVersion : 'v2'; + // we are discarding the lookup field from custom attributes + const lookupField = getLookUpField(message); if (type === 'user') { - ReservedAttributesList = - apiVersion === 'v1' + ReservedAttributesList = [ + ...(apiVersion === 'v1' ? ReservedAttributes.v1UserAttributes - : ReservedAttributes.v2UserAttributes; + : ReservedAttributes.v2UserAttributes), + lookupField, + ]; } else { - ReservedAttributesList = - apiVersion === 'v1' + ReservedAttributesList = [ + ...(apiVersion === 'v1' ? ReservedAttributes.v1CompanyAttributes - : ReservedAttributes.v2CompanyAttributes; + : ReservedAttributes.v2CompanyAttributes), + lookupField !== 'email' && lookupField, + ]; } let customAttributes = { ...get(payload, 'custom_attributes') }; if (customAttributes) { @@ -270,7 +276,10 @@ const filterCustomAttributes = (payload, type, destination) => { */ const searchContact = async (message, destination, metadata) => { const lookupField = getLookUpField(message); - const lookupFieldValue = getFieldValueFromMessage(message, lookupField); + let lookupFieldValue = getFieldValueFromMessage(message, lookupField); + if (!lookupFieldValue) { + lookupFieldValue = message?.context?.traits?.[lookupField]; + } const data = JSON.stringify({ query: { operator: 'AND', diff --git a/test/integrations/destinations/intercom/network.ts b/test/integrations/destinations/intercom/network.ts index 2f90beac408..0a86ce3c897 100644 --- a/test/integrations/destinations/intercom/network.ts +++ b/test/integrations/destinations/intercom/network.ts @@ -1041,5 +1041,42 @@ const deliveryCallsData = [ }, }, }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'external_id', operator: '=', value: '10156' }], + }, + }, + headers: { ...commonHeaders, 'Intercom-Version': '2.10', 'User-Agent': 'RudderStack' }, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 1, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 1, + }, + data: [ + { + type: 'contact', + id: '7070129940741e45d040', + workspace_id: 'rudderWorkspace', + external_id: 'user@2', + role: 'user', + email: 'test+2@rudderlabs.com', + }, + ], + }, + }, + }, ]; export const networkCallsData = [...deleteNwData, ...deliveryCallsData]; diff --git a/test/integrations/destinations/intercom/processor/identifyTestData.ts b/test/integrations/destinations/intercom/processor/identifyTestData.ts index 49f3a400d14..f078536b30a 100644 --- a/test/integrations/destinations/intercom/processor/identifyTestData.ts +++ b/test/integrations/destinations/intercom/processor/identifyTestData.ts @@ -80,6 +80,10 @@ const user3Traits = { name: 'Test Rudderlabs', phone: '+91 9999999999', email: 'test@rudderlabs.com', + custom_attributes: { + ca1: 'value1', + ca2: 'value2', + }, }; const user4Traits = { @@ -170,6 +174,10 @@ const expectedUser3Traits = { name: 'Test Rudderlabs', phone: '+91 9999999999', email: 'test@rudderlabs.com', + custom_attributes: { + ca1: 'value1', + ca2: 'value2', + }, }; const expectedUser4Traits = { @@ -233,6 +241,17 @@ const expectedUser6Traits = { ], }; +const expectedUser7Traits = { + custom_attributes: { + anonymousId: '58b21c2d-f8d5-4410-a2d0-b268a26b7e33', + key1: 'value1', + }, + email: 'test_1@test.com', + name: 'Test Name', + phone: '9876543210', + signed_up_at: 1601493060, +}; + const timestamp = '2023-11-22T10:12:44.757+05:30'; const originalTimestamp = '2023-11-10T14:42:44.724Z'; @@ -1024,4 +1043,63 @@ export const identifyTestData = [ }, }, }, + { + id: 'intercom-identify-test-16', + name: 'intercom', + description: 'V1 version : Identify test with different lookup field than email', + scenario: 'Business', + successCriteria: + 'Response status code should be 200 and response should contain update user payload with all traits', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: v2Destination, + message: { + context: { + externalId: [ + { + id: '10156', + type: 'INTERCOM-customer', + identifierType: 'user_id', + }, + ], + traits: { ...user5Traits, external_id: '10156' }, + }, + type: 'identify', + timestamp, + originalTimestamp, + integrations: { + INTERCOM: { + lookup: 'external_id', + }, + }, + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + endpoint: `${v2Endpoint}/7070129940741e45d040`, + headers: v2Headers, + method: 'PUT', + JSON: expectedUser7Traits, + }), + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, ]; From b2c1a1893dfb957ac7a24c000b33cd254ef54b6c Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:27:31 +0530 Subject: [PATCH 024/147] fix: prefer event check vs config check for vdm (#3754) --- src/v0/destinations/fb_custom_audience/recordTransform.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/v0/destinations/fb_custom_audience/recordTransform.js b/src/v0/destinations/fb_custom_audience/recordTransform.js index 9f48a37fca6..db1fbeec595 100644 --- a/src/v0/destinations/fb_custom_audience/recordTransform.js +++ b/src/v0/destinations/fb_custom_audience/recordTransform.js @@ -269,10 +269,11 @@ const processRecordInputsV2 = (groupedRecordInputs) => { function processRecordInputs(groupedRecordInputs) { const event = groupedRecordInputs[0]; - if (isEventSentByVDMV2Flow(event)) { - return processRecordInputsV2(groupedRecordInputs); + // First check for rETL flow and second check for ES flow + if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) { + return processRecordInputsV1(groupedRecordInputs); } - return processRecordInputsV1(groupedRecordInputs); + return processRecordInputsV2(groupedRecordInputs); } module.exports = { From 386d2ab88c0fe72dc47ba119be08ad1c0cd6d51b Mon Sep 17 00:00:00 2001 From: Akash Chetty Date: Tue, 24 Sep 2024 12:56:11 +0530 Subject: [PATCH 025/147] fix: allow users context traits and underscore divide numbers configuration (#3752) --- src/warehouse/index.js | 34 +- src/warehouse/snakecase/snakecase.js | 37 + src/warehouse/snakecase/unicodeWords.js | 94 ++ src/warehouse/util.js | 11 +- src/warehouse/v0/util.js | 87 -- src/warehouse/v1/util.js | 16 +- test/__tests__/data/warehouse/events.js | 28 +- .../warehouse/integration_options_events.js | 9 +- .../integrations/jsonpaths/legacy/aliases.js | 5 +- .../integrations/jsonpaths/legacy/extract.js | 5 +- .../integrations/jsonpaths/legacy/groups.js | 5 +- .../jsonpaths/legacy/identifies.js | 5 +- .../integrations/jsonpaths/legacy/pages.js | 5 +- .../integrations/jsonpaths/legacy/screens.js | 5 +- .../integrations/jsonpaths/legacy/tracks.js | 5 +- .../integrations/jsonpaths/new/aliases.js | 5 +- .../integrations/jsonpaths/new/extract.js | 5 +- .../integrations/jsonpaths/new/groups.js | 5 +- .../integrations/jsonpaths/new/identifies.js | 5 +- .../integrations/jsonpaths/new/pages.js | 5 +- .../integrations/jsonpaths/new/screens.js | 5 +- .../integrations/jsonpaths/new/tracks.js | 5 +- test/__tests__/snakecase.test.js | 497 +++++++++ test/__tests__/warehouse.test.js | 973 +++++++++++++++++- .../gcs_datalake/processor/data.ts | 2 + 25 files changed, 1697 insertions(+), 161 deletions(-) create mode 100644 src/warehouse/snakecase/snakecase.js create mode 100644 src/warehouse/snakecase/unicodeWords.js delete mode 100644 src/warehouse/v0/util.js create mode 100644 test/__tests__/snakecase.test.js diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 3c2b04079d9..54368da9fce 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -643,6 +643,18 @@ function processWarehouseMessage(message, options) { const skipReservedKeywordsEscaping = options.integrationOptions.skipReservedKeywordsEscaping || false; + // underscoreDivideNumbers when set to false, if a column has a format like "_v_3_", it will be formatted to "_v3_" + // underscoreDivideNumbers when set to true, if a column has a format like "_v_3_", we keep it like that + // For older destinations, it will come as true and for new destinations this config will not be present which means we will treat it as false. + options.underscoreDivideNumbers = options.destConfig?.underscoreDivideNumbers || false; + + // allowUsersContextTraits when set to true, if context.traits.* is present, it will be added as context_traits_* and *, + // e.g., for context.traits.name, context_traits_name and name will be added to the user's table. + // allowUsersContextTraits when set to false, if context.traits.* is present, it will be added only as context_traits_* + // e.g., for context.traits.name, only context_traits_name will be added to the user's table. + // For older destinations, it will come as true, and for new destinations this config will not be present, which means we will treat it as false. + const allowUsersContextTraits = options.destConfig?.allowUsersContextTraits || false; + addJsonKeysToOptions(options); if (isBlank(message.messageId)) { @@ -898,16 +910,18 @@ function processWarehouseMessage(message, options) { `${eventType + '_userProperties_'}`, 2, ); - setDataFromInputAndComputeColumnTypes( - utils, - eventType, - commonProps, - message.context ? message.context.traits : {}, - commonColumnTypes, - options, - `${eventType + '_context_traits_'}`, - 3, - ); + if (allowUsersContextTraits) { + setDataFromInputAndComputeColumnTypes( + utils, + eventType, + commonProps, + message.context ? message.context.traits : {}, + commonColumnTypes, + options, + `${eventType + '_context_traits_'}`, + 3, + ); + } setDataFromInputAndComputeColumnTypes( utils, eventType, diff --git a/src/warehouse/snakecase/snakecase.js b/src/warehouse/snakecase/snakecase.js new file mode 100644 index 00000000000..1e6586e7f25 --- /dev/null +++ b/src/warehouse/snakecase/snakecase.js @@ -0,0 +1,37 @@ +const { toString } = require('lodash'); +const { unicodeWords, unicodeWordsWithNumbers } = require('./unicodeWords'); + +const hasUnicodeWord = RegExp.prototype.test.bind( + /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/, +); + +/** Used to match words composed of alphanumeric characters. */ +// eslint-disable-next-line no-control-regex +const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + +function asciiWords(string) { + return string.match(reAsciiWord); +} + +function words(string) { + const result = hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string); + return result || []; +} + +function wordsWithNumbers(string) { + const result = hasUnicodeWord(string) ? unicodeWordsWithNumbers(string) : asciiWords(string); + return result || []; +} + +const snakeCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), + '', + ); +const snakeCaseWithNumbers = (string) => + wordsWithNumbers(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), + '', + ); + +module.exports = { words, wordsWithNumbers, snakeCase, snakeCaseWithNumbers }; diff --git a/src/warehouse/snakecase/unicodeWords.js b/src/warehouse/snakecase/unicodeWords.js new file mode 100644 index 00000000000..d7b15806c74 --- /dev/null +++ b/src/warehouse/snakecase/unicodeWords.js @@ -0,0 +1,94 @@ +/** Used to compose unicode character classes. */ +const rsAstralRange = '\\ud800-\\udfff'; +const rsComboMarksRange = '\\u0300-\\u036f'; +const reComboHalfMarksRange = '\\ufe20-\\ufe2f'; +const rsComboSymbolsRange = '\\u20d0-\\u20ff'; +const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff'; +const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff'; +const rsComboRange = + rsComboMarksRange + + reComboHalfMarksRange + + rsComboSymbolsRange + + rsComboMarksExtendedRange + + rsComboMarksSupplementRange; +const rsDingbatRange = '\\u2700-\\u27bf'; +const rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff'; +const rsMathOpRange = '\\xac\\xb1\\xd7\\xf7'; +const rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf'; +const rsPunctuationRange = '\\u2000-\\u206f'; +const rsSpaceRange = + ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000'; +const rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde'; +const rsVarRange = '\\ufe0e\\ufe0f'; +const rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + +/** Used to compose unicode capture groups. */ +const rsApos = "['\u2019]"; +const rsBreak = `[${rsBreakRange}]`; +const rsCombo = `[${rsComboRange}]`; +const rsDigit = '\\d'; +const rsDingbat = `[${rsDingbatRange}]`; +const rsLower = `[${rsLowerRange}]`; +const rsMisc = `[^${rsAstralRange}${rsBreakRange + rsDigit + rsDingbatRange + rsLowerRange + rsUpperRange}]`; +const rsFitz = '\\ud83c[\\udffb-\\udfff]'; +const rsModifier = `(?:${rsCombo}|${rsFitz})`; +const rsNonAstral = `[^${rsAstralRange}]`; +const rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}'; +const rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]'; +const rsUpper = `[${rsUpperRange}]`; +const rsZWJ = '\\u200d'; + +/** Used to compose unicode regexes. */ +const rsMiscLower = `(?:${rsLower}|${rsMisc})`; +const rsMiscUpper = `(?:${rsUpper}|${rsMisc})`; +const rsOptContrLower = `(?:${rsApos}(?:d|ll|m|re|s|t|ve))?`; +const rsOptContrUpper = `(?:${rsApos}(?:D|LL|M|RE|S|T|VE))?`; +const reOptMod = `${rsModifier}?`; +const rsOptVar = `[${rsVarRange}]?`; +const rsOptJoin = `(?:${rsZWJ}(?:${[rsNonAstral, rsRegional, rsSurrPair].join('|')})${rsOptVar + reOptMod})*`; +const rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])'; +const rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])'; +const rsSeq = rsOptVar + reOptMod + rsOptJoin; +const rsEmoji = `(?:${[rsDingbat, rsRegional, rsSurrPair].join('|')})${rsSeq}`; + +const reUnicodeWords = RegExp( + [ + `${rsUpper}?${rsLower}+${rsOptContrLower}(?=${[rsBreak, rsUpper, '$'].join('|')})`, // Regular words, lowercase letters followed by optional contractions + `${rsMiscUpper}+${rsOptContrUpper}(?=${[rsBreak, rsUpper + rsMiscLower, '$'].join('|')})`, // Miscellaneous uppercase characters with optional contractions + `${rsUpper}?${rsMiscLower}+${rsOptContrLower}`, // Miscellaneous lowercase sequences with optional contractions + `${rsUpper}+${rsOptContrUpper}`, // All uppercase words with optional contractions (e.g., "THIS") + rsOrdUpper, // Ordinals for uppercase (e.g., "1ST", "2ND") + rsOrdLower, // Ordinals for lowercase (e.g., "1st", "2nd") + `${rsDigit}+`, // Pure digits (e.g., "123") + rsEmoji, // Emojis (e.g., 😀, ❤️) + ].join('|'), + 'g', +); + +const reUnicodeWordsWithNumbers = RegExp( + [ + `${rsUpper}?${rsLower}+${rsDigit}+`, // Lowercase letters followed by digits (e.g., "abc123") + `${rsUpper}+${rsDigit}+`, // Uppercase letters followed by digits (e.g., "ABC123") + `${rsDigit}+${rsUpper}?${rsLower}+`, // Digits followed by lowercase letters (e.g., "123abc") + `${rsDigit}+${rsUpper}+`, // Digits followed by uppercase letters (e.g., "123ABC") + `${rsUpper}?${rsLower}+${rsOptContrLower}(?=${[rsBreak, rsUpper, '$'].join('|')})`, // Regular words, lowercase letters followed by optional contractions + `${rsMiscUpper}+${rsOptContrUpper}(?=${[rsBreak, rsUpper + rsMiscLower, '$'].join('|')})`, // Miscellaneous uppercase characters with optional contractions + `${rsUpper}?${rsMiscLower}+${rsOptContrLower}`, // Miscellaneous lowercase sequences with optional contractions + `${rsUpper}+${rsOptContrUpper}`, // All uppercase words with optional contractions (e.g., "THIS") + rsOrdUpper, // Ordinals for uppercase (e.g., "1ST", "2ND") + rsOrdLower, // Ordinals for lowercase (e.g., "1st", "2nd") + `${rsDigit}+`, // Pure digits (e.g., "123") + rsEmoji, // Emojis (e.g., 😀, ❤️) + ].join('|'), + 'g', +); + +function unicodeWords(string) { + return string.match(reUnicodeWords); +} + +function unicodeWordsWithNumbers(string) { + return string.match(reUnicodeWordsWithNumbers); +} + +module.exports = { unicodeWords, unicodeWordsWithNumbers }; diff --git a/src/warehouse/util.js b/src/warehouse/util.js index b4b22721fd3..7f4e224a349 100644 --- a/src/warehouse/util.js +++ b/src/warehouse/util.js @@ -1,7 +1,5 @@ -const _ = require('lodash'); const get = require('get-value'); -const v0 = require('./v0/util'); const v1 = require('./v1/util'); const { PlatformError, InstrumentationError } = require('@rudderstack/integrations-lib'); const { isBlank } = require('./config/helpers'); @@ -112,14 +110,7 @@ function validTimestamp(input) { } function getVersionedUtils(schemaVersion) { - switch (schemaVersion) { - case 'v0': - return v0; - case 'v1': - return v1; - default: - return v1; - } + return v1; } function isRudderSourcesEvent(event) { diff --git a/src/warehouse/v0/util.js b/src/warehouse/v0/util.js deleted file mode 100644 index 5917f8ea083..00000000000 --- a/src/warehouse/v0/util.js +++ /dev/null @@ -1,87 +0,0 @@ -const reservedANSIKeywordsMap = require('../config/ReservedKeywords.json'); -const { isDataLakeProvider } = require('../config/helpers'); - -const toSnakeCase = (str) => { - if (!str) { - return ''; - } - return String(str) - .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, '') - .replace(/([a-z])([A-Z])/g, (m, a, b) => `${a}_${b.toLowerCase()}`) - .replace(/[^A-Za-z0-9]+|_+/g, '_') - .toLowerCase(); -}; - -function toSafeDBString(provider, name = '') { - let parsedStr = name; - if (parseInt(name[0], 10) >= 0) { - parsedStr = `_${name}`; - } - parsedStr = parsedStr.replace(/[^a-zA-Z0-9_]+/g, ''); - if (isDataLakeProvider(provider)) { - return parsedStr; - } - switch (provider) { - case 'postgres': - return parsedStr.substr(0, 63); - default: - return parsedStr.substr(0, 127); - } -} - -function safeTableName(provider, name = '') { - let tableName = name; - if (tableName === '') { - tableName = 'STRINGEMPTY'; - } - if (provider === 'snowflake') { - tableName = tableName.toUpperCase(); - } - if (provider === 'rs' || isDataLakeProvider(provider)) { - tableName = tableName.toLowerCase(); - } - if (provider === 'postgres') { - tableName = tableName.substr(0, 63); - tableName = tableName.toLowerCase(); - } - if (reservedANSIKeywordsMap[provider.toUpperCase()][tableName.toUpperCase()]) { - tableName = `_${tableName}`; - } - return tableName; -} - -function safeColumnName(provider, name = '') { - let columnName = name; - if (columnName === '') { - columnName = 'STRINGEMPTY'; - } - if (provider === 'snowflake') { - columnName = columnName.toUpperCase(); - } - if (provider === 'rs' || isDataLakeProvider(provider)) { - columnName = columnName.toLowerCase(); - } - if (provider === 'postgres') { - columnName = columnName.substr(0, 63); - columnName = columnName.toLowerCase(); - } - if (reservedANSIKeywordsMap[provider.toUpperCase()][columnName.toUpperCase()]) { - columnName = `_${columnName}`; - } - return columnName; -} - -function transformTableName(name = '') { - return toSnakeCase(name); -} - -function transformColumnName(provider, name = '') { - return toSafeDBString(provider, name); -} - -module.exports = { - safeColumnName, - safeTableName, - transformColumnName, - transformTableName, -}; diff --git a/src/warehouse/v1/util.js b/src/warehouse/v1/util.js index 1c44a2385e9..d1289bc674f 100644 --- a/src/warehouse/v1/util.js +++ b/src/warehouse/v1/util.js @@ -1,8 +1,7 @@ -const _ = require('lodash'); - const reservedANSIKeywordsMap = require('../config/ReservedKeywords.json'); const { isDataLakeProvider } = require('../config/helpers'); const { TransformationError } = require('@rudderstack/integrations-lib'); +const { snakeCase, snakeCaseWithNumbers } = require('../snakecase/snakecase'); function safeTableName(options, name = '') { const { provider } = options; @@ -82,7 +81,7 @@ function safeColumnName(options, name = '') { path to $1,00,000 to path_to_1_00_000 return an empty string if it couldn't find a char if its ascii value doesnt belong to numbers or english alphabets */ -function transformName(provider, name = '') { +function transformName(options, provider, name = '') { const extractedValues = []; let extractedValue = ''; for (let i = 0; i < name.length; i += 1) { @@ -104,14 +103,17 @@ function transformName(provider, name = '') { if (extractedValue !== '') { extractedValues.push(extractedValue); } + const underscoreDivideNumbers = options?.underscoreDivideNumbers || false; + const snakeCaseFn = underscoreDivideNumbers ? snakeCase : snakeCaseWithNumbers; + let key = extractedValues.join('_'); if (name.startsWith('_')) { // do not remove leading underscores to allow esacaping rudder keywords with underscore // _timestamp -> _timestamp // __timestamp -> __timestamp - key = name.match(/^_*/)[0] + _.snakeCase(key.replace(/^_*/, '')); + key = name.match(/^_*/)[0] + snakeCaseFn(key.replace(/^_*/, '')); } else { - key = _.snakeCase(key); + key = snakeCaseFn(key); } if (key !== '' && key.charCodeAt(0) >= 48 && key.charCodeAt(0) <= 57) { @@ -150,7 +152,7 @@ function toBlendoCase(name = '') { function transformTableName(options, name = '') { const useBlendoCasing = options.integrationOptions?.useBlendoCasing || false; - return useBlendoCasing ? toBlendoCase(name) : transformName('', name); + return useBlendoCasing ? toBlendoCase(name) : transformName(options, '', name); } function transformColumnName(options, name = '') { @@ -158,7 +160,7 @@ function transformColumnName(options, name = '') { const useBlendoCasing = options.integrationOptions?.useBlendoCasing || false; return useBlendoCasing ? transformNameToBlendoCase(provider, name) - : transformName(provider, name); + : transformName(options, provider, name); } module.exports = { diff --git a/test/__tests__/data/warehouse/events.js b/test/__tests__/data/warehouse/events.js index ef9cc21096c..bca6f776be4 100644 --- a/test/__tests__/data/warehouse/events.js +++ b/test/__tests__/data/warehouse/events.js @@ -8,7 +8,9 @@ const sampleEvents = { Config: { restApiKey: "dummyApiKey", prefixProperties: true, - useNativeSDK: false + useNativeSDK: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, DestinationDefinition: { DisplayName: "Braze", @@ -514,7 +516,9 @@ const sampleEvents = { Config: { restApiKey: "dummyApiKey", prefixProperties: true, - useNativeSDK: false + useNativeSDK: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, DestinationDefinition: { DisplayName: "Braze", @@ -1026,7 +1030,9 @@ const sampleEvents = { Config: { restApiKey: "dummyApiKey", prefixProperties: true, - useNativeSDK: false + useNativeSDK: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, DestinationDefinition: { DisplayName: "Braze", @@ -1283,7 +1289,9 @@ const sampleEvents = { mapToSingleEvent: false, trackAllPages: false, trackCategorisedPages: true, - trackNamedPages: false + trackNamedPages: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, Enabled: true }, @@ -1532,7 +1540,9 @@ const sampleEvents = { mapToSingleEvent: false, trackAllPages: true, trackCategorisedPages: false, - trackNamedPages: false + trackNamedPages: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, Enabled: true }, @@ -1752,7 +1762,9 @@ const sampleEvents = { Config: { apiKey: "dummyApiKey", prefixProperties: true, - useNativeSDK: false + useNativeSDK: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, DestinationDefinition: { DisplayName: "Kiss Metrics", @@ -2016,7 +2028,9 @@ const sampleEvents = { Config: { restApiKey: "dummyApiKey", prefixProperties: true, - useNativeSDK: false + useNativeSDK: false, + allowUsersContextTraits: true, + underscoreDivideNumbers: true }, DestinationDefinition: { DisplayName: "Braze", diff --git a/test/__tests__/data/warehouse/integration_options_events.js b/test/__tests__/data/warehouse/integration_options_events.js index 05a2d51abdf..bb068d48575 100644 --- a/test/__tests__/data/warehouse/integration_options_events.js +++ b/test/__tests__/data/warehouse/integration_options_events.js @@ -20,7 +20,9 @@ const sampleEvents = { input: { destination: { Config: { - jsonPaths: " testMap.nestedMap, testArray" + jsonPaths: " testMap.nestedMap, testArray", + allowUsersContextTraits: true, + underscoreDivideNumbers: true } }, message: { @@ -731,7 +733,10 @@ const sampleEvents = { users: { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { type: "identify", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js index ee748a1a2b6..30cce51fb7d 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js index 906c3ada231..9d38ecc2929 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js index 13b243f3a7f..bbae993b27b 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js index 47b7f1209a9..14b01d4cdab 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { type: "identify", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js index 0aac8a3c236..dc2d3a3318d 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js index bad325c9084..9b789d27476 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js index 5070284e99d..691ce57ca15 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js index 91f19c5c77d..d5d57f85b9d 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js index 7a36e4787eb..a950b7f526f 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js index f84f9d33edb..6979aa11009 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js index 3d6164b430c..884770864a6 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { type: "identify", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js index 136f355b216..d5282c1cfd7 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js index b11b311ebbc..3eec47b89df 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js index 7ed95685ff2..6b411835dbf 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js @@ -1,7 +1,10 @@ module.exports = { input: { destination: { - Config: {} + Config: { + allowUsersContextTraits: true, + underscoreDivideNumbers: true + } }, message: { anonymousId: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", diff --git a/test/__tests__/snakecase.test.js b/test/__tests__/snakecase.test.js new file mode 100644 index 00000000000..146e2e53c63 --- /dev/null +++ b/test/__tests__/snakecase.test.js @@ -0,0 +1,497 @@ +const _ = require('lodash'); +const {words, wordsWithNumbers, snakeCase, snakeCaseWithNumbers} = require("../../src/warehouse/snakecase/snakecase"); + +const burredLetters = [ + // Latin-1 Supplement letters. + '\xc0', + '\xc1', + '\xc2', + '\xc3', + '\xc4', + '\xc5', + '\xc6', + '\xc7', + '\xc8', + '\xc9', + '\xca', + '\xcb', + '\xcc', + '\xcd', + '\xce', + '\xcf', + '\xd0', + '\xd1', + '\xd2', + '\xd3', + '\xd4', + '\xd5', + '\xd6', + '\xd8', + '\xd9', + '\xda', + '\xdb', + '\xdc', + '\xdd', + '\xde', + '\xdf', + '\xe0', + '\xe1', + '\xe2', + '\xe3', + '\xe4', + '\xe5', + '\xe6', + '\xe7', + '\xe8', + '\xe9', + '\xea', + '\xeb', + '\xec', + '\xed', + '\xee', + '\xef', + '\xf0', + '\xf1', + '\xf2', + '\xf3', + '\xf4', + '\xf5', + '\xf6', + '\xf8', + '\xf9', + '\xfa', + '\xfb', + '\xfc', + '\xfd', + '\xfe', + '\xff', + // Latin Extended-A letters. + '\u0100', + '\u0101', + '\u0102', + '\u0103', + '\u0104', + '\u0105', + '\u0106', + '\u0107', + '\u0108', + '\u0109', + '\u010a', + '\u010b', + '\u010c', + '\u010d', + '\u010e', + '\u010f', + '\u0110', + '\u0111', + '\u0112', + '\u0113', + '\u0114', + '\u0115', + '\u0116', + '\u0117', + '\u0118', + '\u0119', + '\u011a', + '\u011b', + '\u011c', + '\u011d', + '\u011e', + '\u011f', + '\u0120', + '\u0121', + '\u0122', + '\u0123', + '\u0124', + '\u0125', + '\u0126', + '\u0127', + '\u0128', + '\u0129', + '\u012a', + '\u012b', + '\u012c', + '\u012d', + '\u012e', + '\u012f', + '\u0130', + '\u0131', + '\u0132', + '\u0133', + '\u0134', + '\u0135', + '\u0136', + '\u0137', + '\u0138', + '\u0139', + '\u013a', + '\u013b', + '\u013c', + '\u013d', + '\u013e', + '\u013f', + '\u0140', + '\u0141', + '\u0142', + '\u0143', + '\u0144', + '\u0145', + '\u0146', + '\u0147', + '\u0148', + '\u0149', + '\u014a', + '\u014b', + '\u014c', + '\u014d', + '\u014e', + '\u014f', + '\u0150', + '\u0151', + '\u0152', + '\u0153', + '\u0154', + '\u0155', + '\u0156', + '\u0157', + '\u0158', + '\u0159', + '\u015a', + '\u015b', + '\u015c', + '\u015d', + '\u015e', + '\u015f', + '\u0160', + '\u0161', + '\u0162', + '\u0163', + '\u0164', + '\u0165', + '\u0166', + '\u0167', + '\u0168', + '\u0169', + '\u016a', + '\u016b', + '\u016c', + '\u016d', + '\u016e', + '\u016f', + '\u0170', + '\u0171', + '\u0172', + '\u0173', + '\u0174', + '\u0175', + '\u0176', + '\u0177', + '\u0178', + '\u0179', + '\u017a', + '\u017b', + '\u017c', + '\u017d', + '\u017e', + '\u017f', +]; +const emojiVar = '\ufe0f'; +const flag = '\ud83c\uddfa\ud83c\uddf8'; +const heart = `\u2764${emojiVar}`; +const hearts = '\ud83d\udc95'; +const comboGlyph = `\ud83d\udc68\u200d${heart}\u200d\ud83d\udc8B\u200d\ud83d\udc68`; +const leafs = '\ud83c\udf42'; +const rocket = '\ud83d\ude80'; +const stubTrue = function () { + return true; +}; +const stubString = function () { + return ''; +}; + +describe('words', () => { + it('should match words containing Latin Unicode letters', () => { + const expected = _.map(burredLetters, (letter) => [letter]); + const actual = _.map(burredLetters, (letter) => words(letter)); + expect(actual).toEqual(expected); + }); + + it('should work with compound words', () => { + expect(words('12ft')).toEqual(['12', 'ft']); + expect(words('aeiouAreVowels')).toEqual(['aeiou', 'Are', 'Vowels']); + expect(words('enable 6h format')).toEqual(['enable', '6', 'h', 'format']); + expect(words('enable 24H format')).toEqual(['enable', '24', 'H', 'format']); + expect(words('isISO8601')).toEqual(['is', 'ISO', '8601']); + expect(words('LETTERSAeiouAreVowels')).toEqual(['LETTERS', 'Aeiou', 'Are', 'Vowels']); + expect(words('tooLegit2Quit')).toEqual(['too', 'Legit', '2', 'Quit']); + expect(words('walk500Miles')).toEqual(['walk', '500', 'Miles']); + expect(words('xhr2Request')).toEqual(['xhr', '2', 'Request']); + expect(words('XMLHttp')).toEqual(['XML', 'Http']); + expect(words('XmlHTTP')).toEqual(['Xml', 'HTTP']); + expect(words('XmlHttp')).toEqual(['Xml', 'Http']); + }); + + it('should work with compound words containing diacritical marks', () => { + expect(words('LETTERSÆiouAreVowels')).toEqual(['LETTERS', 'Æiou', 'Are', 'Vowels']); + expect(words('æiouAreVowels')).toEqual(['æiou', 'Are', 'Vowels']); + expect(words('æiou2Consonants')).toEqual(['æiou', '2', 'Consonants']); + }); + + it('should not treat contractions as separate words', () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + _.each(["'", '\u2019'], (apos) => { + _.times(2, (index) => { + const actual = _.map(postfixes, (postfix) => { + const string = `a b${apos}${postfix} c`; + return words(string[index ? 'toUpperCase' : 'toLowerCase']()); + }); + const expected = _.map(postfixes, (postfix) => { + const words = ['a', `b${apos}${postfix}`, 'c']; + return _.map(words, (word) => + word[index ? 'toUpperCase' : 'toLowerCase'](), + ); + }); + expect(actual).toEqual(expected); + }); + }); + }); + + it('should not treat ordinal numbers as separate words', () => { + const ordinals = ['1st', '2nd', '3rd', '4th']; + + _.times(2, (index) => { + const expected = _.map(ordinals, (ordinal) => [ + ordinal[index ? 'toUpperCase' : 'toLowerCase'](), + ]); + const actual = _.map(expected, (expectedWords) => words(expectedWords[0])); + expect(actual).toEqual(expected); + }); + }); + + it('should prevent ReDoS', () => { + const largeWordLen = 50000; + const largeWord = 'A'.repeat(largeWordLen); + const maxMs = 1000; + const startTime = _.now(); + + expect(words(`${largeWord}ÆiouAreVowels`)).toEqual([largeWord, 'Æiou', 'Are', 'Vowels']); + + const endTime = _.now(); + const timeSpent = endTime - startTime; + + expect(timeSpent).toBeLessThan(maxMs); + }); + + it('should account for astral symbols', () => { + const string = `A ${leafs}, ${comboGlyph}, and ${rocket}`; + expect(words(string)).toEqual(['A', leafs, comboGlyph, 'and', rocket]); + }); + + it('should account for regional symbols', () => { + const pair = flag.match(/\ud83c[\udde6-\uddff]/g); + const regionals = pair.join(' '); + + expect(words(flag)).toEqual([flag]); + expect(words(regionals)).toEqual([pair[0], pair[1]]); + }); + + it('should account for variation selectors', () => { + expect(words(heart)).toEqual([heart]); + }); + + it('should match lone surrogates', () => { + const pair = hearts.split(''); + const surrogates = `${pair[0]} ${pair[1]}`; + + expect(words(surrogates)).toEqual([]); + }); +}); + +describe('wordsWithoutNumbers', () => { + it('should match words containing Latin Unicode letters', () => { + const expected = _.map(burredLetters, (letter) => [letter]); + const actual = _.map(burredLetters, (letter) => wordsWithNumbers(letter)); + expect(actual).toEqual(expected); + }); + + it('should work with compound words', () => { + expect(wordsWithNumbers('12ft')).toEqual(['12ft']); + expect(wordsWithNumbers('aeiouAreVowels')).toEqual(['aeiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('enable 6h format')).toEqual(['enable', '6h', 'format']); + expect(wordsWithNumbers('enable 24H format')).toEqual(['enable', '24H', 'format']); + expect(wordsWithNumbers('isISO8601')).toEqual(['is', 'ISO8601']); + expect(wordsWithNumbers('LETTERSAeiouAreVowels')).toEqual(['LETTERS', 'Aeiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('tooLegit2Quit')).toEqual(['too', 'Legit2', 'Quit']); + expect(wordsWithNumbers('walk500Miles')).toEqual(['walk500', 'Miles']); + expect(wordsWithNumbers('xhr2Request')).toEqual(['xhr2', 'Request']); + expect(wordsWithNumbers('XMLHttp')).toEqual(['XML', 'Http']); + expect(wordsWithNumbers('XmlHTTP')).toEqual(['Xml', 'HTTP']); + expect(wordsWithNumbers('XmlHttp')).toEqual(['Xml', 'Http']); + }); + + it('should work with compound words containing diacritical marks', () => { + expect(wordsWithNumbers('LETTERSÆiouAreVowels')).toEqual(['LETTERS', 'Æiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('æiouAreVowels')).toEqual(['æiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('æiou2Consonants')).toEqual(['æiou2', 'Consonants']); + }); + + it('should not treat contractions as separate words', () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + _.each(["'", '\u2019'], (apos) => { + _.times(2, (index) => { + const actual = _.map(postfixes, (postfix) => { + const string = `a b${apos}${postfix} c`; + return wordsWithNumbers(string[index ? 'toUpperCase' : 'toLowerCase']()); + }); + const expected = _.map(postfixes, (postfix) => { + const words = ['a', `b${apos}${postfix}`, 'c']; + return _.map(words, (word) => + word[index ? 'toUpperCase' : 'toLowerCase'](), + ); + }); + expect(actual).toEqual(expected); + }); + }); + }); + + it('should not treat ordinal numbers as separate words', () => { + const ordinals = ['1st', '2nd', '3rd', '4th']; + + _.times(2, (index) => { + const expected = _.map(ordinals, (ordinal) => [ + ordinal[index ? 'toUpperCase' : 'toLowerCase'](), + ]); + const actual = _.map(expected, (expectedWords) => wordsWithNumbers(expectedWords[0])); + expect(actual).toEqual(expected); + }); + }); + + it('should prevent ReDoS', () => { + const largeWordLen = 50000; + const largeWord = 'A'.repeat(largeWordLen); + const maxMs = 1000; + const startTime = _.now(); + + expect(wordsWithNumbers(`${largeWord}ÆiouAreVowels`)).toEqual([largeWord, 'Æiou', 'Are', 'Vowels']); + + const endTime = _.now(); + const timeSpent = endTime - startTime; + + expect(timeSpent).toBeLessThan(maxMs); + }); + + it('should account for astral symbols', () => { + const string = `A ${leafs}, ${comboGlyph}, and ${rocket}`; + expect(wordsWithNumbers(string)).toEqual(['A', leafs, comboGlyph, 'and', rocket]); + }); + + it('should account for regional symbols', () => { + const pair = flag.match(/\ud83c[\udde6-\uddff]/g); + const regionals = pair.join(' '); + + expect(wordsWithNumbers(flag)).toEqual([flag]); + expect(wordsWithNumbers(regionals)).toEqual([pair[0], pair[1]]); + }); + + it('should account for variation selectors', () => { + expect(wordsWithNumbers(heart)).toEqual([heart]); + }); + + it('should match lone surrogates', () => { + const pair = hearts.split(''); + const surrogates = `${pair[0]} ${pair[1]}`; + + expect(wordsWithNumbers(surrogates)).toEqual([]); + }); +}); + +describe('snakeCase snakeCaseWithNumbers', () => { + const caseMethods = { + snakeCase, + snakeCaseWithNumbers, + }; + + _.each(['snakeCase', 'snakeCaseWithNumbers'], (caseName) => { + const methodName = caseName; + const func = caseMethods[methodName]; + + const strings = [ + 'foo bar', + 'Foo bar', + 'foo Bar', + 'Foo Bar', + 'FOO BAR', + 'fooBar', + '--foo-bar--', + '__foo_bar__', + ]; + + const converted = (function () { + switch (caseName) { + case 'snakeCase': + return 'foo_bar'; + case 'snakeCaseWithNumbers': + return 'foo_bar'; + } + })(); + + it(`\`_.${methodName}\` should convert \`string\` to ${caseName} case`, () => { + const actual = _.map(strings, (string) => { + const expected = caseName === 'start' && string === 'FOO BAR' ? string : converted; + return func(string) === expected; + }); + expect(actual).toEqual(_.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should handle double-converting strings`, () => { + const actual = _.map(strings, (string) => { + const expected = caseName === 'start' && string === 'FOO BAR' ? string : converted; + return func(func(string)) === expected; + }); + expect(actual).toEqual(_.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should remove contraction apostrophes`, () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + _.each(["'", '\u2019'], (apos) => { + const actual = _.map(postfixes, (postfix) => + func(`a b${apos}${postfix} c`), + ); + const expected = _.map(postfixes, (postfix) => { + switch (caseName) { + case 'snakeCase': + return `a_b${postfix}_c`; + case 'snakeCaseWithNumbers': + return `a_b${postfix}_c`; + } + }); + expect(actual).toEqual(expected); + }); + }); + + it(`\`_.${methodName}\` should remove Latin mathematical operators`, () => { + const actual = _.map(['\xd7', '\xf7'], func); + expect(actual).toEqual(['', '']); + }); + + it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => { + const string = 'foo bar'; + expect(func(Object(string))).toBe(converted); + expect(func({toString: _.constant(string)})).toBe(converted); + }); + + it(`\`_.${methodName}\` should return an empty string for empty values`, () => { + const values = [, null, undefined, '']; + const expected = _.map(values, stubString); + + const actual = _.map(values, (value, index) => + index ? func(value) : func(), + ); + + expect(actual).toEqual(expected); + }); + }); +}); \ No newline at end of file diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 83b24aee159..9099566c602 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1,7 +1,5 @@ const _ = require("lodash"); -const util = require("util"); - const { input, output } = require(`./data/warehouse/events.js`); const { opInput, @@ -21,6 +19,7 @@ const { const { validTimestamp } = require("../../src/warehouse/util.js"); +const {transformTableName, transformColumnName} = require("../../src/warehouse/v1/util"); const {isBlank} = require("../../src/warehouse/config/helpers.js"); const version = "v0"; @@ -1010,28 +1009,6 @@ describe("Add receivedAt for events missing it", () => { }); describe("Integration options", () => { - describe("Destination config options", () => { - destConfig.scenarios().forEach(scenario => { - it(scenario.name, () => { - if (scenario.skipUsersTable !== null) { - scenario.event.destination.Config.skipUsersTable = scenario.skipUsersTable - } - if (scenario.skipTracksTable !== null) { - scenario.event.destination.Config.skipTracksTable = scenario.skipTracksTable - } - - transformers.forEach((transformer, index) => { - const received = transformer.process(scenario.event); - expect(received).toHaveLength(scenario.expected.length); - for (const i in received) { - const evt = received[i]; - expect(evt.data.id ? evt.data.id : evt.data.ID).toEqual(scenario.expected[i].id); - expect(evt.metadata.table.toLowerCase()).toEqual(scenario.expected[i].table); - } - }); - }); - }); - }); describe("track", () => { it("should generate two events for every track call", () => { const i = opInput("track"); @@ -1235,6 +1212,306 @@ describe("isBlank", () => { } }); +describe("Destination config", () => { + describe("skipUsersTable, skipTracksTable", () => { + destConfig.scenarios().forEach(scenario => { + it(scenario.name, () => { + if (scenario.skipUsersTable !== null) { + scenario.event.destination.Config.skipUsersTable = scenario.skipUsersTable + } + if (scenario.skipTracksTable !== null) { + scenario.event.destination.Config.skipTracksTable = scenario.skipTracksTable + } + + transformers.forEach((transformer, index) => { + const received = transformer.process(scenario.event); + expect(received).toHaveLength(scenario.expected.length); + for (const i in received) { + const evt = received[i]; + expect(evt.data.id ? evt.data.id : evt.data.ID).toEqual(scenario.expected[i].id); + expect(evt.metadata.table.toLowerCase()).toEqual(scenario.expected[i].table); + } + }); + }); + }); + }); + + describe('allowUsersContextTraits, underscoreDivideNumbers', () => { + describe("old destinations", () => { + it('with allowUsersContextTraits', () => { + transformers.forEach((transformer, index) => { + const event = { + destination: { + Config: { + allowUsersContextTraits: true + } + }, + message: { + context: { + traits: { + city: "Disney", + country: "USA", + email: "mickey@disney.com", + firstname: "Mickey" + }, + }, + traits: { + lastname: "Mouse" + }, + type: "identify", + userId: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + request: { + query: { + whSchemaVersion: "v1" + } + } + } + const output = transformer.process(event); + const events = [output[0], output[1]]; // identifies and users event + const traitsToCheck = { + 'city': 'Disney', + 'country': 'USA', + 'email': 'mickey@disney.com', + 'firstname': 'Mickey' + }; + events.forEach(event => { + Object.entries(traitsToCheck).forEach(([trait, value]) => { + expect(event.data[integrationCasedString(integrations[index], trait)]).toEqual(value); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); + }); + }); + }); + }); + + it('with underscoreDivideNumbers', () => { + transformers.forEach((transformer, index) => { + const event = { + destination: { + Config: { + underscoreDivideNumbers: true + }, + }, + message: { + context: { + 'attribute v3': 'some-value' + }, + event: "button clicked v2", + type: "track", + }, + request: { + query: { + whSchemaVersion: "v1" + } + } + } + const output = transformer.process(event); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v_2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); + }); + }); + }); + describe("new destinations", () => { + it('without allowUsersContextTraits', () => { + transformers.forEach((transformer, index) => { + const event = { + destination: { + Config: {} + }, + message: { + context: { + traits: { + city: "Disney", + country: "USA", + email: "mickey@disney.com", + firstname: "Mickey" + }, + }, + traits: { + lastname: "Mouse" + }, + type: "identify", + userId: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + request: { + query: { + whSchemaVersion: "v1" + } + } + } + const received = transformer.process(event); + const events = [received[0], received[1]]; // identifies and users event + const traitsToCheck = { + 'city': 'Disney', + 'country': 'USA', + 'email': 'mickey@disney.com', + 'firstname': 'Mickey' + }; + events.forEach(event => { + Object.entries(traitsToCheck).forEach(([trait, value]) => { + expect(event.data).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); + }); + }); + }); + }); + + it('without underscoreDivideNumbers', () => { + transformers.forEach((transformer, index) => { + const event = { + destination: { + Config: {}, + }, + message: { + context: { + 'attribute v3': 'some-value' + }, + event: "button clicked v2", + type: "track", + }, + request: { + query: { + whSchemaVersion: "v1" + } + } + } + const output = transformer.process(event); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); + }); + }); + }); + }); +}); + +describe("validTimestamp", () => { + const testCases = [ + { + name: "undefined input should return false", + input: undefined, + expected: false, + }, + { + name: "negative year and time input should return false #1", + input: '-0001-11-30T00:00:00+0000', + expected: false, + }, + { + name: "negative year and time input should return false #2", + input: '-2023-06-14T05:23:59.244Z', + expected: false, + }, + { + name: "negative year and time input should return false #3", + input: '-1900-06-14T05:23:59.244Z', + expected: false, + }, + { + name: "positive year and time input should return false", + input: '+2023-06-14T05:23:59.244Z', + expected: false, + }, + { + name: "valid timestamp input should return true", + input: '2023-06-14T05:23:59.244Z', + expected: true, + }, + { + name: "non-date string input should return false", + input: 'abc', + expected: false, + }, + { + name: "malicious string input should return false", + input: '%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216%u002e%u002e%u2216Windows%u2216win%u002ein', + expected: false, + }, + { + name: "empty string input should return false", + input: '', + expected: false, + }, + { + name: "valid date input should return true", + input: '2023-06-14', + expected: true, + }, + { + name: "time-only input should return false", + input: '05:23:59.244Z', + expected: false, + }, + { + name: "non-string input should return false", + input: {abc: 123}, + expected: false, + }, + { + name: "object with toString method input should return false", + input: { + toString: '2023-06-14T05:23:59.244Z' + }, + expected: false, + }, + ]; + for (const testCase of testCases) { + it(`should return ${testCase.expected} for ${testCase.name}`, () => { + expect(validTimestamp(testCase.input)).toEqual(testCase.expected); + }); + } +}); + +describe("isBlank", () => { + const testCases = [ + { + name: "null", + input: null, + expected: true + }, + { + name: "empty string", + input: "", + expected: true + }, + { + name: "non-empty string", + input: "test", + expected: false + }, + { + name: "numeric value", + input: 1634762544, + expected: false + }, + { + name: "object with toString property", + input: { + toString: '2023-06-14T05:23:59.244Z' + }, + expected: false + }, + ]; + for (const testCase of testCases) { + it(`should return ${testCase.expected} for ${testCase.name}`, () => { + expect(isBlank(testCase.input)).toEqual(testCase.expected); + }); + } +}); + describe("context traits", () => { const testCases = [ { @@ -1421,3 +1698,651 @@ describe("group traits", () => { }); } }) + +describe("transformColumnName", () => { + describe('with Blendo Casing', () => { + const testCases = [ + { + description: 'should convert special characters other than "\\" or "$" to underscores', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'column@Name$1', + expected: 'column_name$1', + }, + { + description: 'should add underscore if name does not start with an alphabet or underscore', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: '1CComega', + expected: '_1ccomega', + }, + { + description: 'should handle non-ASCII characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'Cízǔ', + expected: 'c_z_', + }, + { + description: 'should transform CamelCase123Key to camelcase123key', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'CamelCase123Key', + expected: 'camelcase123key', + }, + { + description: 'should preserve "\\" and "$" characters', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'path to $1,00,000', + expected: 'path_to_$1_00_000', + }, + { + description: 'should handle a mix of characters, numbers, and special characters', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'CamelCase123Key_with$special\\chars', + expected: 'camelcase123key_with$special\\chars', + }, + { + description: 'should limit length to 63 characters for postgres provider', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'a'.repeat(70), + expected: 'a'.repeat(63), + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); + }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=true)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4_yasdfa_84224_fs_9_3_q', + }, + { + description: 'should transform "omega" to "omega"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega v2', + expected: 'omega_v_2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '9mega', + expected: '_9_mega', + }, + { + description: 'should remove trailing special characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '9mega________-________90', + expected: '_9_mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'CamelCase123Key', + expected: 'camel_case_123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'test123', + expected: 'test_123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'abc123def456', + expected: 'abc_123_def_456', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'abc_123_def_456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); + }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=false)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4yasdfa_84224_fs9_3q', + }, + { + description: 'should transform "omega" to "omega"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'omega v2', + expected: 'omega_v2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '9mega', + expected: '_9mega', + }, + { + description: 'should remove trailing special characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '9mega________-________90', + expected: '_9mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'CamelCase123Key', + expected: 'camel_case123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'test123', + expected: 'test123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'abc123def456', + expected: 'abc123_def456', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'abc_123_def_456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); + }); + }); +}) + +describe("transformTableName", () => { + describe('with Blendo Casing', () => { + const testCases = [ + { + description: 'should convert name to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'TableName123', + expected: 'tablename123', + }, + { + description: 'should trim spaces and convert to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: ' TableName ', + expected: 'tablename', + }, + { + description: 'should return an empty string when input is empty and Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: '', + expected: '', + }, + { + description: 'should handle names with special characters and convert to Blendo casing (lowercase)', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'Table@Name!', + expected: 'table@name!', + }, + { + description: 'should convert a mixed-case name to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'CaMeLcAsE', + expected: 'camelcase', + }, + { + description: 'should keep an already lowercase name unchanged with Blendo casing enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'lowercase', + expected: 'lowercase', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); + }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=true)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4_yasdfa_84224_fs_9_3_q', + }, + { + description: 'should transform "omega" to "omega"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega v2', + expected: 'omega_v_2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '9mega', + expected: '_9_mega', + }, + { + description: 'should remove trailing special characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '9mega________-________90', + expected: '_9_mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'CamelCase123Key', + expected: 'camel_case_123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'test123', + expected: 'test_123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'abc123def456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); + }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=false)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4yasdfa_84224_fs9_3q', + }, + { + description: 'should transform "omega" to "omega"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'omega v2', + expected: 'omega_v2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '9mega', + expected: '_9mega', + }, + { + description: 'should remove trailing special characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '9mega________-________90', + expected: '_9mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'CamelCase123Key', + expected: 'camel_case123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'test123', + expected: 'test123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'abc123def456', + expected: 'abc123_def456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/integrations/destinations/gcs_datalake/processor/data.ts b/test/integrations/destinations/gcs_datalake/processor/data.ts index 46c77887091..26f438758d6 100644 --- a/test/integrations/destinations/gcs_datalake/processor/data.ts +++ b/test/integrations/destinations/gcs_datalake/processor/data.ts @@ -62,6 +62,8 @@ export const data = [ syncFrequency: '30', tableSuffix: '', timeWindowLayout: '2006/01/02/15', + allowUsersContextTraits: true, + underscoreDivideNumbers: true, }, Enabled: true, }, From f50effeeabdb888f82451c225a80971dbe6532b6 Mon Sep 17 00:00:00 2001 From: Akash Chetty Date: Tue, 24 Sep 2024 12:59:41 +0530 Subject: [PATCH 026/147] fix: populate users fields for sentAt, timestamp and originalTimestamp (#3753) --- src/warehouse/index.js | 14 +- .../warehouse/integration_options_events.js | 278 ++++++++++++++++++ .../jsonpaths/legacy/identifies.js | 174 +++++++++++ .../integrations/jsonpaths/new/identifies.js | 174 +++++++++++ test/__tests__/warehouse.test.js | 14 +- 5 files changed, 650 insertions(+), 4 deletions(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 54368da9fce..4afa8f72c2d 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -1001,11 +1001,23 @@ function processWarehouseMessage(message, options) { const usersEvent = { ...commonProps }; const usersColumnTypes = {}; + let userColumnMappingRules = whUserColumnMappingRules; + if (!isDataLakeProvider(options.provider)) { + userColumnMappingRules = { + ...userColumnMappingRules, + ...{ + sent_at: 'sentAt', + timestamp: 'timestamp', + original_timestamp: 'originalTimestamp', + }, + }; + } + setDataFromColumnMappingAndComputeColumnTypes( utils, usersEvent, message, - whUserColumnMappingRules, + userColumnMappingRules, usersColumnTypes, options, ); diff --git a/test/__tests__/data/warehouse/integration_options_events.js b/test/__tests__/data/warehouse/integration_options_events.js index bb068d48575..35eafb6a9ba 100644 --- a/test/__tests__/data/warehouse/integration_options_events.js +++ b/test/__tests__/data/warehouse/integration_options_events.js @@ -885,6 +885,9 @@ const sampleEvents = { "email": "user123@email.com", "id": "user123", "phone": "+917836362334", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "received_at": "2020-01-24T06:29:02.403Z" }, "metadata": { @@ -911,6 +914,9 @@ const sampleEvents = { "id": "string", "phone": "string", "received_at": "datetime", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -1079,6 +1085,9 @@ const sampleEvents = { "email": "user123@email.com", "id": "user123", "phone": "+917836362334", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "received_at": "2020-01-24T06:29:02.403Z" }, "metadata": { @@ -1106,6 +1115,9 @@ const sampleEvents = { "loaded_at": "datetime", "phone": "string", "received_at": "datetime", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -1204,6 +1216,9 @@ const sampleEvents = { "EMAIL": "user123@email.com", "ID": "user123", "PHONE": "+917836362334", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", "RECEIVED_AT": "2020-01-24T06:29:02.403Z" }, "metadata": { @@ -1230,6 +1245,9 @@ const sampleEvents = { "ID": "string", "PHONE": "string", "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "ORIGINAL_TIMESTAMP": "datetime", "UUID_TS": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -1360,6 +1378,254 @@ const sampleEvents = { "table": "users" } } + ], + gcs_datalake: [ + { + "data": { + "timestamp": "2020-01-24T06:29:02.403Z", + "anonymous_id": "97c46c81-3140-456d-b2a9-690d70aaca35", + "channel": "web", + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "email": "user123@email.com", + "id": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "user_id": "user123" + }, + "metadata": { + "columns": { + "timestamp": "datetime", + "anonymous_id": "string", + "channel": "string", + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "email": "string", + "id": "string", + "original_timestamp": "datetime", + "phone": "string", + "received_at": "datetime", + "sent_at": "datetime", + "user_id": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "identifies" + } + }, + { + "data": { + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "email": "user123@email.com", + "id": "user123", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z" + }, + "metadata": { + "columns": { + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "email": "string", + "id": "string", + "phone": "string", + "received_at": "datetime", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "users" + } + } + ], + azure_datalake: [ + { + "data": { + "timestamp": "2020-01-24T06:29:02.403Z", + "anonymous_id": "97c46c81-3140-456d-b2a9-690d70aaca35", + "channel": "web", + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "email": "user123@email.com", + "id": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "user_id": "user123" + }, + "metadata": { + "columns": { + "timestamp": "datetime", + "anonymous_id": "string", + "channel": "string", + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "email": "string", + "id": "string", + "original_timestamp": "datetime", + "phone": "string", + "received_at": "datetime", + "sent_at": "datetime", + "user_id": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "identifies" + } + }, + { + "data": { + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "email": "user123@email.com", + "id": "user123", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z" + }, + "metadata": { + "columns": { + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "email": "string", + "id": "string", + "phone": "string", + "received_at": "datetime", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "users" + } + } ] } } @@ -1379,6 +1645,18 @@ function opOutput(eventType, provider) { return _.cloneDeep(sampleEvents[eventType].output.rs); case "bq": return _.cloneDeep(sampleEvents[eventType].output.bq); + case "gcs_datalake": + if (eventType === 'users') { + return _.cloneDeep(sampleEvents[eventType].output.gcs_datalake); + } else { + return _.cloneDeep(sampleEvents[eventType].output.default); + } + case "azure_datalake": + if (eventType === 'users') { + return _.cloneDeep(sampleEvents[eventType].output.azure_datalake); + } else { + return _.cloneDeep(sampleEvents[eventType].output.default); + } default: return _.cloneDeep(sampleEvents[eventType].output.default); } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js index 14b01d4cdab..42f5cccf49a 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js @@ -233,6 +233,9 @@ module.exports = { "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", "t_map_nested_map_n_1": "nested prop 1", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "up_map_nested_map_n_1": "nested prop 1" }, "metadata": { @@ -264,6 +267,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map_n_1": "string", "up_map_nested_map_n_1": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -377,6 +383,9 @@ module.exports = { "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", "t_map_nested_map_n_1": "nested prop 1", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "up_map_nested_map_n_1": "nested prop 1" }, "metadata": { @@ -408,6 +417,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map_n_1": "string", "up_map_nested_map_n_1": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -522,6 +534,9 @@ module.exports = { "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", "t_map_nested_map_n_1": "nested prop 1", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "up_map_nested_map_n_1": "nested prop 1" }, "metadata": { @@ -554,6 +569,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map_n_1": "string", "up_map_nested_map_n_1": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -667,6 +685,9 @@ module.exports = { "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", "t_map_nested_map_n_1": "nested prop 1", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "up_map_nested_map_n_1": "nested prop 1" }, "metadata": { @@ -698,6 +719,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map_n_1": "string", "up_map_nested_map_n_1": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -811,6 +835,9 @@ module.exports = { "PHONE": "+917836362334", "RECEIVED_AT": "2020-01-24T06:29:02.403Z", "T_MAP_NESTED_MAP_N_1": "nested prop 1", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", "UP_MAP_NESTED_MAP_N_1": "nested prop 1" }, "metadata": { @@ -842,6 +869,9 @@ module.exports = { "RECEIVED_AT": "datetime", "T_MAP_NESTED_MAP_N_1": "string", "UP_MAP_NESTED_MAP_N_1": "string", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "ORIGINAL_TIMESTAMP": "datetime", "UUID_TS": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -849,5 +879,149 @@ module.exports = { } } ], + datalake: [ + { + "data": { + "anonymous_id": "97c46c81-3140-456d-b2a9-690d70aaca35", + "channel": "web", + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_c_map_nested_map_n_1": "context nested prop 1", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_ct_map_nested_map_n_1": "nested prop 1", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "ct_map_nested_map_n_1": "nested prop 1", + "email": "user123@email.com", + "id": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "t_map_nested_map_n_1": "nested prop 1", + "timestamp": "2020-01-24T06:29:02.403Z", + "up_map_nested_map_n_1": "nested prop 1", + "user_id": "user123" + }, + "metadata": { + "columns": { + "anonymous_id": "string", + "channel": "string", + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_c_map_nested_map_n_1": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_ct_map_nested_map_n_1": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "ct_map_nested_map_n_1": "string", + "email": "string", + "id": "string", + "original_timestamp": "datetime", + "phone": "string", + "received_at": "datetime", + "sent_at": "datetime", + "t_map_nested_map_n_1": "string", + "timestamp": "datetime", + "up_map_nested_map_n_1": "string", + "user_id": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "identifies" + } + }, + { + "data": { + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_c_map_nested_map_n_1": "context nested prop 1", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_ct_map_nested_map_n_1": "nested prop 1", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "ct_map_nested_map_n_1": "nested prop 1", + "email": "user123@email.com", + "id": "user123", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "t_map_nested_map_n_1": "nested prop 1", + "up_map_nested_map_n_1": "nested prop 1" + }, + "metadata": { + "columns": { + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_c_map_nested_map_n_1": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_ct_map_nested_map_n_1": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "ct_map_nested_map_n_1": "string", + "email": "string", + "id": "string", + "phone": "string", + "received_at": "datetime", + "t_map_nested_map_n_1": "string", + "up_map_nested_map_n_1": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "users" + } + } + ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js index 884770864a6..89fcc23cd5c 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js @@ -233,6 +233,9 @@ module.exports = { "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", "t_map_nested_map_n_1": "nested prop 1", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "up_map_nested_map_n_1": "nested prop 1" }, "metadata": { @@ -264,6 +267,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map_n_1": "string", "up_map_nested_map_n_1": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -376,6 +382,9 @@ module.exports = { "id": "user123", "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "t_map_nested_map": "{\"n1\":\"nested prop 1\"}", "up_map_nested_map": "{\"n1\":\"nested prop 1\"}" }, @@ -408,6 +417,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map": "json", "up_map_nested_map": "json", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -521,6 +533,9 @@ module.exports = { "id": "user123", "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "t_map_nested_map": "{\"n1\":\"nested prop 1\"}", "up_map_nested_map": "{\"n1\":\"nested prop 1\"}" }, @@ -554,6 +569,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map": "string", "up_map_nested_map": "string", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -666,6 +684,9 @@ module.exports = { "id": "user123", "phone": "+917836362334", "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "timestamp": "2020-01-24T06:29:02.403Z", "t_map_nested_map": "{\"n1\":\"nested prop 1\"}", "up_map_nested_map": "{\"n1\":\"nested prop 1\"}" }, @@ -698,6 +719,9 @@ module.exports = { "received_at": "datetime", "t_map_nested_map": "json", "up_map_nested_map": "json", + "sent_at": "datetime", + "timestamp": "datetime", + "original_timestamp": "datetime", "uuid_ts": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -810,6 +834,9 @@ module.exports = { "ID": "user123", "PHONE": "+917836362334", "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", "T_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}" }, @@ -842,6 +869,9 @@ module.exports = { "RECEIVED_AT": "datetime", "T_MAP_NESTED_MAP": "json", "UP_MAP_NESTED_MAP": "json", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "ORIGINAL_TIMESTAMP": "datetime", "UUID_TS": "datetime" }, "receivedAt": "2020-01-24T11:59:02.403+05:30", @@ -849,5 +879,149 @@ module.exports = { } } ], + datalake: [ + { + "data": { + "anonymous_id": "97c46c81-3140-456d-b2a9-690d70aaca35", + "channel": "web", + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_c_map_nested_map_n_1": "context nested prop 1", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_ct_map_nested_map_n_1": "nested prop 1", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "ct_map_nested_map_n_1": "nested prop 1", + "email": "user123@email.com", + "id": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "original_timestamp": "2020-01-24T06:29:02.364Z", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "sent_at": "2021-01-03T17:02:53.195Z", + "t_map_nested_map_n_1": "nested prop 1", + "timestamp": "2020-01-24T06:29:02.403Z", + "up_map_nested_map_n_1": "nested prop 1", + "user_id": "user123" + }, + "metadata": { + "columns": { + "anonymous_id": "string", + "channel": "string", + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_c_map_nested_map_n_1": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_ct_map_nested_map_n_1": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "ct_map_nested_map_n_1": "string", + "email": "string", + "id": "string", + "original_timestamp": "datetime", + "phone": "string", + "received_at": "datetime", + "sent_at": "datetime", + "t_map_nested_map_n_1": "string", + "timestamp": "datetime", + "up_map_nested_map_n_1": "string", + "user_id": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "identifies" + } + }, + { + "data": { + "context_app_build": "1.0.0", + "context_app_name": "RudderLabs JavaScript SDK", + "context_app_namespace": "com.rudderlabs.javascript", + "context_app_version": "1.1.11", + "context_c_map_nested_map_n_1": "context nested prop 1", + "context_device_id": "id", + "context_device_token": "token", + "context_device_type": "ios", + "context_ip": "[::1]:53708", + "context_library_name": "RudderLabs JavaScript SDK", + "context_library_version": "1.1.11", + "context_locale": "en-US", + "context_os_name": "android", + "context_os_version": "1.12.3", + "context_request_ip": "[::1]:53708", + "context_traits_ct_map_nested_map_n_1": "nested prop 1", + "context_traits_email": "user123@email.com", + "context_traits_phone": "+917836362334", + "context_traits_user_id": "user123", + "context_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "ct_map_nested_map_n_1": "nested prop 1", + "email": "user123@email.com", + "id": "user123", + "phone": "+917836362334", + "received_at": "2020-01-24T06:29:02.403Z", + "t_map_nested_map_n_1": "nested prop 1", + "up_map_nested_map_n_1": "nested prop 1" + }, + "metadata": { + "columns": { + "context_app_build": "string", + "context_app_name": "string", + "context_app_namespace": "string", + "context_app_version": "string", + "context_c_map_nested_map_n_1": "string", + "context_device_id": "string", + "context_device_token": "string", + "context_device_type": "string", + "context_ip": "string", + "context_library_name": "string", + "context_library_version": "string", + "context_locale": "string", + "context_os_name": "string", + "context_os_version": "string", + "context_request_ip": "string", + "context_traits_ct_map_nested_map_n_1": "string", + "context_traits_email": "string", + "context_traits_phone": "string", + "context_traits_user_id": "string", + "context_user_agent": "string", + "ct_map_nested_map_n_1": "string", + "email": "string", + "id": "string", + "phone": "string", + "received_at": "datetime", + "t_map_nested_map_n_1": "string", + "up_map_nested_map_n_1": "string", + "uuid_ts": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "users" + } + } + ], } } diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 9099566c602..6bde2e9eb22 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -1035,7 +1035,7 @@ describe("Integration options", () => { }); describe("json paths", () => { - const output = (config, provider) => { + const output = (eventType, config, provider) => { switch (provider) { case "rs": return _.cloneDeep(config.output.rs); @@ -1045,6 +1045,14 @@ describe("Integration options", () => { return _.cloneDeep(config.output.postgres); case "snowflake": return _.cloneDeep(config.output.snowflake); + case "s3_datalake": + case "gcs_datalake": + case "azure_datalake": + if (eventType === 'identifies') { + return _.cloneDeep(config.output.datalake); + } else { + return _.cloneDeep(config.output.default); + } default: return _.cloneDeep(config.output.default); } @@ -1080,14 +1088,14 @@ describe("Integration options", () => { const config = require("./data/warehouse/integrations/jsonpaths/new/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(config, integrations[index])); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) it(`legacy ${testCase.eventType} for ${integrations[index]}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/legacy/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(config, integrations[index])); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) }); } From c6a2344b9960043b9a5ad12ffea28d253499ac0e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 24 Sep 2024 08:03:32 +0000 Subject: [PATCH 027/147] chore(release): 1.79.1 --- CHANGELOG.md | 10 ++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c860747b6f7..854f45b096c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.79.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.0...v1.79.1) (2024-09-24) + + +### Bug Fixes + +* allow users context traits and underscore divide numbers configuration ([#3752](https://github.com/rudderlabs/rudder-transformer/issues/3752)) ([386d2ab](https://github.com/rudderlabs/rudder-transformer/commit/386d2ab88c0fe72dc47ba119be08ad1c0cd6d51b)) +* populate users fields for sentAt, timestamp and originalTimestamp ([#3753](https://github.com/rudderlabs/rudder-transformer/issues/3753)) ([f50effe](https://github.com/rudderlabs/rudder-transformer/commit/f50effeeabdb888f82451c225a80971dbe6532b6)) +* prefer event check vs config check for vdm ([#3754](https://github.com/rudderlabs/rudder-transformer/issues/3754)) ([b2c1a18](https://github.com/rudderlabs/rudder-transformer/commit/b2c1a1893dfb957ac7a24c000b33cd254ef54b6c)) +* support different lookup fields and custom_attributes for rETL events ([#3751](https://github.com/rudderlabs/rudder-transformer/issues/3751)) ([10d914e](https://github.com/rudderlabs/rudder-transformer/commit/10d914e25203bd6ae95801c2a98c17690bd2d6ef)) + ## [1.79.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.78.0...v1.79.0) (2024-09-20) diff --git a/package-lock.json b/package-lock.json index 98bc41379e4..ae018a5ec94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.79.0", + "version": "1.79.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.79.0", + "version": "1.79.1", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index c598db805ce..ede36441eb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.79.0", + "version": "1.79.1", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From e82d6c7e5655f3c37581e8ce7087d1931879e730 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:10:24 +0530 Subject: [PATCH 028/147] chore: refactor common server side logic for both app flows (#3760) --- .../shopify/pixelWebhookEventTransform.js | 88 ------------------- src/v1/sources/shopify/transform.js | 32 +++---- .../shopify/v1ServerSideEventsTests.ts | 12 ++- 3 files changed, 15 insertions(+), 117 deletions(-) delete mode 100644 src/v1/sources/shopify/pixelWebhookEventTransform.js diff --git a/src/v1/sources/shopify/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js deleted file mode 100644 index 43b741f8372..00000000000 --- a/src/v1/sources/shopify/pixelWebhookEventTransform.js +++ /dev/null @@ -1,88 +0,0 @@ -const lodash = require('lodash'); -const get = require('get-value'); -const { isDefinedNotNullNotEmpty } = require('@rudderstack/integrations-lib'); -const stats = require('../../../util/stats'); -const { getShopifyTopic, extractEmailFromPayload } = require('../../../v0/sources/shopify/util'); -const { - identifyPayloadBuilder, - trackPayloadBuilder, - ecomPayloadBuilder, -} = require('../../../v0/sources/shopify/transform'); -const { removeUndefinedAndNullValues, generateUUID } = require('../../../v0/util'); -const Message = require('../../../v0/sources/message'); -const { - INTEGERATION, - IDENTIFY_TOPICS, - ECOM_TOPICS, - SUPPORTED_TRACK_EVENTS, -} = require('../../../v0/sources/shopify/config'); - -const NO_OPERATION_SUCCESS = { - outputToSource: { - body: Buffer.from('OK').toString('base64'), - contentType: 'text/plain', - }, - statusCode: 200, -}; - -const processPixelWebhookEvent = async (inputEvent, metricMetadata) => { - let message = new Message(INTEGERATION); - const event = lodash.cloneDeep(inputEvent); - const shopifyTopic = getShopifyTopic(event); - delete event.query_parameters; - switch (shopifyTopic) { - case IDENTIFY_TOPICS.CUSTOMERS_CREATE: - case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: - message = identifyPayloadBuilder(event); - break; - case ECOM_TOPICS.ORDERS_CREATE: - case ECOM_TOPICS.ORDERS_UPDATE: - case ECOM_TOPICS.CHECKOUTS_CREATE: - case ECOM_TOPICS.CHECKOUTS_UPDATE: - message = ecomPayloadBuilder(event, shopifyTopic); - break; - case 'carts_update': - message = trackPayloadBuilder(event, shopifyTopic); - break; - default: - if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { - stats.increment('invalid_shopify_event', { - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - shopifyTopic: metricMetadata.shopifyTopic, - }); - return NO_OPERATION_SUCCESS; - } - message = trackPayloadBuilder(event, shopifyTopic); - break; - } - - if (event.customer && isDefinedNotNullNotEmpty(event?.customer?.id)) { - message.userId = String(event.customer.id); - } - message.anonymousId = generateUUID(); - - if (!get(message, 'traits.email')) { - const email = extractEmailFromPayload(event); - if (email) { - message.setProperty('traits.email', email); - } - } - message.setProperty(`integrations.${INTEGERATION}`, true); - message.setProperty('context.library', { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'server', - version: '2.0.0', - }); - message.setProperty('context.topic', shopifyTopic); - // attaching cart, checkout and order tokens in context object - message.setProperty(`context.cart_token`, event.cart_token); - message.setProperty(`context.checkout_token`, event.checkout_token); - if (shopifyTopic === 'orders_updated') { - message.setProperty(`context.order_token`, event.token); - } - message = removeUndefinedAndNullValues(message); - return message; -}; - -module.exports = { processPixelWebhookEvent }; diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index ff9aadbca42..dee5a14a9df 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -1,32 +1,20 @@ /* eslint-disable @typescript-eslint/naming-convention */ -const { isDefinedAndNotNull } = require('../../../v0/util'); const { processEventFromPixel } = require('./pixelTransform'); -const { processPixelWebhookEvent } = require('./pixelWebhookEventTransform'); -const { process: processLegacyEvents } = require('../../../v0/sources/shopify/transform'); +const { process: processWebhookEvents } = require('../../../v0/sources/shopify/transform'); const process = async (inputEvent) => { - const { event, source } = inputEvent; - const metricMetadata = { - // eslint-disable-next-line unicorn/consistent-destructuring - writeKey: source?.WriteKey || event.query_parameters?.writeKey?.[0], - sourceId: source?.ID, - source: 'SHOPIFY', - }; + const { event } = inputEvent; // check on the source Config to identify the event is from the tracker-based (legacy) // or the pixel-based (latest) implementation. - if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'pixel') { - const { pixelEventLabel: pixelClientEventLabel } = event; - if (pixelClientEventLabel) { - // this is a event fired from the web pixel loaded on the browser - // by the user interactions with the store. - const responseV2 = await processEventFromPixel(event); - return responseV2; - } - const webhookEventResponse = await processPixelWebhookEvent(event, metricMetadata, source); - return webhookEventResponse; + const { pixelEventLabel: pixelClientEventLabel } = event; + if (pixelClientEventLabel) { + // this is a event fired from the web pixel loaded on the browser + // by the user interactions with the store. + const responseV2 = await processEventFromPixel(event); + return responseV2; } - // this is for default legacy tracker based server-side events processing - const response = await processLegacyEvents(event); + // this is for common logic for server-side events processing for both pixel and tracker apps. + const response = await processWebhookEvents(event); return response; }; diff --git a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts index a91a2138731..2c323cb370d 100644 --- a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts +++ b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts @@ -2,7 +2,7 @@ // the v1 transformation flow import utils from '../../../../src/v0/util'; const defaultMockFns = () => { - jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); + jest.spyOn(utils, 'generateUUID').mockReturnValue('5d3e2cb6-4011-5c9c-b7ee-11bc1e905097'); }; import { dummySourceConfig } from './constants'; @@ -207,8 +207,7 @@ export const v1ServerSideEventsScenarios = [ context: { library: { name: 'RudderStack Shopify Cloud', - eventOrigin: 'server', - version: '2.0.0', + version: '1.0.0', }, integration: { name: 'SHOPIFY', @@ -367,7 +366,7 @@ export const v1ServerSideEventsScenarios = [ }, }, timestamp: '2024-09-17T07:29:02.000Z', - anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', }, ], }, @@ -491,8 +490,7 @@ export const v1ServerSideEventsScenarios = [ context: { library: { name: 'RudderStack Shopify Cloud', - eventOrigin: 'server', - version: '2.0.0', + version: '1.0.0', }, integration: { name: 'SHOPIFY', @@ -583,7 +581,7 @@ export const v1ServerSideEventsScenarios = [ }, ], }, - anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', }, ], }, From 7fa7c8d3a4f6aefb580cf0de2e64e2f8aef5b5ce Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Fri, 27 Sep 2024 10:56:09 +0530 Subject: [PATCH 029/147] fix: payment info entered event in facebook_conversions (#3762) * fix: payment info entered event in facebook_conversions * fix: logic to get products - updated test-cases - added products added to wishlist to get products function * chore: add without products test-case for payment info entered --------- Co-authored-by: Sai Sankeerth --- .../facebook_conversions/utils.js | 27 +++- .../facebook_conversions/processor/data.ts | 143 +++++++++++++++++- 2 files changed, 160 insertions(+), 10 deletions(-) diff --git a/src/v0/destinations/facebook_conversions/utils.js b/src/v0/destinations/facebook_conversions/utils.js index 87fb0ea6061..9119bfdca54 100644 --- a/src/v0/destinations/facebook_conversions/utils.js +++ b/src/v0/destinations/facebook_conversions/utils.js @@ -79,16 +79,31 @@ const validateProductSearchedData = (eventTypeCustomData) => { } }; +const getProducts = (message, category) => { + let products = message.properties?.products; + if (['product added', 'product viewed', 'products searched'].includes(category.type)) { + return [message.properties]; + } + if ( + ['payment info entered', 'product added to wishlist'].includes(category.type) && + !Array.isArray(products) + ) { + products = [message.properties]; + } + return products; +}; + const populateCustomDataBasedOnCategory = (customData, message, category, categoryToContent) => { let eventTypeCustomData = {}; if (category.name) { eventTypeCustomData = constructPayload(message, MAPPING_CONFIG[category.name]); } + const products = getProducts(message, category); switch (category.type) { case 'product list viewed': { const { contentIds, contents } = populateContentsAndContentIDs( - message.properties?.products, + products, message.properties?.quantity, ); @@ -119,9 +134,7 @@ const populateCustomDataBasedOnCategory = (customData, message, category, catego } case 'product added': case 'product viewed': - case 'products searched': - case 'payment info entered': - case 'product added to wishlist': { + case 'products searched': { const contentCategory = eventTypeCustomData.content_category; const contentType = message.properties?.content_type || @@ -131,7 +144,7 @@ const populateCustomDataBasedOnCategory = (customData, message, category, catego categoryToContent, DESTINATION.toLowerCase(), ); - const { contentIds, contents } = populateContentsAndContentIDs([message.properties]); + const { contentIds, contents } = populateContentsAndContentIDs(products); eventTypeCustomData = { ...eventTypeCustomData, content_ids: contentIds.length === 1 ? contentIds[0] : contentIds, @@ -142,10 +155,12 @@ const populateCustomDataBasedOnCategory = (customData, message, category, catego validateProductSearchedData(eventTypeCustomData); break; } + case 'payment info entered': + case 'product added to wishlist': case 'order completed': case 'checkout started': { const { contentIds, contents } = populateContentsAndContentIDs( - message.properties?.products, + products, message.properties?.quantity, message.properties?.delivery_category, ); diff --git a/test/integrations/destinations/facebook_conversions/processor/data.ts b/test/integrations/destinations/facebook_conversions/processor/data.ts index d72114c15be..49d2416726c 100644 --- a/test/integrations/destinations/facebook_conversions/processor/data.ts +++ b/test/integrations/destinations/facebook_conversions/processor/data.ts @@ -1045,7 +1045,7 @@ export const data = [ JSON_ARRAY: {}, FORM: { data: [ - '{"user_data":{"em":"48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08","zp":"03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"},"event_name":"AddToWishlist","event_time":1699784211,"action_source":"website","custom_data":{"revenue":400,"additional_bet_index":0,"content_ids":[],"contents":[],"currency":"USD","value":400}}', + '{"user_data":{"em":"48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08","zp":"03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"},"event_name":"AddToWishlist","event_time":1699784211,"action_source":"website","custom_data":{"revenue":400,"additional_bet_index":0,"content_ids":[],"contents":[],"currency":"USD","value":400,"num_items":0}}', ], }, }, @@ -1104,8 +1104,143 @@ export const data = [ }, message_id: 'a80f82be-9bdc-4a9f-b2a5-15621ee41df8', properties: { - revenue: 400, - additional_bet_index: 0, + application_tracking_enabled: 1, + content_name: 'Checkout', + content_type: 'product', + num_items: 1, + products: [ + { + id: '12809', + price: 80, + quantity: 1, + }, + ], + revenue: 93.99, + }, + timestamp: '2023-11-12T15:46:51.693229+05:30', + type: 'track', + }, + destination: { + Config: { + limitedDataUsage: true, + blacklistPiiProperties: [ + { + blacklistPiiProperties: '', + blacklistPiiHash: false, + }, + ], + accessToken: '09876', + datasetId: 'dummyID', + eventsToEvents: [ + { + from: '', + to: '', + }, + ], + eventCustomProperties: [ + { + eventCustomProperties: '', + }, + ], + removeExternalId: true, + whitelistPiiProperties: [ + { + whitelistPiiProperties: '', + }, + ], + actionSource: 'website', + }, + Enabled: true, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://graph.facebook.com/v20.0/dummyID/events?access_token=09876', + headers: {}, + params: {}, + body: { + JSON: {}, + XML: {}, + JSON_ARRAY: {}, + FORM: { + data: [ + '{"user_data":{"em":"48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08","zp":"03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"},"event_name":"AddPaymentInfo","event_time":1699784211,"action_source":"website","custom_data":{"application_tracking_enabled":1,"content_name":"Checkout","content_type":"product","num_items":1,"products":[{"id":"12809","price":80,"quantity":1}],"revenue":93.99,"content_ids":["12809"],"contents":[{"id":"12809","quantity":1,"item_price":80}],"currency":"USD","value":93.99}}', + ], + }, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + name: 'facebook_conversions', + description: 'Track event with standard event payment info entered without products', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + channel: 'web', + context: { + device: { + id: 'df16bffa-5c3d-4fbb-9bce-3bab098129a7R', + manufacturer: 'Xiaomi', + model: 'Redmi 6', + name: 'xiaomi', + }, + network: { + carrier: 'Banglalink', + }, + os: { + name: 'android', + version: '8.1.0', + }, + screen: { + height: '100', + density: 50, + }, + traits: { + email: ' aBc@gmail.com ', + address: { + zip: 1234, + }, + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + }, + }, + event: 'payment info entered', + integrations: { + All: true, + }, + message_id: 'a80f82be-9bdc-4a9f-b2a5-15621ee41df8', + properties: { + application_tracking_enabled: 1, + content_name: 'Checkout', + content_type: 'product', + num_items: 1, + id: '12809', + price: 80, + quantity: 1, + revenue: 93.99, }, timestamp: '2023-11-12T15:46:51.693229+05:30', type: 'track', @@ -1164,7 +1299,7 @@ export const data = [ JSON_ARRAY: {}, FORM: { data: [ - '{"user_data":{"em":"48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08","zp":"03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"},"event_name":"AddPaymentInfo","event_time":1699784211,"action_source":"website","custom_data":{"revenue":400,"additional_bet_index":0,"content_ids":[],"contents":[],"currency":"USD","value":400}}', + '{"user_data":{"em":"48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08","zp":"03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"},"event_name":"AddPaymentInfo","event_time":1699784211,"action_source":"website","custom_data":{"application_tracking_enabled":1,"content_name":"Checkout","content_type":"product","num_items":1,"id":"12809","price":80,"quantity":1,"revenue":93.99,"content_ids":["12809"],"contents":[{"id":"12809","quantity":1,"item_price":80}],"currency":"USD","value":93.99}}', ], }, }, From 6f92bd31b60caaa07d18bb86ce5939cd7cc9a416 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:28:52 +0530 Subject: [PATCH 030/147] fix: correct typo for order fulfillment event, add test (#3764) --- src/v0/sources/shopify/config.js | 4 +- test/integrations/sources/shopify/data.ts | 821 ++++++++++++++++++++++ 2 files changed, 823 insertions(+), 2 deletions(-) diff --git a/src/v0/sources/shopify/config.js b/src/v0/sources/shopify/config.js index a5ededf9da9..7f5d41ec964 100644 --- a/src/v0/sources/shopify/config.js +++ b/src/v0/sources/shopify/config.js @@ -35,7 +35,7 @@ const SHOPIFY_TRACK_MAP = { orders_cancelled: 'Order Cancelled', orders_fulfilled: 'Order Fulfilled', orders_paid: 'Order Paid', - orders_partially_fullfilled: 'Order Partially Fulfilled', + orders_partially_fulfilled: 'Order Partially Fulfilled', // following are the events that supported by rudderstack pixel app as generic track events customer_tags_added: 'Customer Tags Added', customer_tags_removed: 'Customer Tags Removed', @@ -125,7 +125,7 @@ const SUPPORTED_TRACK_EVENTS = [ 'orders_cancelled', 'orders_fulfilled', 'orders_paid', - 'orders_partially_fullfilled', + 'orders_partially_fulfilled', // following are the events that supported by rudderstack pixel app as generic track events 'customer_tags_added', 'customer_tags_removed', diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index 7a74bc4d06a..a2b27cbbccd 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -610,6 +610,827 @@ const serverSideEventsScenarios = [ }, }, }, + { + name: 'shopify', + description: 'Track Call -> Order Partially Fulfilled event', + module: 'source', + version: 'v0', + input: { + request: { + body: [ + { + query_parameters: { + topic: ['orders_partially_fulfilled'], + writeKey: ['sample-write-key'], + signature: ['rudderstack'], + }, + id: 820982911946154508, + admin_graphql_api_id: 'gid://shopify/Order/820982911946154508', + app_id: null, + browser_ip: null, + buyer_accepts_marketing: true, + cancel_reason: 'customer', + cancelled_at: '2021-12-31T19:00:00-05:00', + cart_token: null, + checkout_id: null, + checkout_token: null, + client_details: null, + closed_at: null, + confirmation_number: null, + confirmed: false, + contact_email: 'jon@example.com', + created_at: '2021-12-31T19:00:00-05:00', + currency: 'USD', + current_subtotal_price: '398.00', + current_subtotal_price_set: { + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + current_total_additional_fees_set: null, + current_total_discounts: '0.00', + current_total_discounts_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + current_total_duties_set: null, + current_total_price: '398.00', + current_total_price_set: { + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + current_total_tax: '0.00', + current_total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + customer_locale: 'en', + device_id: null, + discount_codes: [], + email: 'jon@example.com', + estimated_taxes: false, + financial_status: 'voided', + fulfillment_status: 'pending', + landing_site: null, + landing_site_ref: null, + location_id: null, + merchant_of_record_app_id: null, + name: '#9999', + note: null, + note_attributes: [], + number: 234, + order_number: 1234, + order_status_url: + 'https://jsmith.myshopify.com/548380009/orders/123456abcd/authenticate?key=abcdefg', + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['visa', 'bogus'], + phone: null, + po_number: null, + presentment_currency: 'USD', + processed_at: '2021-12-31T19:00:00-05:00', + reference: null, + referring_site: null, + source_identifier: null, + source_name: 'web', + source_url: null, + subtotal_price: '388.00', + subtotal_price_set: { + shop_money: { + amount: '388.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '388.00', + currency_code: 'USD', + }, + }, + tags: 'tag1, tag2', + tax_exempt: false, + tax_lines: [], + taxes_included: false, + test: true, + token: '123456abcd', + total_discounts: '20.00', + total_discounts_set: { + shop_money: { + amount: '20.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '20.00', + currency_code: 'USD', + }, + }, + total_line_items_price: '398.00', + total_line_items_price_set: { + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + total_outstanding: '398.00', + total_price: '388.00', + total_price_set: { + shop_money: { + amount: '388.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '388.00', + currency_code: 'USD', + }, + }, + total_shipping_price_set: { + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + total_tax: '0.00', + total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_tip_received: '0.00', + total_weight: 0, + updated_at: '2021-12-31T19:00:00-05:00', + user_id: null, + billing_address: { + first_name: 'Steve', + address1: '123 Shipping Street', + phone: '555-555-SHIP', + city: 'Shippington', + zip: '40003', + province: 'Kentucky', + country: 'United States', + last_name: 'Shipper', + address2: null, + company: 'Shipping Company', + latitude: null, + longitude: null, + name: 'Steve Shipper', + country_code: 'US', + province_code: 'KY', + }, + customer: { + id: 115310627314723954, + email: 'john@example.com', + created_at: null, + updated_at: null, + first_name: 'John', + last_name: 'Smith', + state: 'disabled', + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: null, + consent_updated_at: null, + }, + sms_marketing_consent: null, + tags: '', + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/115310627314723954', + default_address: { + id: 715243470612851245, + customer_id: 115310627314723954, + first_name: null, + last_name: null, + company: null, + address1: '123 Elm St.', + address2: null, + city: 'Ottawa', + province: 'Ontario', + country: 'Canada', + zip: 'K2H7A8', + phone: '123-123-1234', + name: '', + province_code: 'ON', + country_code: 'CA', + country_name: 'Canada', + default: true, + }, + }, + discount_applications: [], + fulfillments: [], + line_items: [ + { + id: 866550311766439020, + admin_graphql_api_id: 'gid://shopify/LineItem/866550311766439020', + attributed_staffs: [ + { + id: 'gid://shopify/StaffMember/902541635', + quantity: 1, + }, + ], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 567, + name: 'IPod Nano - 8GB', + price: '199.00', + price_set: { + shop_money: { + amount: '199.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '199.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 632910392, + properties: [], + quantity: 1, + requires_shipping: true, + sku: 'IPOD2008PINK', + taxable: true, + title: 'IPod Nano - 8GB', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 808950810, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: null, + tax_lines: [], + duties: [], + discount_allocations: [], + }, + { + id: 141249953214522974, + admin_graphql_api_id: 'gid://shopify/LineItem/141249953214522974', + attributed_staffs: [], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 567, + name: 'IPod Nano - 8GB', + price: '199.00', + price_set: { + shop_money: { + amount: '199.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '199.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 632910392, + properties: [], + quantity: 1, + requires_shipping: true, + sku: 'IPOD2008PINK', + taxable: true, + title: 'IPod Nano - 8GB', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 808950810, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: null, + tax_lines: [], + duties: [], + discount_allocations: [], + }, + ], + payment_terms: null, + refunds: [], + shipping_address: { + first_name: 'Steve', + address1: '123 Shipping Street', + phone: '555-555-SHIP', + city: 'Shippington', + zip: '40003', + province: 'Kentucky', + country: 'United States', + last_name: 'Shipper', + address2: null, + company: 'Shipping Company', + latitude: null, + longitude: null, + name: 'Steve Shipper', + country_code: 'US', + province_code: 'KY', + }, + shipping_lines: [ + { + id: 271878346596884015, + carrier_identifier: null, + code: null, + discounted_price: '10.00', + discounted_price_set: { + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + is_removed: false, + phone: null, + price: '10.00', + price_set: { + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + requested_fulfillment_service_id: null, + source: 'shopify', + title: 'Generic Shipping', + tax_lines: [], + discount_allocations: [], + }, + ], + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + cart_token: null, + checkout_token: null, + integration: { + name: 'SHOPIFY', + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '1.0.0', + }, + topic: 'orders_partially_fulfilled', + }, + event: 'Order Partially Fulfilled', + integrations: { + SHOPIFY: true, + }, + properties: { + admin_graphql_api_id: 'gid://shopify/Order/820982911946154508', + app_id: null, + browser_ip: null, + buyer_accepts_marketing: true, + cancel_reason: 'customer', + cancelled_at: '2021-12-31T19:00:00-05:00', + cart_token: null, + checkout_id: null, + checkout_token: null, + client_details: null, + closed_at: null, + confirmation_number: null, + confirmed: false, + contact_email: 'jon@example.com', + created_at: '2021-12-31T19:00:00-05:00', + currency: 'USD', + current_subtotal_price: '398.00', + current_subtotal_price_set: { + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + current_total_additional_fees_set: null, + current_total_discounts: '0.00', + current_total_discounts_set: { + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + current_total_duties_set: null, + current_total_price: '398.00', + current_total_price_set: { + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + current_total_tax: '0.00', + current_total_tax_set: { + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + customer_locale: 'en', + device_id: null, + discount_applications: [], + discount_codes: [], + email: 'jon@example.com', + estimated_taxes: false, + financial_status: 'voided', + fulfillment_status: 'pending', + fulfillments: [], + id: 820982911946154500, + landing_site: null, + landing_site_ref: null, + location_id: null, + merchant_of_record_app_id: null, + name: '#9999', + note: null, + note_attributes: [], + number: 234, + order_number: 1234, + order_status_url: + 'https://jsmith.myshopify.com/548380009/orders/123456abcd/authenticate?key=abcdefg', + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['visa', 'bogus'], + payment_terms: null, + phone: null, + po_number: null, + presentment_currency: 'USD', + processed_at: '2021-12-31T19:00:00-05:00', + products: [ + { + admin_graphql_api_id: 'gid://shopify/LineItem/866550311766439020', + attributed_staffs: [ + { + id: 'gid://shopify/StaffMember/902541635', + quantity: 1, + }, + ], + current_quantity: 1, + discount_allocations: [], + duties: [], + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 567, + id: 866550311766439000, + price: '199.00', + price_set: { + presentment_money: { + amount: '199.00', + currency_code: 'USD', + }, + shop_money: { + amount: '199.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 632910392, + properties: [], + quantity: 1, + requires_shipping: true, + sku: 'IPOD2008PINK', + tax_lines: [], + taxable: true, + title: 'IPod Nano - 8GB', + total_discount: '0.00', + total_discount_set: { + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant: '808950810 ', + variant_inventory_management: 'shopify', + }, + { + admin_graphql_api_id: 'gid://shopify/LineItem/141249953214522974', + attributed_staffs: [], + current_quantity: 1, + discount_allocations: [], + duties: [], + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 567, + id: 141249953214522980, + price: '199.00', + price_set: { + presentment_money: { + amount: '199.00', + currency_code: 'USD', + }, + shop_money: { + amount: '199.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 632910392, + properties: [], + quantity: 1, + requires_shipping: true, + sku: 'IPOD2008PINK', + tax_lines: [], + taxable: true, + title: 'IPod Nano - 8GB', + total_discount: '0.00', + total_discount_set: { + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant: '808950810 ', + variant_inventory_management: 'shopify', + }, + ], + reference: null, + referring_site: null, + refunds: [], + shipping_lines: [ + { + carrier_identifier: null, + code: null, + discount_allocations: [], + discounted_price: '10.00', + discounted_price_set: { + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + id: 271878346596884000, + is_removed: false, + phone: null, + price: '10.00', + price_set: { + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + requested_fulfillment_service_id: null, + source: 'shopify', + tax_lines: [], + title: 'Generic Shipping', + }, + ], + source_identifier: null, + source_name: 'web', + source_url: null, + subtotal_price: '388.00', + subtotal_price_set: { + presentment_money: { + amount: '388.00', + currency_code: 'USD', + }, + shop_money: { + amount: '388.00', + currency_code: 'USD', + }, + }, + tags: 'tag1, tag2', + tax_exempt: false, + tax_lines: [], + taxes_included: false, + test: true, + token: '123456abcd', + total_discounts: '20.00', + total_discounts_set: { + presentment_money: { + amount: '20.00', + currency_code: 'USD', + }, + shop_money: { + amount: '20.00', + currency_code: 'USD', + }, + }, + total_line_items_price: '398.00', + total_line_items_price_set: { + presentment_money: { + amount: '398.00', + currency_code: 'USD', + }, + shop_money: { + amount: '398.00', + currency_code: 'USD', + }, + }, + total_outstanding: '398.00', + total_price: '388.00', + total_price_set: { + presentment_money: { + amount: '388.00', + currency_code: 'USD', + }, + shop_money: { + amount: '388.00', + currency_code: 'USD', + }, + }, + total_shipping_price_set: { + presentment_money: { + amount: '10.00', + currency_code: 'USD', + }, + shop_money: { + amount: '10.00', + currency_code: 'USD', + }, + }, + total_tax: '0.00', + total_tax_set: { + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_tip_received: '0.00', + total_weight: 0, + updated_at: '2021-12-31T19:00:00-05:00', + user_id: null, + }, + traits: { + address: { + address1: '123 Elm St.', + address2: null, + city: 'Ottawa', + company: null, + country: 'Canada', + country_code: 'CA', + country_name: 'Canada', + customer_id: 115310627314723950, + default: true, + first_name: null, + id: 715243470612851200, + last_name: null, + name: '', + phone: '123-123-1234', + province: 'Ontario', + province_code: 'ON', + zip: 'K2H7A8', + }, + adminGraphqlApiId: 'gid://shopify/Customer/115310627314723954', + billingAddress: { + address1: '123 Shipping Street', + address2: null, + city: 'Shippington', + company: 'Shipping Company', + country: 'United States', + country_code: 'US', + first_name: 'Steve', + last_name: 'Shipper', + latitude: null, + longitude: null, + name: 'Steve Shipper', + phone: '555-555-SHIP', + province: 'Kentucky', + province_code: 'KY', + zip: '40003', + }, + currency: 'USD', + email: 'john@example.com', + firstName: 'John', + lastName: 'Smith', + shippingAddress: { + address1: '123 Shipping Street', + address2: null, + city: 'Shippington', + company: 'Shipping Company', + country: 'United States', + country_code: 'US', + first_name: 'Steve', + last_name: 'Shipper', + latitude: null, + longitude: null, + name: 'Steve Shipper', + phone: '555-555-SHIP', + province: 'Kentucky', + province_code: 'KY', + zip: '40003', + }, + state: 'disabled', + tags: '', + taxExempt: false, + taxExemptions: [], + verifiedEmail: true, + }, + type: 'track', + userId: '115310627314723950', + }, + ], + }, + }, + ], + }, + }, + }, ]; export const data = [ From 9cc72f2288f99ee394977ffeb209faaae657f6d2 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Fri, 27 Sep 2024 18:55:03 +0530 Subject: [PATCH 031/147] fix: add correct validation for purchase events (#3766) --- src/cdk/v2/destinations/bluecore/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdk/v2/destinations/bluecore/utils.js b/src/cdk/v2/destinations/bluecore/utils.js index 91eda60d0d2..543b6de745f 100644 --- a/src/cdk/v2/destinations/bluecore/utils.js +++ b/src/cdk/v2/destinations/bluecore/utils.js @@ -46,12 +46,12 @@ const verifyPayload = (payload, message) => { } break; case 'purchase': - if (!payload?.properties?.order_id) { + if (!isDefinedAndNotNull(payload?.properties?.order_id)) { throw new InstrumentationError( '[Bluecore] property:: order_id is required for purchase event', ); } - if (!payload?.properties?.total) { + if (!isDefinedAndNotNull(payload?.properties?.total)) { throw new InstrumentationError( '[Bluecore] property:: total is required for purchase event', ); From 12996d7a7ce23de7c150c1c1e012d4dda8668977 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:39:53 +0530 Subject: [PATCH 032/147] feat: add unity source support in Singular (#3634) * feat: add unity source support in Singular * chore: address comment --- src/v0/destinations/singular/config.js | 16 + .../data/SINGULARUnityEventConfig.json | 112 +++++++ .../data/SINGULARUnitySessionConfig.json | 76 +++++ src/v0/destinations/singular/transform.js | 2 +- src/v0/destinations/singular/util.js | 94 +++--- .../destinations/singular/processor/data.ts | 285 ++++++++++++++++++ 6 files changed, 544 insertions(+), 41 deletions(-) create mode 100644 src/v0/destinations/singular/data/SINGULARUnityEventConfig.json create mode 100644 src/v0/destinations/singular/data/SINGULARUnitySessionConfig.json diff --git a/src/v0/destinations/singular/config.js b/src/v0/destinations/singular/config.js index d3fd2849636..97824b809b0 100644 --- a/src/v0/destinations/singular/config.js +++ b/src/v0/destinations/singular/config.js @@ -13,6 +13,10 @@ const CONFIG_CATEGORIES = { name: 'SINGULARIosSessionConfig', type: 'track', }, + SESSION_UNITY: { + name: 'SINGULARUnitySessionConfig', + type: 'track', + }, EVENT_ANDROID: { name: 'SINGULARAndroidEventConfig', type: 'track', @@ -21,6 +25,10 @@ const CONFIG_CATEGORIES = { name: 'SINGULARIosEventConfig', type: 'track', }, + EVENT_UNITY: { + name: 'SINGULARUnityEventConfig', + type: 'track', + }, PRODUCT_PROPERTY: { name: 'SINGULAREventProductConfig', }, @@ -29,8 +37,15 @@ const CONFIG_CATEGORIES = { const SUPPORTED_PLATFORM = { android: 'ANDROID', ios: 'IOS', + pc: 'unity', + xbox: 'unity', + playstation: 'unity', + nintendo: 'unity', + metaquest: 'unity', }; +const SUPPORTED_UNTIY_SUBPLATFORMS = ['pc', 'xbox', 'playstation', 'nintendo', 'metaquest']; + const SINGULAR_SESSION_ANDROID_EXCLUSION = [ 'referring_application', 'asid', @@ -93,5 +108,6 @@ module.exports = { SINGULAR_EVENT_ANDROID_EXCLUSION, SINGULAR_EVENT_IOS_EXCLUSION, SUPPORTED_PLATFORM, + SUPPORTED_UNTIY_SUBPLATFORMS, BASE_URL, }; diff --git a/src/v0/destinations/singular/data/SINGULARUnityEventConfig.json b/src/v0/destinations/singular/data/SINGULARUnityEventConfig.json new file mode 100644 index 00000000000..97cdfda2297 --- /dev/null +++ b/src/v0/destinations/singular/data/SINGULARUnityEventConfig.json @@ -0,0 +1,112 @@ +[ + { + "destKey": "p", + "sourceKeys": "context.os.name", + "required": true + }, + { + "destKey": "i", + "sourceKeys": "context.app.namespace", + "required": true + }, + { + "destKey": "sdid", + "sourceKeys": "context.device.id", + "required": false + }, + { + "destKey": "is_revenue_event", + "sourceKeys": "properties.is_revenue_event", + "required": false + }, + { + "destKey": "n", + "sourceKeys": "event", + "required": true + }, + { + "destKey": "av", + "sourceKeys": "context.app.version", + "required": false + }, + { + "destKey": "ve", + "sourceKeys": "context.os.version", + "required": false + }, + { + "destKey": "os", + "sourceKeys": "properties.os", + "required": true + }, + { + "destKey": "ip", + "sourceKeys": ["context.ip", "request_ip"], + "required": true + }, + { + "destKey": "use_ip", + "sourceKeys": "properties.use_ip", + "required": false + }, + { + "destKey": "install_source", + "sourceKeys": "properties.install_source", + "required": true + }, + { + "destKey": "data_sharing_options", + "sourceKeys": "properties.data_sharing_options", + "required": false + }, + { + "destKey": "amt", + "sourceKeys": [ + "properties.total", + "properties.value", + "properties.revenue", + { + "operation": "multiplication", + "args": [ + { + "sourceKeys": "properties.price" + }, + { + "sourceKeys": "properties.quantity", + "default": 1 + } + ] + } + ], + "required": false + }, + { + "destKey": "cur", + "sourceKeys": "properties.currency", + "required": false + }, + { + "destKey": "ua", + "sourceKeys": "context.userAgent", + "required": false + }, + { + "destKey": "utime", + "sourceKeys": "timestamp", + "sourceFromGenericMap": true, + "required": false, + "metadata": { + "type": "secondTimestamp" + } + }, + { + "destKey": "custom_user_id", + "sourceKeys": "properties.custom_user_id", + "required": false + }, + { + "destKey": "install", + "sourceKeys": "properties.install", + "required": false + } +] diff --git a/src/v0/destinations/singular/data/SINGULARUnitySessionConfig.json b/src/v0/destinations/singular/data/SINGULARUnitySessionConfig.json new file mode 100644 index 00000000000..aca561bc59d --- /dev/null +++ b/src/v0/destinations/singular/data/SINGULARUnitySessionConfig.json @@ -0,0 +1,76 @@ +[ + { + "destKey": "p", + "sourceKeys": "context.os.name", + "required": true + }, + { + "destKey": "i", + "sourceKeys": "context.app.namespace", + "required": true + }, + { + "destKey": "sdid", + "sourceKeys": "context.device.id", + "required": false + }, + { + "destKey": "av", + "sourceKeys": "context.app.version", + "required": false + }, + { + "destKey": "ve", + "sourceKeys": "context.os.version", + "required": false + }, + { + "destKey": "os", + "sourceKeys": "properties.os", + "required": true + }, + { + "destKey": "ip", + "sourceKeys": ["context.ip", "request_ip"], + "required": true + }, + { + "destKey": "use_ip", + "sourceKeys": "properties.use_ip", + "required": false + }, + { + "destKey": "install_source", + "sourceKeys": "properties.install_source", + "required": true + }, + { + "destKey": "ua", + "sourceKeys": "context.userAgent", + "required": false + }, + { + "destKey": "utime", + "sourceKeys": "timestamp", + "sourceFromGenericMap": true, + "required": false, + "metadata": { + "type": "secondTimestamp" + } + }, + { + "destKey": "data_sharing_options", + "sourceKeys": "properties.data_sharing_options", + "required": false + }, + { + "destKey": "custom_user_id", + "sourceKeys": "properties.custom_user_id", + "required": false + }, + { + "destKey": "install", + "sourceKeys": "properties.install", + "required": false + } +] diff --git a/src/v0/destinations/singular/transform.js b/src/v0/destinations/singular/transform.js index ff5d18db9aa..ed6757c47ba 100644 --- a/src/v0/destinations/singular/transform.js +++ b/src/v0/destinations/singular/transform.js @@ -20,7 +20,7 @@ const responseBuilderSimple = (message, { Config }) => { } const sessionEvent = isSessionEvent(Config, eventName); - const { eventAttributes, payload } = platformWisePayloadGenerator(message, sessionEvent); + const { eventAttributes, payload } = platformWisePayloadGenerator(message, sessionEvent, Config); const endpoint = sessionEvent ? `${BASE_URL}/launch` : `${BASE_URL}/evt`; // If we have an event where we have an array of Products, example Order Completed diff --git a/src/v0/destinations/singular/util.js b/src/v0/destinations/singular/util.js index 4c5aeb8964a..61db0472ab4 100644 --- a/src/v0/destinations/singular/util.js +++ b/src/v0/destinations/singular/util.js @@ -9,6 +9,7 @@ const { SINGULAR_EVENT_IOS_EXCLUSION, BASE_URL, SUPPORTED_PLATFORM, + SUPPORTED_UNTIY_SUBPLATFORMS, SESSIONEVENTS, } = require('./config'); const { @@ -85,7 +86,7 @@ const isSessionEvent = (Config, eventName) => { * @param {*} sessionEvent * @returns */ -const platformWisePayloadGenerator = (message, sessionEvent) => { +const platformWisePayloadGenerator = (message, sessionEvent, Config) => { let eventAttributes; const clonedMessage = { ...message }; let platform = getValueFromMessage(clonedMessage, 'context.os.name'); @@ -99,55 +100,68 @@ const platformWisePayloadGenerator = (message, sessionEvent) => { platform = 'iOS'; } platform = platform.toLowerCase(); - if (!SUPPORTED_PLATFORM[platform]) { + if (!SUPPORTED_PLATFORM[platform] && !SUPPORTED_UNTIY_SUBPLATFORMS[platform]) { throw new InstrumentationError(`Platform ${platform} is not supported`); } - - const payload = constructPayload( - clonedMessage, - MAPPING_CONFIG[CONFIG_CATEGORIES[`${typeOfEvent}_${SUPPORTED_PLATFORM[platform]}`].name], - ); - - if (!payload) { - throw new TransformationError(`Failed to Create ${platform} ${typeOfEvent} Payload`); - } - if (sessionEvent) { - // context.device.adTrackingEnabled = true implies Singular's do not track (dnt) - // to be 0 and vice-versa. - const adTrackingEnabled = getValueFromMessage( + let payload; + if (SUPPORTED_UNTIY_SUBPLATFORMS.includes(platform)) { + payload = constructPayload( clonedMessage, - 'context.device.adTrackingEnabled', + MAPPING_CONFIG[CONFIG_CATEGORIES[`${typeOfEvent}_UNITY`].name], ); - if (adTrackingEnabled === true) { - payload.dnt = 0; - } else { - payload.dnt = 1; - } - // by default, the value of openuri and install_source should be "", i.e empty string if nothing is passed - payload.openuri = clonedMessage.properties.url || ''; - if (platform === 'android' || platform === 'Android') { - payload.install_source = clonedMessage.properties.referring_application || ''; - } } else { - // Custom Attribues is not supported by session events - eventAttributes = extractExtraFields( + payload = constructPayload( clonedMessage, - exclusionList[`${SUPPORTED_PLATFORM[platform]}_${typeOfEvent}_EXCLUSION_LIST`], + MAPPING_CONFIG[CONFIG_CATEGORIES[`${typeOfEvent}_${SUPPORTED_PLATFORM[platform]}`].name], ); - eventAttributes = removeUndefinedAndNullValues(eventAttributes); + } - // If anyone out of value, revenue, total is set,we will have amt in payload - // and we will consider the event as revenue event. - if (!isDefinedAndNotNull(payload.is_revenue_event) && payload.amt) { - payload.is_revenue_event = true; - } + if (!payload) { + throw new TransformationError(`Failed to Create ${platform} ${typeOfEvent} Payload`); } + if (!SUPPORTED_UNTIY_SUBPLATFORMS.includes(platform)) { + if (sessionEvent) { + // context.device.adTrackingEnabled = true implies Singular's do not track (dnt) + // to be 0 and vice-versa. + const adTrackingEnabled = getValueFromMessage( + clonedMessage, + 'context.device.adTrackingEnabled', + ); + if (adTrackingEnabled === true) { + payload.dnt = 0; + } else { + payload.dnt = 1; + } + // by default, the value of openuri and install_source should be "", i.e empty string if nothing is passed + payload.openuri = clonedMessage.properties.url || ''; + if (platform === 'android' || platform === 'Android') { + payload.install_source = clonedMessage.properties.referring_application || ''; + } + } else { + // Custom Attribues is not supported by session events + eventAttributes = extractExtraFields( + clonedMessage, + exclusionList[`${SUPPORTED_PLATFORM[platform]}_${typeOfEvent}_EXCLUSION_LIST`], + ); + eventAttributes = removeUndefinedAndNullValues(eventAttributes); - // Singular maps Connection Type to either wifi or carrier - if (clonedMessage.context?.network?.wifi) { - payload.c = 'wifi'; - } else { - payload.c = 'carrier'; + // If anyone out of value, revenue, total is set,we will have amt in payload + // and we will consider the event as revenue event. + if (!isDefinedAndNotNull(payload.is_revenue_event) && payload.amt) { + payload.is_revenue_event = true; + } + } + + // Singular maps Connection Type to either wifi or carrier + if (clonedMessage.context?.network?.wifi) { + payload.c = 'wifi'; + } else { + payload.c = 'carrier'; + } + } else if (Config.match_id === 'advertisingId') { + payload.match_id = clonedMessage?.context?.device?.advertisingId; + } else if (message.properties.match_id) { + payload.match_id = message.properties.match_id; } return { payload, eventAttributes }; }; diff --git a/test/integrations/destinations/singular/processor/data.ts b/test/integrations/destinations/singular/processor/data.ts index 22c075fffc5..6e749dd0a01 100644 --- a/test/integrations/destinations/singular/processor/data.ts +++ b/test/integrations/destinations/singular/processor/data.ts @@ -1903,4 +1903,289 @@ export const data = [ }, }, }, + { + name: 'singular', + description: '(Unity) Session Event', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + apiKey: 'dummyApiKey', + sessionEventList: [ + { sessionEventName: 'mysessionevent' }, + { sessionEventName: 'randomuser' }, + { sessionEventName: 'titanium' }, + ], + }, + }, + message: { + type: 'track', + event: 'mysessionevent', + userId: 'ruddersampleX3', + request_ip: '14.5.67.21', + context: { + app: { + build: '1', + name: 'RudderAndroidClient', + namespace: 'com.singular.game', + version: '1.1.5.581823alpha', + }, + device: { + manufacturer: 'Google', + model: 'Android SDK built for x86', + name: 'generic_x86', + type: 'android', + advertisingId: '8ecd7512-2864-440c-93f3-a3cabe62525b', + attStatus: true, + id: '49c2d3a6-326e-4ec5-a16b-0a47e34ed953', + adTrackingEnabled: true, + token: 'testDeviceToken', + }, + library: { name: 'com.rudderstack.android.sdk.core', version: '0.1.4' }, + locale: 'en-US', + network: { carrier: 'Android', bluetooth: false, cellular: true, wifi: true }, + campaign: { + source: 'google', + medium: 'medium', + term: 'keyword', + content: 'some content', + }, + os: { name: 'nintendo', version: '360v2-2024h1' }, + screen: { density: 420, height: 1794, width: 1080 }, + timezone: 'Asia/Mumbai', + userAgent: + 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/613.0 (KHTML, like Gecko) NF/6.0.3.25.0 NintendoBrowser/5.1.0.32061', + }, + properties: { + asid: 'IISqwYJKoZIcNqts0jvcNvPc', + url: 'myapp%3A%2F%2Fhome%2Fpage%3Fqueryparam1%3Dvalue1', + install: 'false', + install_source: 'nintendo', + category: 'Games', + affiliation: 'Apple Store', + receipt_signature: '1234dfghnh', + referring_application: '2134dfg', + os: 'nintendo_switch', + data_sharing_options: '%7B%22limit_data_sharing%22%3Atrue%7D', + }, + timestamp: '2024-06-01T11:26:50.000Z', + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'GET', + endpoint: 'https://s2s.singular.net/api/v1/launch', + headers: {}, + params: { + a: 'dummyApiKey', + av: '1.1.5.581823alpha', + data_sharing_options: '%7B%22limit_data_sharing%22%3Atrue%7D', + i: 'com.singular.game', + install: 'false', + install_source: 'nintendo', + ip: '14.5.67.21', + os: 'nintendo_switch', + p: 'nintendo', + sdid: '49c2d3a6-326e-4ec5-a16b-0a47e34ed953', + ua: 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/613.0 (KHTML, like Gecko) NF/6.0.3.25.0 NintendoBrowser/5.1.0.32061', + utime: 1717241210, + ve: '360v2-2024h1', + }, + body: { JSON: {}, JSON_ARRAY: {}, XML: {}, FORM: {} }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'singular', + description: '(Unity) Custom Event with multiple products', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + apiKey: 'dummyApiKey', + sessionEventList: [ + { sessionEventName: 'mysessionevent' }, + { sessionEventName: 'randomuser' }, + { sessionEventName: 'titanium' }, + ], + }, + }, + message: { + type: 'track', + event: 'myevent', + userId: 'ruddersampleX4', + request_ip: '14.5.67.21', + context: { + app: { + build: '1', + name: 'RudderAndroidClient', + namespace: 'com.singular.game', + version: '1.1.5.581823alpha', + }, + device: { + manufacturer: 'Google', + model: 'Android SDK built for x86', + name: 'generic_x86', + type: 'android', + advertisingId: '8ecd7512-2864-440c-93f3-a3cabe62525b', + attStatus: true, + id: '49c2d3a6-326e-4ec5-a16b-0a47e34ed953', + adTrackingEnabled: true, + token: 'testDeviceToken', + }, + library: { name: 'com.rudderstack.android.sdk.core', version: '0.1.4' }, + locale: 'en-US', + network: { carrier: 'Android', bluetooth: false, cellular: true, wifi: true }, + campaign: { + source: 'google', + medium: 'medium', + term: 'keyword', + content: 'some content', + }, + os: { name: 'metaquest', version: 'qst2-2023h2' }, + screen: { density: 420, height: 1794, width: 1080 }, + timezone: 'Asia/Mumbai', + userAgent: + 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/613.0 (KHTML, like Gecko) NF/6.0.3.25.0 NintendoBrowser/5.1.0.32061', + }, + properties: { + asid: 'IISqwYJKoZIcNqts0jvcNvPc', + url: 'myapp%3A%2F%2Fhome%2Fpage%3Fqueryparam1%3Dvalue1', + install: 'SM-G935F', + install_source: 'selfdistributed', + category: 'Games', + checkout_id: '12345', + order_id: '1234', + receipt_signature: '1234dfghnh', + referring_application: '2134dfg', + total: 20, + revenue: 15, + shipping: 22, + tax: 1, + discount: 1.5, + coupon: 'ImagePro', + currency: 'USD', + fetch_token: 'dummyFetchToken', + product_id: '123', + is_revenue_event: true, + os: 'metaquest_pro', + products: [ + { + product_id: '789', + sku: 'G-32', + name: 'Monopoly', + price: 14, + quantity: 2, + category: 'Games', + url: 'https://www.website.com/product/path', + image_url: 'https://www.website.com/product/path.jpg', + }, + { sku: 'F-32', name: 'UNO', price: 3.45, quantity: 2, category: 'Games' }, + ], + }, + timestamp: '2021-09-01T15:46:51.000Z', + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'GET', + endpoint: 'https://s2s.singular.net/api/v1/evt', + headers: {}, + params: { + n: 'myevent', + ip: '14.5.67.21', + av: '1.1.5.581823alpha', + is_revenue_event: true, + i: 'com.singular.game', + utime: 1630511211, + cur: 'USD', + amt: 28, + purchase_product_id: '789', + a: 'dummyApiKey', + install_source: 'selfdistributed', + os: 'metaquest_pro', + p: 'metaquest', + sdid: '49c2d3a6-326e-4ec5-a16b-0a47e34ed953', + ua: 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/613.0 (KHTML, like Gecko) NF/6.0.3.25.0 NintendoBrowser/5.1.0.32061', + ve: 'qst2-2023h2', + install: 'SM-G935F', + }, + body: { JSON: {}, JSON_ARRAY: {}, XML: {}, FORM: {} }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + { + output: { + version: '1', + type: 'REST', + method: 'GET', + endpoint: 'https://s2s.singular.net/api/v1/evt', + headers: {}, + params: { + n: 'myevent', + i: 'com.singular.game', + ip: '14.5.67.21', + is_revenue_event: true, + utime: 1630511211, + cur: 'USD', + purchase_product_id: 'F-32', + install: 'SM-G935F', + install_source: 'selfdistributed', + amt: 6.9, + os: 'metaquest_pro', + p: 'metaquest', + a: 'dummyApiKey', + sdid: '49c2d3a6-326e-4ec5-a16b-0a47e34ed953', + ua: 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/613.0 (KHTML, like Gecko) NF/6.0.3.25.0 NintendoBrowser/5.1.0.32061', + ve: 'qst2-2023h2', + av: '1.1.5.581823alpha', + }, + body: { JSON: {}, JSON_ARRAY: {}, XML: {}, FORM: {} }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, ]; From 43a8a304f9f66a79bb91a2eb305a7db5ccfde2d2 Mon Sep 17 00:00:00 2001 From: Gauravudia <60897972+Gauravudia@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:31:51 +0530 Subject: [PATCH 033/147] refactor: trade desk component testcases (#3763) --- .../the_trade_desk/router/business.ts | 330 +++++ .../the_trade_desk/router/data.ts | 1067 +---------------- .../the_trade_desk/router/validation.ts | 743 ++++++++++++ 3 files changed, 1076 insertions(+), 1064 deletions(-) create mode 100644 test/integrations/destinations/the_trade_desk/router/business.ts create mode 100644 test/integrations/destinations/the_trade_desk/router/validation.ts diff --git a/test/integrations/destinations/the_trade_desk/router/business.ts b/test/integrations/destinations/the_trade_desk/router/business.ts new file mode 100644 index 00000000000..556e69a909e --- /dev/null +++ b/test/integrations/destinations/the_trade_desk/router/business.ts @@ -0,0 +1,330 @@ +import { defaultMockFns } from '../mocks'; +import { + destType, + advertiserId, + dataProviderId, + segmentName, + sampleDestination, + sampleContext, +} from '../common'; + +export const business = [ + { + id: 'trade_desk-business-test-1', + name: destType, + description: 'Add IDs to the segment', + scenario: 'Framework', + successCriteria: 'Response should contain all the mapping and status code should be 200', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: { + jobId: 1, + userId: 'u1', + }, + }, + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-2', + UID2: 'test-uid2-2', + }, + channel: 'sources', + context: sampleContext, + recordId: '2', + }, + destination: sampleDestination, + metadata: { + jobId: 2, + userId: 'u1', + }, + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + DAID: 'test-daid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + UID2: 'test-uid2-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + DAID: 'test-daid-2', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + UID2: 'test-uid2-2', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + jobId: 1, + userId: 'u1', + }, + { + jobId: 2, + userId: 'u1', + }, + ], + batched: true, + statusCode: 200, + destination: sampleDestination, + }, + ], + }, + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'trade_desk-business-test-2', + name: destType, + description: + 'Add/Remove IDs to/from the segment and split into multiple requests based on size', + successCriteria: 'Response should contain all the mapping and status code should be 200', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: { + jobId: 1, + userId: 'u1', + }, + }, + { + message: { + type: 'record', + action: 'delete', + fields: { + DAID: 'test-daid-2', + UID2: 'test-uid2-2', + }, + channel: 'sources', + context: sampleContext, + recordId: '2', + }, + destination: sampleDestination, + metadata: { + jobId: 2, + userId: 'u1', + }, + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + DAID: 'test-daid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + UID2: 'test-uid2-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + DAID: 'test-daid-2', + Data: [ + { + Name: segmentName, + TTLInMinutes: 0, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + UID2: 'test-uid2-2', + Data: [ + { + Name: segmentName, + TTLInMinutes: 0, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + jobId: 1, + userId: 'u1', + }, + { + jobId: 2, + userId: 'u1', + }, + ], + batched: true, + statusCode: 200, + destination: sampleDestination, + }, + ], + }, + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/the_trade_desk/router/data.ts b/test/integrations/destinations/the_trade_desk/router/data.ts index d2dbf9a7cc5..6de2069ff4d 100644 --- a/test/integrations/destinations/the_trade_desk/router/data.ts +++ b/test/integrations/destinations/the_trade_desk/router/data.ts @@ -1,1064 +1,3 @@ -import { overrideDestination } from '../../../testUtils'; -import { defaultMockFns } from '../mocks'; -import { - destType, - destTypeInUpperCase, - advertiserId, - dataProviderId, - segmentName, - sampleDestination, - sampleContext, -} from '../common'; - -export const data = [ - { - name: destType, - description: 'Add IDs to the segment', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-2', - UID2: 'test-uid2-2', - }, - channel: 'sources', - context: sampleContext, - recordId: '2', - }, - destination: sampleDestination, - metadata: { - jobId: 2, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: [ - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - DAID: 'test-daid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - UID2: 'test-uid2-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - DAID: 'test-daid-2', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - UID2: 'test-uid2-2', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - ], - metadata: [ - { - jobId: 1, - userId: 'u1', - }, - { - jobId: 2, - userId: 'u1', - }, - ], - batched: true, - statusCode: 200, - destination: sampleDestination, - }, - ], - }, - }, - }, - mockFns: defaultMockFns, - }, - { - name: destType, - description: - 'Add/Remove IDs to/from the segment and split into multiple requests based on size', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - { - message: { - type: 'record', - action: 'delete', - fields: { - DAID: 'test-daid-2', - UID2: 'test-uid2-2', - }, - channel: 'sources', - context: sampleContext, - recordId: '2', - }, - destination: sampleDestination, - metadata: { - jobId: 2, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: [ - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - DAID: 'test-daid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - UID2: 'test-uid2-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - DAID: 'test-daid-2', - Data: [ - { - Name: segmentName, - TTLInMinutes: 0, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - UID2: 'test-uid2-2', - Data: [ - { - Name: segmentName, - TTLInMinutes: 0, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - ], - metadata: [ - { - jobId: 1, - userId: 'u1', - }, - { - jobId: 2, - userId: 'u1', - }, - ], - batched: true, - statusCode: 200, - destination: sampleDestination, - }, - ], - }, - }, - }, - mockFns: defaultMockFns, - }, - { - name: destType, - description: - 'Missing segment name (audienceId) in the config (segment name will be populated from vdm)', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: overrideDestination(sampleDestination, { audienceId: '' }), - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-2', - UID2: 'test-uid2-2', - }, - channel: 'sources', - context: sampleContext, - recordId: '2', - }, - destination: overrideDestination(sampleDestination, { audienceId: '' }), - metadata: { - jobId: 2, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batched: false, - metadata: [ - { jobId: 1, userId: 'u1' }, - { jobId: 2, userId: 'u1' }, - ], - statusCode: 400, - error: 'Segment name/Audience ID is not present. Aborting', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'configuration', - }, - }, - ], - }, - }, - }, - }, - { - name: destType, - description: 'Missing advertiser ID in the config', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: overrideDestination(sampleDestination, { advertiserId: '' }), - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-2', - UID2: 'test-uid2-2', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: overrideDestination(sampleDestination, { advertiserId: '' }), - metadata: { - jobId: 2, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batched: false, - metadata: [ - { jobId: 1, userId: 'u1' }, - { jobId: 2, userId: 'u1' }, - ], - statusCode: 400, - error: 'Advertiser ID is not present. Aborting', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'configuration', - }, - }, - ], - }, - }, - }, - }, - { - name: destType, - description: 'Missing advertiser secret key in the config', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: overrideDestination(sampleDestination, { advertiserSecretKey: '' }), - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batched: false, - metadata: [{ jobId: 1, userId: 'u1' }], - statusCode: 400, - error: 'Advertiser Secret Key is not present. Aborting', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'configuration', - }, - }, - ], - }, - }, - }, - }, - { - name: destType, - description: 'TTL is out of range', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: overrideDestination(sampleDestination, { ttlInDays: 190 }), - metadata: { - jobId: 1, - userId: 'u1', - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batched: false, - metadata: [{ jobId: 1, userId: 'u1' }], - statusCode: 400, - error: 'TTL is out of range. Allowed values are 0 to 180 days', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'configuration', - }, - }, - ], - }, - }, - }, - }, - { - name: destType, - description: 'Invalid action type', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - }, - }, - { - message: { - type: 'record', - action: 'update', - fields: { - DAID: 'test-daid-2', - UID2: null, - }, - channel: 'sources', - context: sampleContext, - recordId: '2', - }, - destination: sampleDestination, - metadata: { - jobId: 2, - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: [ - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - DAID: 'test-daid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - UID2: 'test-uid2-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - ], - metadata: [ - { - jobId: 1, - }, - ], - batched: true, - statusCode: 200, - destination: sampleDestination, - }, - { - batched: false, - metadata: [{ jobId: 2 }], - statusCode: 400, - error: - 'Invalid action type. You can only add or remove IDs from the audience/segment', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - }, - destination: sampleDestination, - }, - ], - }, - }, - }, - mockFns: defaultMockFns, - }, - { - name: destType, - description: 'Empty fields in the message', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: {}, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - }, - }, - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - UID2: 'test-uid2-1', - EUID: 'test-euid-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '2', - }, - destination: sampleDestination, - metadata: { - jobId: 2, - }, - }, - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-2', - UID2: null, - EUID: null, - }, - channel: 'sources', - context: sampleContext, - recordId: '3', - }, - destination: sampleDestination, - metadata: { - jobId: 3, - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: [ - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - DAID: 'test-daid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - UID2: 'test-uid2-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - { - EUID: 'test-euid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - ], - metadata: [ - { - jobId: 2, - }, - ], - batched: true, - statusCode: 200, - destination: sampleDestination, - }, - { - batched: false, - metadata: [{ jobId: 1 }], - statusCode: 400, - error: '`fields` cannot be empty', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - }, - destination: sampleDestination, - }, - { - batched: false, - metadata: [{ jobId: 3 }], - statusCode: 400, - error: '`fields` cannot be empty', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - }, - destination: sampleDestination, - }, - ], - }, - }, - }, - mockFns: defaultMockFns, - }, - { - name: destType, - description: '`fields` is missing', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batched: false, - metadata: [{ jobId: 1 }], - statusCode: 400, - error: '`fields` cannot be empty', - statTags: { - destType: destTypeInUpperCase, - implementation: 'cdkV2', - feature: 'router', - module: 'destination', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - }, - destination: sampleDestination, - }, - ], - }, - }, - }, - mockFns: defaultMockFns, - }, - { - name: destType, - description: 'Batch call with different event types', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - type: 'record', - action: 'insert', - fields: { - DAID: 'test-daid-1', - }, - channel: 'sources', - context: sampleContext, - recordId: '1', - }, - destination: sampleDestination, - metadata: { - jobId: 1, - }, - }, - { - message: { - type: 'identify', - context: { - traits: { - name: 'John Doe', - email: 'johndoe@gmail.com', - age: 25, - }, - }, - }, - destination: sampleDestination, - metadata: { - jobId: 2, - }, - }, - ], - destType, - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: [ - { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://sin-data.adsrvr.org/data/advertiser', - headers: {}, - params: {}, - body: { - JSON: { - DataProviderId: dataProviderId, - AdvertiserId: advertiserId, - Items: [ - { - DAID: 'test-daid-1', - Data: [ - { - Name: segmentName, - TTLInMinutes: 43200, - }, - ], - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - ], - metadata: [ - { - jobId: 1, - }, - ], - batched: true, - statusCode: 200, - destination: sampleDestination, - }, - { - batched: false, - metadata: [{ jobId: 2 }], - statusCode: 400, - error: 'Event type identify is not supported', - statTags: { - errorCategory: 'dataValidation', - errorType: 'instrumentation', - destType: 'THE_TRADE_DESK', - module: 'destination', - implementation: 'cdkV2', - feature: 'router', - }, - destination: sampleDestination, - }, - ], - }, - }, - }, - }, -]; +import { business } from './business'; +import { validation } from './validation'; +export const data = [...business, ...validation]; diff --git a/test/integrations/destinations/the_trade_desk/router/validation.ts b/test/integrations/destinations/the_trade_desk/router/validation.ts new file mode 100644 index 00000000000..be7caf079a7 --- /dev/null +++ b/test/integrations/destinations/the_trade_desk/router/validation.ts @@ -0,0 +1,743 @@ +import { defaultMockFns } from '../mocks'; +import { generateMetadata } from '../../../testUtils'; +import { overrideDestination } from '../../../testUtils'; +import { + destType, + destTypeInUpperCase, + advertiserId, + dataProviderId, + segmentName, + sampleDestination, + sampleContext, +} from '../common'; + +export const validation = [ + { + id: 'trade_desk-validation-test-1', + name: destType, + description: 'Missing advertiser ID in the config', + scenario: 'Framework', + successCriteria: 'Partial Failure: Configuration Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: overrideDestination(sampleDestination, { advertiserId: '' }), + metadata: generateMetadata(1, 'u1'), + }, + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-2', + UID2: 'test-uid2-2', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: overrideDestination(sampleDestination, { advertiserId: '' }), + metadata: generateMetadata(2, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + metadata: [generateMetadata(1, 'u1'), generateMetadata(2, 'u1')], + statusCode: 400, + error: 'Advertiser ID is not present. Aborting', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'configuration', + }, + }, + ], + }, + }, + }, + }, + { + id: 'trade_desk-validation-test-2', + name: destType, + description: + 'Missing segment name (audienceId) in the config (segment name will be populated from vdm)', + scenario: 'Framework', + successCriteria: 'Partial Failure: Configuration Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: overrideDestination(sampleDestination, { audienceId: '' }), + metadata: generateMetadata(1, 'u1'), + }, + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-2', + UID2: 'test-uid2-2', + }, + channel: 'sources', + context: sampleContext, + recordId: '2', + }, + destination: overrideDestination(sampleDestination, { audienceId: '' }), + metadata: generateMetadata(2, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + metadata: [generateMetadata(1, 'u1'), generateMetadata(2, 'u1')], + statusCode: 400, + error: 'Segment name/Audience ID is not present. Aborting', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'configuration', + }, + }, + ], + }, + }, + }, + }, + { + id: 'trade_desk-validation-test-3', + name: destType, + description: 'Missing advertiser secret key in the config', + scenario: 'Framework', + successCriteria: 'Partial Failure: Configuration Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: overrideDestination(sampleDestination, { advertiserSecretKey: '' }), + metadata: generateMetadata(1, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + metadata: [generateMetadata(1, 'u1')], + statusCode: 400, + error: 'Advertiser Secret Key is not present. Aborting', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'configuration', + }, + }, + ], + }, + }, + }, + }, + { + id: 'trade_desk-validation-test-4', + name: destType, + description: 'Invalid action type', + scenario: 'Framework', + successCriteria: 'Partial Failure: Instrumentation Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: generateMetadata(1, 'u1'), + }, + { + message: { + type: 'record', + action: 'update', + fields: { + DAID: 'test-daid-2', + UID2: null, + }, + channel: 'sources', + context: sampleContext, + recordId: '2', + }, + destination: sampleDestination, + metadata: generateMetadata(2, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + DAID: 'test-daid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + UID2: 'test-uid2-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [generateMetadata(1, 'u1')], + batched: true, + statusCode: 200, + destination: sampleDestination, + }, + { + batched: false, + metadata: [generateMetadata(2, 'u1')], + statusCode: 400, + error: + 'Invalid action type. You can only add or remove IDs from the audience/segment', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + }, + destination: sampleDestination, + }, + ], + }, + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'trade_desk-validation-test-5', + name: destType, + description: 'Invalid action type', + scenario: 'Framework', + successCriteria: 'Partial Failure: Instrumentation Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: {}, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: generateMetadata(1, 'u1'), + }, + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + EUID: 'test-euid-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '2', + }, + destination: sampleDestination, + metadata: generateMetadata(2, 'u1'), + }, + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-2', + UID2: null, + EUID: null, + }, + channel: 'sources', + context: sampleContext, + recordId: '3', + }, + destination: sampleDestination, + metadata: generateMetadata(3, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + DAID: 'test-daid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + UID2: 'test-uid2-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + { + EUID: 'test-euid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [generateMetadata(2, 'u1')], + batched: true, + statusCode: 200, + destination: sampleDestination, + }, + { + batched: false, + metadata: [generateMetadata(1, 'u1')], + statusCode: 400, + error: '`fields` cannot be empty', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + }, + destination: sampleDestination, + }, + { + batched: false, + metadata: [generateMetadata(3, 'u1')], + statusCode: 400, + error: '`fields` cannot be empty', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + }, + destination: sampleDestination, + }, + ], + }, + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'trade_desk-validation-test-6', + name: destType, + description: '`fields` is missing', + scenario: 'Framework', + successCriteria: 'Partial Failure: Instrumentation Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: generateMetadata(1, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + metadata: [generateMetadata(1, 'u1')], + statusCode: 400, + error: '`fields` cannot be empty', + statTags: { + destType: destTypeInUpperCase, + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + }, + destination: sampleDestination, + }, + ], + }, + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'trade_desk-validation-test-7', + name: destType, + description: 'Batch call with different event types', + scenario: 'Framework', + successCriteria: 'Partial Failure: Instrumentation Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: sampleDestination, + metadata: generateMetadata(1, 'u1'), + }, + { + message: { + type: 'identify', + context: { + traits: { + name: 'John Doe', + email: 'johndoe@gmail.com', + age: 25, + }, + }, + }, + destination: sampleDestination, + metadata: generateMetadata(2, 'u1'), + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://sin-data.adsrvr.org/data/advertiser', + headers: {}, + params: {}, + body: { + JSON: { + DataProviderId: dataProviderId, + AdvertiserId: advertiserId, + Items: [ + { + DAID: 'test-daid-1', + Data: [ + { + Name: segmentName, + TTLInMinutes: 43200, + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [generateMetadata(1, 'u1')], + batched: true, + statusCode: 200, + destination: sampleDestination, + }, + { + batched: false, + metadata: [generateMetadata(2, 'u1')], + statusCode: 400, + error: 'Event type identify is not supported', + statTags: { + errorCategory: 'dataValidation', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + errorType: 'instrumentation', + destType: destTypeInUpperCase, + module: 'destination', + implementation: 'cdkV2', + feature: 'router', + }, + destination: sampleDestination, + }, + ], + }, + }, + }, + }, + { + id: 'trade_desk-validation-test-8', + name: destType, + description: 'TTL is out of range', + scenario: 'Framework', + successCriteria: 'Configurations= Error', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + DAID: 'test-daid-1', + UID2: 'test-uid2-1', + }, + channel: 'sources', + context: sampleContext, + recordId: '1', + }, + destination: overrideDestination(sampleDestination, { ttlInDays: 190 }), + metadata: { + jobId: 1, + userId: 'u1', + }, + }, + ], + destType, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + metadata: [{ jobId: 1, userId: 'u1' }], + statusCode: 400, + error: 'TTL is out of range. Allowed values are 0 to 180 days', + statTags: { + destType: destTypeInUpperCase, + implementation: 'cdkV2', + feature: 'router', + module: 'destination', + errorCategory: 'dataValidation', + errorType: 'configuration', + }, + }, + ], + }, + }, + }, + }, +]; From 173b9895fb2a0bed615f6e3a9c670abe42d5754f Mon Sep 17 00:00:00 2001 From: Anant Jain <62471433+anantjain45823@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:46:36 +0530 Subject: [PATCH 034/147] fix: braze include fields_to_export to lookup users (#3761) * fix: braze include fields_to_export to lookup users * chore: fix test cases * fix: add user_aliases as export field for anonymous users * chore: fix test cases --------- Co-authored-by: Utsab Chowdhury --- src/v0/destinations/braze/braze.util.test.js | 14 +++++++++ src/v0/destinations/braze/util.js | 21 ++++++++++++-- .../destinations/braze/network.ts | 29 +++++++++---------- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 5ec48d29f18..71052f8d776 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -304,6 +304,20 @@ describe('dedup utility tests', () => { { external_ids: ['user1', 'user2'], user_aliases: [{ alias_name: 'user3', alias_label: 'rudder_id' }], + fields_to_export: [ + 'created_at', + 'custom_attributes', + 'dob', + 'email', + 'first_name', + 'gender', + 'home_city', + 'last_name', + 'phone', + 'time_zone', + 'external_id', + 'user_aliases', + ], }, { headers: { diff --git a/src/v0/destinations/braze/util.js b/src/v0/destinations/braze/util.js index e5df75b562b..6c8cf64265f 100644 --- a/src/v0/destinations/braze/util.js +++ b/src/v0/destinations/braze/util.js @@ -141,19 +141,36 @@ const BrazeDedupUtility = { const identfierChunks = _.chunk(identifiers, 50); return identfierChunks; }, - + getFieldsToExport() { + return [ + 'created_at', + 'custom_attributes', + 'dob', + 'email', + 'first_name', + 'gender', + 'home_city', + 'last_name', + 'phone', + 'time_zone', + 'external_id', + 'user_aliases', + // 'country' and 'language' not needed because it is not billable so we don't use it + ]; + }, async doApiLookup(identfierChunks, { destination, metadata }) { return Promise.all( identfierChunks.map(async (ids) => { const externalIdentifiers = ids.filter((id) => id.external_id); const aliasIdentifiers = ids.filter((id) => id.alias_name !== undefined); - + const fieldsToExport = this.getFieldsToExport(); const { processedResponse: lookUpResponse } = await handleHttpRequest( 'post', `${getEndpointFromConfig(destination)}/users/export/ids`, { external_ids: externalIdentifiers.map((extId) => extId.external_id), user_aliases: aliasIdentifiers, + fields_to_export: fieldsToExport, }, { headers: { diff --git a/test/integrations/destinations/braze/network.ts b/test/integrations/destinations/braze/network.ts index ae093ce1f48..bcfa78de5de 100644 --- a/test/integrations/destinations/braze/network.ts +++ b/test/integrations/destinations/braze/network.ts @@ -406,6 +406,20 @@ const deleteNwData = [ { alias_name: '77e278c9-e984-4cdd-950c-cd0b61befd03', alias_label: 'rudder_id' }, { alias_name: 'e6ab2c5e-2cda-44a9-a962-e2f67df78bca', alias_label: 'rudder_id' }, ], + fields_to_export: [ + 'created_at', + 'custom_attributes', + 'dob', + 'email', + 'first_name', + 'gender', + 'home_city', + 'last_name', + 'phone', + 'time_zone', + 'external_id', + 'user_aliases', + ], }, headers: { Authorization: 'Bearer dummyApiKey' }, url: 'https://rest.iad-03.braze.com/users/export/ids', @@ -416,12 +430,8 @@ const deleteNwData = [ { created_at: '2023-03-17T20:51:58.297Z', external_id: 'braze_test_user', - user_aliases: [], - appboy_id: '6414d2ee33326e3354e3040b', - braze_id: '6414d2ee33326e3354e3040b', first_name: 'Jackson', last_name: 'Miranda', - random_bucket: 8134, email: 'jackson24miranda@gmail.com', custom_attributes: { pwa: false, @@ -437,17 +447,6 @@ const deleteNwData = [ }, custom_arr: [1, 2, 'str1'], }, - custom_events: [ - { - name: 'Sign In Completed', - first: '2023-03-10T18:36:05.028Z', - last: '2023-03-10T18:36:05.028Z', - count: 2, - }, - ], - total_revenue: 0, - push_subscribe: 'subscribed', - email_subscribe: 'subscribed', }, ], }, From b6240d06a9d1f7f3bc8f245807f72a72ab40f170 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:47:23 +0530 Subject: [PATCH 035/147] fix: posthog alias mapping swap (#3765) * fix: posthog swapped alias ids (#3507) [Posthog] fix swapped alias ids Co-authored-by: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> * fix: test case update for posthog --------- Co-authored-by: Marc Jeffrey --- src/v0/destinations/posthog/data/PHAliasConfig.json | 4 ++-- test/integrations/destinations/posthog/processor/data.ts | 4 ++-- test/integrations/destinations/posthog/router/data.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/v0/destinations/posthog/data/PHAliasConfig.json b/src/v0/destinations/posthog/data/PHAliasConfig.json index 1992349e227..26fb61ea785 100644 --- a/src/v0/destinations/posthog/data/PHAliasConfig.json +++ b/src/v0/destinations/posthog/data/PHAliasConfig.json @@ -1,12 +1,12 @@ [ { - "destKey": "properties.alias", + "destKey": "properties.distinct_id", "sourceKeys": "userId", "sourceFromGenericMap": true, "required": true }, { - "destKey": "properties.distinct_id", + "destKey": "properties.alias", "sourceKeys": "previousId", "required": true }, diff --git a/test/integrations/destinations/posthog/processor/data.ts b/test/integrations/destinations/posthog/processor/data.ts index f33aa268b72..35e12b4aab6 100644 --- a/test/integrations/destinations/posthog/processor/data.ts +++ b/test/integrations/destinations/posthog/processor/data.ts @@ -74,7 +74,7 @@ export const data = [ $ip: '0.0.0.0', $timestamp: '2020-11-04T13:21:09.712Z', $anon_distinct_id: 'f3cf54d8-f237-45d2-89f7-ccd70d42cf31', - distinct_id: 'prevId_1', + distinct_id: 'uid-1', $device_manufacturer: 'Xiaomi', $os_version: '8.1.0', $app_version: '1.1.7', @@ -84,7 +84,7 @@ export const data = [ $device_model: 'Redmi 6', $app_namespace: 'com.rudderlabs.javascript', $app_build: '1.0.0', - alias: 'uid-1', + alias: 'prevId_1', }, timestamp: '2020-11-04T13:21:09.712Z', event: '$create_alias', diff --git a/test/integrations/destinations/posthog/router/data.ts b/test/integrations/destinations/posthog/router/data.ts index dab8ba8b1ce..20870670dc5 100644 --- a/test/integrations/destinations/posthog/router/data.ts +++ b/test/integrations/destinations/posthog/router/data.ts @@ -79,7 +79,7 @@ export const data = [ $ip: '0.0.0.0', $timestamp: '2020-11-04T13:21:09.712Z', $anon_distinct_id: 'f3cf54d8-f237-45d2-89f7-ccd70d42cf31', - distinct_id: 'prevId_1', + distinct_id: 'uid-1', $device_manufacturer: 'Xiaomi', $os_version: '8.1.0', $app_version: '1.1.7', @@ -89,7 +89,7 @@ export const data = [ $device_model: 'Redmi 6', $app_namespace: 'com.rudderlabs.javascript', $app_build: '1.0.0', - alias: 'uid-1', + alias: 'prevId_1', }, timestamp: '2020-11-04T13:21:09.712Z', event: '$create_alias', From 08cfdb9ada4d22901916425484167ecc1a3bc543 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:32:33 +0530 Subject: [PATCH 036/147] chore: reuse ga4 network handler for ga4v2 (#3768) --- src/v1/destinations/ga4_v2/networkHandler.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/v1/destinations/ga4_v2/networkHandler.ts diff --git a/src/v1/destinations/ga4_v2/networkHandler.ts b/src/v1/destinations/ga4_v2/networkHandler.ts new file mode 100644 index 00000000000..aece0411c18 --- /dev/null +++ b/src/v1/destinations/ga4_v2/networkHandler.ts @@ -0,0 +1,3 @@ +import { networkHandler } from '../../../v0/destinations/ga4/networkHandler'; + +module.exports = { networkHandler }; From 45b1067d81f3883e19d35634ffec52434fef452f Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:02:46 +0530 Subject: [PATCH 037/147] fix: fixing lytics user_id and anonymousId mapping (#3745) * fix: fixing lytics user_id and anonymousId mapping * fix: adding mapping config for identify call and clean up of native code * fix: adding user and anonymousId mapping for other calls as well --------- Co-authored-by: Krishna Chaitanya --- src/cdk/v2/destinations/lytics/config.ts | 9 + .../lytics/data/LYTICSIdentifyConfig.json | 25 ++ .../v2/destinations/lytics/procWorkflow.yaml | 16 +- src/v0/destinations/lytics/config.js | 27 -- .../lytics/data/LYTICSIdentifyConfig.json | 19 -- .../lytics/data/LYTICSPageScreenConfig.json | 12 - .../lytics/data/LYTICSTrackConfig.json | 12 - src/v0/destinations/lytics/transform.js | 77 ----- .../destinations/lytics/processor/data.ts | 122 +++++++ .../destinations/lytics/router/data.ts | 299 ------------------ 10 files changed, 165 insertions(+), 453 deletions(-) create mode 100644 src/cdk/v2/destinations/lytics/config.ts create mode 100644 src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json delete mode 100644 src/v0/destinations/lytics/config.js delete mode 100644 src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json delete mode 100644 src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json delete mode 100644 src/v0/destinations/lytics/data/LYTICSTrackConfig.json delete mode 100644 src/v0/destinations/lytics/transform.js delete mode 100644 test/integrations/destinations/lytics/router/data.ts diff --git a/src/cdk/v2/destinations/lytics/config.ts b/src/cdk/v2/destinations/lytics/config.ts new file mode 100644 index 00000000000..6756834caa0 --- /dev/null +++ b/src/cdk/v2/destinations/lytics/config.ts @@ -0,0 +1,9 @@ +import { getMappingConfig } from '../../../../v0/util'; + +const CONFIG_CATEGORIES = { + CUSTOMER_PROPERTIES_CONFIG: { name: 'LYTICSIdentifyConfig' }, +}; + +const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); +export const CUSTOMER_PROPERTIES_CONFIG = + MAPPING_CONFIG[CONFIG_CATEGORIES.CUSTOMER_PROPERTIES_CONFIG.name]; diff --git a/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json b/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json new file mode 100644 index 00000000000..c1996d34f7b --- /dev/null +++ b/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json @@ -0,0 +1,25 @@ +[ + { + "destKey": "user_id", + "sourceKeys": "userIdOnly", + "sourceFromGenericMap": true, + "required": false + }, + { + "destKey": "anonymous_id", + "sourceKeys": "anonymousId", + "required": false + }, + { + "destKey": "first_name", + "sourceKeys": "firstName", + "sourceFromGenericMap": true, + "required": false + }, + { + "destKey": "last_name", + "sourceKeys": "lastName", + "sourceFromGenericMap": true, + "required": false + } +] diff --git a/src/cdk/v2/destinations/lytics/procWorkflow.yaml b/src/cdk/v2/destinations/lytics/procWorkflow.yaml index 26221462213..834493e79c3 100644 --- a/src/cdk/v2/destinations/lytics/procWorkflow.yaml +++ b/src/cdk/v2/destinations/lytics/procWorkflow.yaml @@ -5,9 +5,12 @@ bindings: path: ../../../../v0/util - name: removeUndefinedAndNullValues path: ../../../../v0/util + - name: constructPayload + path: ../../../../v0/util - path: ../../bindings/jsontemplate - name: defaultRequestConfig path: ../../../../v0/util + - path: ./config steps: - name: validateInput @@ -24,20 +27,19 @@ steps: condition: $.context.messageType === {{$.EventType.IDENTIFY}} template: | const flattenTraits = $.flattenJson(.message.traits ?? .message.context.traits); - $.context.payload = .message.({ + const payload = $.constructPayload(.message, $.CUSTOMER_PROPERTIES_CONFIG); + $.context.payload = { ...flattenTraits, - first_name: {{{{$.getGenericPaths("firstName")}}}}, - last_name: {{{{$.getGenericPaths("lastName")}}}}, - user_id: {{{{$.getGenericPaths("userId")}}}} - }) + ...payload, + } else: name: payloadForOthers template: | const flattenProperties = $.flattenJson(.message.properties); + const customerPropertiesInfo = $.constructPayload(.message, $.CUSTOMER_PROPERTIES_CONFIG); $.context.payload = .message.({ ...flattenProperties, - first_name: .properties.firstName ?? .properties.firstname, - last_name: .properties.lastName ?? .properties.lastname + ...customerPropertiesInfo }) - name: trackPayload condition: $.context.messageType === {{$.EventType.TRACK}} diff --git a/src/v0/destinations/lytics/config.js b/src/v0/destinations/lytics/config.js deleted file mode 100644 index c7843eda46a..00000000000 --- a/src/v0/destinations/lytics/config.js +++ /dev/null @@ -1,27 +0,0 @@ -const { getMappingConfig } = require('../../util'); - -const ENDPOINT = 'https://api.lytics.io/collect/json'; -const CONFIG_CATEGORIES = { - IDENTIFY: { - name: 'LYTICSIdentifyConfig', - }, - PAGESCREEN: { - name: 'LYTICSPageScreenConfig', - }, - TRACK: { - name: 'LYTICSTrackConfig', - }, -}; - -const forFirstName = ['firstname', 'firstName']; -const forLastName = ['lastname', 'lastName']; - -const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); - -module.exports = { - ENDPOINT, - MAPPING_CONFIG, - CONFIG_CATEGORIES, - forFirstName, - forLastName, -}; diff --git a/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json b/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json deleted file mode 100644 index d9765490e3c..00000000000 --- a/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "destKey": "user_id", - "sourceKeys": [ - "userId", - "traits.userId", - "traits.id", - "context.traits.userId", - "context.traits.id", - "anonymousId" - ], - "required": false - }, - { - "destKey": "", - "sourceKeys": ["traits", "context.traits"], - "required": false - } -] diff --git a/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json b/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json deleted file mode 100644 index f925dbc5bdd..00000000000 --- a/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "destKey": "event", - "sourceKeys": "name", - "required": false - }, - { - "destKey": "", - "sourceKeys": "properties", - "required": false - } -] diff --git a/src/v0/destinations/lytics/data/LYTICSTrackConfig.json b/src/v0/destinations/lytics/data/LYTICSTrackConfig.json deleted file mode 100644 index 5de09eb10b9..00000000000 --- a/src/v0/destinations/lytics/data/LYTICSTrackConfig.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "destKey": "_e", - "sourceKeys": "event", - "required": false - }, - { - "destKey": "", - "sourceKeys": "properties", - "required": false - } -] diff --git a/src/v0/destinations/lytics/transform.js b/src/v0/destinations/lytics/transform.js deleted file mode 100644 index c3a971adba9..00000000000 --- a/src/v0/destinations/lytics/transform.js +++ /dev/null @@ -1,77 +0,0 @@ -const { InstrumentationError } = require('@rudderstack/integrations-lib'); -const { EventType } = require('../../../constants'); -const { - CONFIG_CATEGORIES, - MAPPING_CONFIG, - ENDPOINT, - forFirstName, - forLastName, -} = require('./config'); -const { - constructPayload, - defaultPostRequestConfig, - removeUndefinedAndNullValues, - defaultRequestConfig, - flattenJson, - simpleProcessRouterDest, -} = require('../../util'); -const { JSON_MIME_TYPE } = require('../../util/constant'); - -const responseBuilderSimple = (message, category, destination) => { - const payload = constructPayload(message, MAPPING_CONFIG[category.name]); - const response = defaultRequestConfig(); - const { stream, apiKey } = destination.Config; - response.endpoint = `${ENDPOINT}/${stream}?access_token=${apiKey}`; - response.method = defaultPostRequestConfig.requestMethod; - const flattenedPayload = removeUndefinedAndNullValues(flattenJson(payload)); - forFirstName.forEach((key) => { - if (flattenedPayload[key]) { - flattenedPayload.first_name = flattenedPayload[key]; - delete flattenedPayload[key]; - } - }); - forLastName.forEach((key) => { - if (flattenedPayload[key]) { - flattenedPayload.last_name = flattenedPayload[key]; - delete flattenedPayload[key]; - } - }); - response.body.JSON = flattenedPayload; - response.headers = { - 'Content-Type': JSON_MIME_TYPE, - }; - return response; -}; - -const processEvent = (message, destination) => { - if (!message.type) { - throw new InstrumentationError('Event type is required'); - } - const messageType = message.type; - let category; - switch (messageType.toLowerCase()) { - case EventType.IDENTIFY: - category = CONFIG_CATEGORIES.IDENTIFY; - break; - case EventType.PAGE: - case EventType.SCREEN: - category = CONFIG_CATEGORIES.PAGESCREEN; - break; - case EventType.TRACK: - category = CONFIG_CATEGORIES.TRACK; - break; - default: - throw new InstrumentationError(`Event type ${messageType} is not supported`); - } - // build the response - return responseBuilderSimple(message, category, destination); -}; - -const process = (event) => processEvent(event.message, event.destination); - -const processRouterDest = async (inputs, reqMetadata) => { - const respList = await simpleProcessRouterDest(inputs, process, reqMetadata); - return respList; -}; - -module.exports = { process, processRouterDest }; diff --git a/test/integrations/destinations/lytics/processor/data.ts b/test/integrations/destinations/lytics/processor/data.ts index 344eecc3cdc..dd5511140aa 100644 --- a/test/integrations/destinations/lytics/processor/data.ts +++ b/test/integrations/destinations/lytics/processor/data.ts @@ -143,6 +143,7 @@ export const data = [ body: { JSON: { _e: 'Order Completed', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', checkout_id: 'what is checkout id here??', coupon: 'APPARELSALE', currency: 'GBP', @@ -190,6 +191,7 @@ export const data = [ 'products[2].url': 'https://www.example.com/product/offer-t-shirt', 'products[2].value': 12.99, 'products[2].variant': 'Black', + user_id: 'rudder123', revenue: 31.98, shipping: 4, value: 31.98, @@ -293,6 +295,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -407,6 +410,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -514,6 +518,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -626,6 +631,7 @@ export const data = [ email: 'rudderTest@gmail.com', name: 'Rudder Test', plan: 'Enterprise', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', }, XML: {}, JSON_ARRAY: {}, @@ -732,6 +738,7 @@ export const data = [ email: 'rudderTest@gmail.com', name: 'Rudder Test', plan: 'Enterprise', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', }, XML: {}, JSON_ARRAY: {}, @@ -1116,6 +1123,7 @@ export const data = [ revenue: 31.98, shipping: 4, value: 31.98, + user_id: 'rudder123', }, XML: {}, JSON_ARRAY: {}, @@ -1209,11 +1217,13 @@ export const data = [ body: { JSON: { event: 'ApplicationLoaded', + anonymous_id: '00000000000000000000000000', path: '', referrer: '', search: '', title: '', url: '', + user_id: '12345', }, XML: {}, JSON_ARRAY: {}, @@ -1307,11 +1317,13 @@ export const data = [ body: { JSON: { event: 'ApplicationLoaded', + anonymous_id: '00000000000000000000000000', path: '', referrer: '', search: '', title: '', url: '', + user_id: '12345', }, XML: {}, JSON_ARRAY: {}, @@ -1414,6 +1426,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -1440,4 +1453,113 @@ export const data = [ }, }, }, + { + name: 'lytics', + description: 'Test 11: user_id is mapped to userIdOnly', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.1.6', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, + locale: 'en-GB', + os: { name: '', version: '' }, + page: { + path: '/testing/script-test.html', + referrer: '', + search: '', + title: '', + url: 'http://localhost:3243/testing/script-test.html', + }, + screen: { density: 2 }, + traits: { + company: { id: 'abc123' }, + createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', + email: 'rudderTest@gmail.com', + name: 'Rudder Test', + plan: 'Enterprise', + firstName: 'Rudderstack', + lastname: 'Test', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', + }, + integrations: { All: true }, + messageId: 'e108eb05-f6cd-4624-ba8c-568f2e2b3f92', + originalTimestamp: '2020-10-16T08:26:14.938Z', + receivedAt: '2020-10-16T13:56:14.945+05:30', + request_ip: '[::1]', + sentAt: '2020-10-16T08:26:14.939Z', + timestamp: '2020-10-16T13:56:14.944+05:30', + type: 'identify', + }, + destination: { + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + Config: { apiKey: 'dummyApiKey', stream: 'default' }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + method: 'POST', + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', + headers: { 'Content-Type': 'application/json' }, + params: {}, + body: { + JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + 'company.id': 'abc123', + createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', + email: 'rudderTest@gmail.com', + name: 'Rudder Test', + plan: 'Enterprise', + first_name: 'Rudderstack', + last_name: 'Test', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/lytics/router/data.ts b/test/integrations/destinations/lytics/router/data.ts deleted file mode 100644 index e5d9adae5ca..00000000000 --- a/test/integrations/destinations/lytics/router/data.ts +++ /dev/null @@ -1,299 +0,0 @@ -export const data = [ - { - name: 'lytics', - description: 'Test 0', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.1.6', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, - locale: 'en-GB', - os: { name: '', version: '' }, - page: { - path: '/testing/script-test.html', - referrer: '', - search: '', - title: '', - url: 'http://localhost:3243/testing/script-test.html', - }, - screen: { density: 2 }, - traits: { - company: { id: 'abc123' }, - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', - }, - event: 'Order Completed', - integrations: { All: true }, - messageId: 'a0adfab9-baf7-4e09-a2ce-bbe2844c324a', - timestamp: '2020-10-16T08:10:12.782Z', - properties: { - checkout_id: 'what is checkout id here??', - coupon: 'APPARELSALE', - currency: 'GBP', - order_id: 'transactionId', - products: [ - { - brand: '', - category: 'Merch', - currency: 'GBP', - image_url: 'https://www.example.com/product/bacon-jam.jpg', - name: 'Food/Drink', - position: 1, - price: 3, - product_id: 'product-bacon-jam', - quantity: 2, - sku: 'sku-1', - typeOfProduct: 'Food', - url: 'https://www.example.com/product/bacon-jam', - value: 6, - variant: 'Extra topped', - }, - { - brand: 'Levis', - category: 'Merch', - currency: 'GBP', - image_url: 'https://www.example.com/product/t-shirt.jpg', - name: 'T-Shirt', - position: 2, - price: 12.99, - product_id: 'product-t-shirt', - quantity: 1, - sku: 'sku-2', - typeOfProduct: 'Shirt', - url: 'https://www.example.com/product/t-shirt', - value: 12.99, - variant: 'White', - }, - { - brand: 'Levis', - category: 'Merch', - coupon: 'APPARELSALE', - currency: 'GBP', - image_url: 'https://www.example.com/product/offer-t-shirt.jpg', - name: 'T-Shirt-on-offer', - position: 1, - price: 12.99, - product_id: 'offer-t-shirt', - quantity: 1, - sku: 'sku-3', - typeOfProduct: 'Shirt', - url: 'https://www.example.com/product/offer-t-shirt', - value: 12.99, - variant: 'Black', - }, - ], - revenue: 31.98, - shipping: 4, - value: 31.98, - }, - receivedAt: '2020-10-16T13:40:12.792+05:30', - request_ip: '[::1]', - sentAt: '2020-10-16T08:10:12.783Z', - type: 'track', - userId: 'rudder123', - }, - metadata: { jobId: 1, userId: 'u1' }, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - { - message: { - anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.1.6', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, - locale: 'en-GB', - os: { name: '', version: '' }, - page: { - path: '/testing/script-test.html', - referrer: '', - search: '', - title: '', - url: 'http://localhost:3243/testing/script-test.html', - }, - screen: { density: 2 }, - traits: { - company: { id: 'abc123' }, - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', - }, - integrations: { All: true }, - messageId: 'e108eb05-f6cd-4624-ba8c-568f2e2b3f92', - originalTimestamp: '2020-10-16T08:26:14.938Z', - receivedAt: '2020-10-16T13:56:14.945+05:30', - request_ip: '[::1]', - sentAt: '2020-10-16T08:26:14.939Z', - timestamp: '2020-10-16T13:56:14.944+05:30', - type: 'identify', - userId: 'rudder123', - }, - metadata: { jobId: 2, userId: 'u1' }, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - ], - destType: 'lytics', - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', - headers: { 'Content-Type': 'application/json' }, - params: {}, - body: { - JSON: { - _e: 'Order Completed', - checkout_id: 'what is checkout id here??', - coupon: 'APPARELSALE', - currency: 'GBP', - order_id: 'transactionId', - 'products[0].brand': '', - 'products[0].category': 'Merch', - 'products[0].currency': 'GBP', - 'products[0].image_url': 'https://www.example.com/product/bacon-jam.jpg', - 'products[0].name': 'Food/Drink', - 'products[0].position': 1, - 'products[0].price': 3, - 'products[0].product_id': 'product-bacon-jam', - 'products[0].quantity': 2, - 'products[0].sku': 'sku-1', - 'products[0].typeOfProduct': 'Food', - 'products[0].url': 'https://www.example.com/product/bacon-jam', - 'products[0].value': 6, - 'products[0].variant': 'Extra topped', - 'products[1].brand': 'Levis', - 'products[1].category': 'Merch', - 'products[1].currency': 'GBP', - 'products[1].image_url': 'https://www.example.com/product/t-shirt.jpg', - 'products[1].name': 'T-Shirt', - 'products[1].position': 2, - 'products[1].price': 12.99, - 'products[1].product_id': 'product-t-shirt', - 'products[1].quantity': 1, - 'products[1].sku': 'sku-2', - 'products[1].typeOfProduct': 'Shirt', - 'products[1].url': 'https://www.example.com/product/t-shirt', - 'products[1].value': 12.99, - 'products[1].variant': 'White', - 'products[2].brand': 'Levis', - 'products[2].category': 'Merch', - 'products[2].coupon': 'APPARELSALE', - 'products[2].currency': 'GBP', - 'products[2].image_url': 'https://www.example.com/product/offer-t-shirt.jpg', - 'products[2].name': 'T-Shirt-on-offer', - 'products[2].position': 1, - 'products[2].price': 12.99, - 'products[2].product_id': 'offer-t-shirt', - 'products[2].quantity': 1, - 'products[2].sku': 'sku-3', - 'products[2].typeOfProduct': 'Shirt', - 'products[2].url': 'https://www.example.com/product/offer-t-shirt', - 'products[2].value': 12.99, - 'products[2].variant': 'Black', - revenue: 31.98, - shipping: 4, - value: 31.98, - }, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - metadata: [{ jobId: 1, userId: 'u1' }], - batched: false, - statusCode: 200, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - { - batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', - headers: { 'Content-Type': 'application/json' }, - params: {}, - body: { - JSON: { - user_id: 'rudder123', - 'company.id': 'abc123', - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: false, - statusCode: 200, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - ], - }, - }, - }, - }, -]; From 028e7fc618eb85b72f55a2663ad54bd57a1157dd Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 30 Sep 2024 07:54:46 +0000 Subject: [PATCH 038/147] chore(release): 1.80.0 --- CHANGELOG.md | 18 ++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 854f45b096c..99875dc1b4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.80.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.1...v1.80.0) (2024-09-30) + + +### Features + +* add unity source support in Singular ([#3634](https://github.com/rudderlabs/rudder-transformer/issues/3634)) ([12996d7](https://github.com/rudderlabs/rudder-transformer/commit/12996d7a7ce23de7c150c1c1e012d4dda8668977)) +* onboard shopify to v1 ([#3665](https://github.com/rudderlabs/rudder-transformer/issues/3665)) ([d40e772](https://github.com/rudderlabs/rudder-transformer/commit/d40e772f1a3741c1c4e9ab2365ed464b3988812e)) + + +### Bug Fixes + +* add correct validation for purchase events ([#3766](https://github.com/rudderlabs/rudder-transformer/issues/3766)) ([9cc72f2](https://github.com/rudderlabs/rudder-transformer/commit/9cc72f2288f99ee394977ffeb209faaae657f6d2)) +* braze include fields_to_export to lookup users ([#3761](https://github.com/rudderlabs/rudder-transformer/issues/3761)) ([173b989](https://github.com/rudderlabs/rudder-transformer/commit/173b9895fb2a0bed615f6e3a9c670abe42d5754f)) +* correct typo for order fulfillment event, add test ([#3764](https://github.com/rudderlabs/rudder-transformer/issues/3764)) ([6f92bd3](https://github.com/rudderlabs/rudder-transformer/commit/6f92bd31b60caaa07d18bb86ce5939cd7cc9a416)) +* fixing lytics user_id and anonymousId mapping ([#3745](https://github.com/rudderlabs/rudder-transformer/issues/3745)) ([45b1067](https://github.com/rudderlabs/rudder-transformer/commit/45b1067d81f3883e19d35634ffec52434fef452f)) +* payment info entered event in facebook_conversions ([#3762](https://github.com/rudderlabs/rudder-transformer/issues/3762)) ([7fa7c8d](https://github.com/rudderlabs/rudder-transformer/commit/7fa7c8d3a4f6aefb580cf0de2e64e2f8aef5b5ce)) +* posthog alias mapping swap ([#3765](https://github.com/rudderlabs/rudder-transformer/issues/3765)) ([b6240d0](https://github.com/rudderlabs/rudder-transformer/commit/b6240d06a9d1f7f3bc8f245807f72a72ab40f170)), closes [#3507](https://github.com/rudderlabs/rudder-transformer/issues/3507) + ### [1.79.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.0...v1.79.1) (2024-09-24) diff --git a/package-lock.json b/package-lock.json index ae018a5ec94..13425b9682a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.79.1", + "version": "1.80.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.79.1", + "version": "1.80.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index ede36441eb9..85e5a7152c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.79.1", + "version": "1.80.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From de8e503524c1e8e3320f7458c66b8581f121b9bb Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:30:05 +0530 Subject: [PATCH 039/147] fix: webhook proc workflow object assign bug (#3775) * fix: webhook proc workflow object assign bug * chore: add test for webhook headers --- .../v2/destinations/webhook/procWorkflow.yaml | 2 +- .../destinations/webhook/processor/data.ts | 254 ++++++++++++++++++ 2 files changed, 255 insertions(+), 1 deletion(-) diff --git a/src/cdk/v2/destinations/webhook/procWorkflow.yaml b/src/cdk/v2/destinations/webhook/procWorkflow.yaml index 950af46b96a..bfe7bd4c133 100644 --- a/src/cdk/v2/destinations/webhook/procWorkflow.yaml +++ b/src/cdk/v2/destinations/webhook/procWorkflow.yaml @@ -27,7 +27,7 @@ steps: template: | let defaultHeaders = $.context.method in ['POST', 'PUT', 'PATCH'] ? {"content-type": "application/json"} : {} let configHeaders = $.getHashFromArray(.destination.Config.headers) - let messageHeader = typeof .message.header === "object" ? Object.assign(...Object.entries(.message.header).({[.[0]]:typeof .[1] === 'string' ? .[1] : JSON.stringify(.[1])})[]) : {} + let messageHeader = typeof .message.header === "object" ? Object.assign({}, ...Object.entries(.message.header).({[.[0]]:typeof .[1] === 'string' ? .[1] : JSON.stringify(.[1])})[]) : {} $.context.finalHeaders = { ...defaultHeaders, ...configHeaders, diff --git a/test/integrations/destinations/webhook/processor/data.ts b/test/integrations/destinations/webhook/processor/data.ts index 3add4629bfe..92fe8f50d93 100644 --- a/test/integrations/destinations/webhook/processor/data.ts +++ b/test/integrations/destinations/webhook/processor/data.ts @@ -1,3 +1,5 @@ +import { head } from 'lodash'; + export const data = [ { name: 'webhook', @@ -250,6 +252,258 @@ export const data = [ }, }, }, + { + name: 'webhook', + description: 'Empty headers', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + context: { + device: { + id: 'df16bffa-5c3d-4fbb-9bce-3bab098129a7R', + manufacturer: 'Xiaomi', + model: 'Redmi 6', + name: 'xiaomi', + }, + network: { + carrier: 'Banglalink', + }, + os: { + name: 'android', + version: '8.1.0', + }, + traits: { + address: { + city: 'Dhaka', + country: 'Bangladesh', + }, + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + }, + }, + header: {}, + event: 'spin_result', + integrations: { + All: true, + }, + message_id: 'a80f82be-9bdc-4a9f-b2a5-15621ee41df8', + properties: { + additional_bet_index: 0, + battle_id: 'N/A', + bet_amount: 9, + bet_level: 1, + bet_multiplier: 1, + coin_balance: 9466052, + current_module_name: 'CasinoGameModule', + days_in_game: 0, + extra_param: 'N/A', + fb_profile: '0', + featureGameType: 'N/A', + game_fps: 30, + game_id: 'fireEagleBase', + game_name: 'FireEagleSlots', + gem_balance: 0, + graphicsQuality: 'HD', + idfa: '2bf99787-33d2-4ae2-a76a-c49672f97252', + internetReachability: 'ReachableViaLocalAreaNetwork', + isLowEndDevice: 'False', + is_auto_spin: 'False', + is_turbo: 'False', + isf: 'False', + ishighroller: 'False', + jackpot_win_amount: 90, + jackpot_win_type: 'Silver', + level: 6, + lifetime_gem_balance: 0, + no_of_spin: 1, + player_total_battles: 0, + player_total_shields: 0, + start_date: '2019-08-01', + total_payments: 0, + tournament_id: 'T1561970819', + userId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + versionSessionCount: 2, + win_amount: 0, + }, + timestamp: '2019-09-01T15:46:51.693229+05:30', + type: 'track', + user_properties: { + coin_balance: 9466052, + current_module_name: 'CasinoGameModule', + fb_profile: '0', + game_fps: 30, + game_name: 'FireEagleSlots', + gem_balance: 0, + graphicsQuality: 'HD', + idfa: '2bf99787-33d2-4ae2-a76a-c49672f97252', + internetReachability: 'ReachableViaLocalAreaNetwork', + isLowEndDevice: false, + level: 6, + lifetime_gem_balance: 0, + player_total_battles: 0, + player_total_shields: 0, + start_date: '2019-08-01', + total_payments: 0, + userId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + versionSessionCount: 2, + }, + }, + destination: { + Config: { + webhookUrl: 'http://6b0e6a60.ngrok.io', + headers: [ + { + from: '', + to: '', + }, + { + from: 'test2', + to: 'value2', + }, + ], + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + JSON: { + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + context: { + device: { + id: 'df16bffa-5c3d-4fbb-9bce-3bab098129a7R', + manufacturer: 'Xiaomi', + model: 'Redmi 6', + name: 'xiaomi', + }, + network: { + carrier: 'Banglalink', + }, + os: { + name: 'android', + version: '8.1.0', + }, + traits: { + address: { + city: 'Dhaka', + country: 'Bangladesh', + }, + anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + }, + }, + event: 'spin_result', + integrations: { + All: true, + }, + message_id: 'a80f82be-9bdc-4a9f-b2a5-15621ee41df8', + properties: { + additional_bet_index: 0, + battle_id: 'N/A', + bet_amount: 9, + bet_level: 1, + bet_multiplier: 1, + coin_balance: 9466052, + current_module_name: 'CasinoGameModule', + days_in_game: 0, + extra_param: 'N/A', + fb_profile: '0', + featureGameType: 'N/A', + game_fps: 30, + game_id: 'fireEagleBase', + game_name: 'FireEagleSlots', + gem_balance: 0, + graphicsQuality: 'HD', + idfa: '2bf99787-33d2-4ae2-a76a-c49672f97252', + internetReachability: 'ReachableViaLocalAreaNetwork', + isLowEndDevice: 'False', + is_auto_spin: 'False', + is_turbo: 'False', + isf: 'False', + ishighroller: 'False', + jackpot_win_amount: 90, + jackpot_win_type: 'Silver', + level: 6, + lifetime_gem_balance: 0, + no_of_spin: 1, + player_total_battles: 0, + player_total_shields: 0, + start_date: '2019-08-01', + total_payments: 0, + tournament_id: 'T1561970819', + userId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + versionSessionCount: 2, + win_amount: 0, + }, + timestamp: '2019-09-01T15:46:51.693229+05:30', + type: 'track', + user_properties: { + coin_balance: 9466052, + current_module_name: 'CasinoGameModule', + fb_profile: '0', + game_fps: 30, + game_name: 'FireEagleSlots', + gem_balance: 0, + graphicsQuality: 'HD', + idfa: '2bf99787-33d2-4ae2-a76a-c49672f97252', + internetReachability: 'ReachableViaLocalAreaNetwork', + isLowEndDevice: false, + level: 6, + lifetime_gem_balance: 0, + player_total_battles: 0, + player_total_shields: 0, + start_date: '2019-08-01', + total_payments: 0, + userId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + versionSessionCount: 2, + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + userId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', + type: 'REST', + method: 'POST', + endpoint: 'http://6b0e6a60.ngrok.io', + headers: { + 'content-type': 'application/json', + test2: 'value2', + }, + params: {}, + files: {}, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + statusCode: 200, + }, + ], + }, + }, + }, { name: 'webhook', description: 'Test 1', From 9f5140b194384295c0a56147fed16273b2b7805b Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Fri, 4 Oct 2024 17:00:04 +0530 Subject: [PATCH 040/147] fix: npm start command to include exec --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85e5a7152c1..46c4d037ddd 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lint:fix:json": "eslint --ext .json --fix .", "lint": "npm run format && npm run lint:fix", "check:merge": "npm run verify || exit 1; codecov", - "start": "cd dist;node ./src/index.js;cd ..", + "start": "cd dist;exec node ./src/index.js;cd ..", "build:start": "npm run build && npm run start", "build:ci": "tsc -p tsconfig.json", "build:swagger": "npm run build && npm run setup:swagger", From 168015e5ac1e70c2d224393ddda10eef6374e589 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 4 Oct 2024 11:37:26 +0000 Subject: [PATCH 041/147] chore(release): 1.81.0 --- CHANGELOG.md | 19 +++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99875dc1b4f..a79be1db383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.81.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.1...v1.81.0) (2024-10-04) + + +### Features + +* add unity source support in Singular ([#3634](https://github.com/rudderlabs/rudder-transformer/issues/3634)) ([12996d7](https://github.com/rudderlabs/rudder-transformer/commit/12996d7a7ce23de7c150c1c1e012d4dda8668977)) +* onboard shopify to v1 ([#3665](https://github.com/rudderlabs/rudder-transformer/issues/3665)) ([d40e772](https://github.com/rudderlabs/rudder-transformer/commit/d40e772f1a3741c1c4e9ab2365ed464b3988812e)) + + +### Bug Fixes + +* add correct validation for purchase events ([#3766](https://github.com/rudderlabs/rudder-transformer/issues/3766)) ([9cc72f2](https://github.com/rudderlabs/rudder-transformer/commit/9cc72f2288f99ee394977ffeb209faaae657f6d2)) +* braze include fields_to_export to lookup users ([#3761](https://github.com/rudderlabs/rudder-transformer/issues/3761)) ([173b989](https://github.com/rudderlabs/rudder-transformer/commit/173b9895fb2a0bed615f6e3a9c670abe42d5754f)) +* correct typo for order fulfillment event, add test ([#3764](https://github.com/rudderlabs/rudder-transformer/issues/3764)) ([6f92bd3](https://github.com/rudderlabs/rudder-transformer/commit/6f92bd31b60caaa07d18bb86ce5939cd7cc9a416)) +* fixing lytics user_id and anonymousId mapping ([#3745](https://github.com/rudderlabs/rudder-transformer/issues/3745)) ([45b1067](https://github.com/rudderlabs/rudder-transformer/commit/45b1067d81f3883e19d35634ffec52434fef452f)) +* npm start command to include exec ([9f5140b](https://github.com/rudderlabs/rudder-transformer/commit/9f5140b194384295c0a56147fed16273b2b7805b)) +* payment info entered event in facebook_conversions ([#3762](https://github.com/rudderlabs/rudder-transformer/issues/3762)) ([7fa7c8d](https://github.com/rudderlabs/rudder-transformer/commit/7fa7c8d3a4f6aefb580cf0de2e64e2f8aef5b5ce)) +* posthog alias mapping swap ([#3765](https://github.com/rudderlabs/rudder-transformer/issues/3765)) ([b6240d0](https://github.com/rudderlabs/rudder-transformer/commit/b6240d06a9d1f7f3bc8f245807f72a72ab40f170)), closes [#3507](https://github.com/rudderlabs/rudder-transformer/issues/3507) + ## [1.80.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.1...v1.80.0) (2024-09-30) diff --git a/package-lock.json b/package-lock.json index 13425b9682a..243b989a6d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.80.0", + "version": "1.81.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.80.0", + "version": "1.81.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 46c4d037ddd..8a104f3081f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.80.0", + "version": "1.81.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From a84dd4a6d9d94e5875030168697472f0d26faf23 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:49:33 +0530 Subject: [PATCH 042/147] chore: add missed track entries for fulfillment discount events (#3772) * chore: add missed track entries for fulfillment discount events * chore: update config --- src/v0/sources/shopify/config.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/v0/sources/shopify/config.js b/src/v0/sources/shopify/config.js index 7f5d41ec964..f0a844830ba 100644 --- a/src/v0/sources/shopify/config.js +++ b/src/v0/sources/shopify/config.js @@ -52,10 +52,12 @@ const SHOPIFY_TRACK_MAP = { discounts_create: 'Discount Created', discounts_delete: 'Discount Deleted', discounts_update: 'Discount Updated', + discounts_redeemcode_added: 'Discount Redeemcode Added', + discounts_redeemcode_removed: 'Discount Redeemcode Removed', draft_orders_create: 'Draft Order Created', draft_orders_delete: 'Draft Order Deleted', draft_orders_update: 'Draft Order Updated', - fulfillment_order_split: 'Fulfillment Order Split', + fulfillment_orders_split: 'Fulfillment Orders Split', inventory_items_create: 'Inventory Items Created', inventory_items_delete: 'Inventory Items Deleted', inventory_items_update: 'Inventory Items Updated', @@ -141,11 +143,13 @@ const SUPPORTED_TRACK_EVENTS = [ 'collection_publications_update', 'discounts_create', 'discounts_delete', + 'discounts_redeemcode_added', + 'discounts_redeemcode_removed', 'discounts_update', 'draft_orders_create', 'draft_orders_delete', 'draft_orders_update', - 'fulfillment_order_split', + 'fulfillment_orders_split', 'inventory_items_create', 'inventory_items_delete', 'inventory_items_update', From f8cde8c072eb9415368fb97f53a3070027a3943b Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:34:11 +0530 Subject: [PATCH 043/147] feat: onboard intercom v2 destination (#3721) * feat: onboard intercom v2 destination (initial commit) * feat: intercom v2 native integration * fix: lint error * fix: addressing comments * fix: addressing comments * fix: addressing comment * fix: address comment --- src/features.json | 3 +- src/v0/destinations/intercom_v2/config.js | 28 + .../intercom_v2/data/IntercomGroupConfig.json | 47 + .../data/IntercomIdentifyConfig.json | 51 + .../intercom_v2/data/IntercomTrackConfig.json | 33 + .../intercom_v2/networkHandler.js | 67 ++ src/v0/destinations/intercom_v2/transform.js | 187 ++++ src/v0/destinations/intercom_v2/utils.js | 332 +++++++ .../destinations/intercom_v2/common.ts | 150 +++ .../intercom_v2/dataDelivery/business.ts | 516 ++++++++++ .../intercom_v2/dataDelivery/data.ts | 9 + .../intercom_v2/dataDelivery/oauth.ts | 196 ++++ .../destinations/intercom_v2/network.ts | 751 +++++++++++++++ .../destinations/intercom_v2/router/data.ts | 883 ++++++++++++++++++ 14 files changed, 3252 insertions(+), 1 deletion(-) create mode 100644 src/v0/destinations/intercom_v2/config.js create mode 100644 src/v0/destinations/intercom_v2/data/IntercomGroupConfig.json create mode 100644 src/v0/destinations/intercom_v2/data/IntercomIdentifyConfig.json create mode 100644 src/v0/destinations/intercom_v2/data/IntercomTrackConfig.json create mode 100644 src/v0/destinations/intercom_v2/networkHandler.js create mode 100644 src/v0/destinations/intercom_v2/transform.js create mode 100644 src/v0/destinations/intercom_v2/utils.js create mode 100644 test/integrations/destinations/intercom_v2/common.ts create mode 100644 test/integrations/destinations/intercom_v2/dataDelivery/business.ts create mode 100644 test/integrations/destinations/intercom_v2/dataDelivery/data.ts create mode 100644 test/integrations/destinations/intercom_v2/dataDelivery/oauth.ts create mode 100644 test/integrations/destinations/intercom_v2/network.ts create mode 100644 test/integrations/destinations/intercom_v2/router/data.ts diff --git a/src/features.json b/src/features.json index 097e4a8aa0b..4c7fc7b231d 100644 --- a/src/features.json +++ b/src/features.json @@ -80,7 +80,8 @@ "X_AUDIENCE": true, "BLOOMREACH_CATALOG": true, "SMARTLY": true, - "HTTP": true + "HTTP": true, + "INTERCOM_V2": true }, "regulations": [ "BRAZE", diff --git a/src/v0/destinations/intercom_v2/config.js b/src/v0/destinations/intercom_v2/config.js new file mode 100644 index 00000000000..c7cb43b093c --- /dev/null +++ b/src/v0/destinations/intercom_v2/config.js @@ -0,0 +1,28 @@ +const { getMappingConfig } = require('../../util'); + +const destType = 'INTERCOM_V2'; + +const ApiVersions = { + v2: '2.10', +}; + +const ConfigCategory = { + IDENTIFY: { + name: 'IntercomIdentifyConfig', + }, + TRACK: { + name: 'IntercomTrackConfig', + }, + GROUP: { + name: 'IntercomGroupConfig', + }, +}; + +const MappingConfig = getMappingConfig(ConfigCategory, __dirname); + +module.exports = { + destType, + ConfigCategory, + MappingConfig, + ApiVersions, +}; diff --git a/src/v0/destinations/intercom_v2/data/IntercomGroupConfig.json b/src/v0/destinations/intercom_v2/data/IntercomGroupConfig.json new file mode 100644 index 00000000000..d357d2bb5df --- /dev/null +++ b/src/v0/destinations/intercom_v2/data/IntercomGroupConfig.json @@ -0,0 +1,47 @@ +[ + { + "destKey": "company_id", + "sourceKeys": "groupId", + "sourceFromGenericMap": true, + "required": true + }, + { + "destKey": "name", + "sourceKeys": "name", + "sourceFromGenericMap": true + }, + { + "destKey": "website", + "sourceKeys": "website", + "sourceFromGenericMap": true + }, + { + "destKey": "plan", + "sourceKeys": ["traits.plan", "context.traits.plan"] + }, + { + "destKey": "size", + "sourceKeys": ["traits.size", "context.traits.size"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "industry", + "sourceKeys": ["traits.industry", "context.traits.industry"] + }, + { + "destKey": "monthly_spend", + "sourceKeys": ["traits.monthlySpend", "context.traits.monthlySpend"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "remote_created_at", + "sourceKeys": ["traits.remoteCreatedAt", "context.traits.remoteCreatedAt"], + "metadata": { + "type": "secondTimestamp" + } + } +] diff --git a/src/v0/destinations/intercom_v2/data/IntercomIdentifyConfig.json b/src/v0/destinations/intercom_v2/data/IntercomIdentifyConfig.json new file mode 100644 index 00000000000..7ace2e030d2 --- /dev/null +++ b/src/v0/destinations/intercom_v2/data/IntercomIdentifyConfig.json @@ -0,0 +1,51 @@ +[ + { + "destKey": "external_id", + "sourceKeys": "userIdOnly", + "sourceFromGenericMap": true + }, + { + "destKey": "email", + "sourceKeys": "email", + "sourceFromGenericMap": true + }, + { + "destKey": "phone", + "sourceKeys": "phone", + "sourceFromGenericMap": true + }, + { + "destKey": "avatar", + "sourceKeys": "avatar", + "sourceFromGenericMap": true + }, + { + "destKey": "last_seen_at", + "sourceKeys": ["context.traits.lastSeenAt", "last_seen_at"], + "metadata": { + "type": "secondTimestamp" + } + }, + { + "destKey": "role", + "sourceKeys": ["traits.role", "context.traits.role"] + }, + { + "destKey": "signed_up_at", + "sourceKeys": ["traits.createdAt", "context.traits.createdAt"], + "metadata": { + "type": "secondTimestamp" + } + }, + { + "destKey": "owner_id", + "sourceKeys": ["traits.ownerId", "context.traits.ownerId"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "unsubscribed_from_emails", + "sourceKeys": ["traits.unsubscribedFromEmails", "context.traits.unsubscribedFromEmails"] + } +] diff --git a/src/v0/destinations/intercom_v2/data/IntercomTrackConfig.json b/src/v0/destinations/intercom_v2/data/IntercomTrackConfig.json new file mode 100644 index 00000000000..f5ab226cce7 --- /dev/null +++ b/src/v0/destinations/intercom_v2/data/IntercomTrackConfig.json @@ -0,0 +1,33 @@ +[ + { + "destKey": "user_id", + "sourceKeys": "userIdOnly", + "sourceFromGenericMap": true + }, + { + "destKey": "email", + "sourceKeys": "email", + "sourceFromGenericMap": true + }, + { + "destKey": "event_name", + "sourceKeys": "event", + "required": true + }, + { + "destKey": "created_at", + "sourceKeys": "timestamp", + "sourceFromGenericMap": true, + "metadata": { + "type": "secondTimestamp" + } + }, + { + "destKey": "id", + "sourceKeys": ["message.properties.id", "message.traits.id"] + }, + { + "destKey": "metadata", + "sourceKeys": "properties" + } +] diff --git a/src/v0/destinations/intercom_v2/networkHandler.js b/src/v0/destinations/intercom_v2/networkHandler.js new file mode 100644 index 00000000000..3f06460588f --- /dev/null +++ b/src/v0/destinations/intercom_v2/networkHandler.js @@ -0,0 +1,67 @@ +const { RetryableError, NetworkError } = require('@rudderstack/integrations-lib'); +const { + processAxiosResponse, + getDynamicErrorType, +} = require('../../../adapters/utils/networkUtils'); +const { AUTH_STATUS_INACTIVE } = require('../../../adapters/networkhandler/authConstants'); +const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network'); +const { TransformerProxyError } = require('../../util/errorTypes'); +const tags = require('../../util/tags'); +const { isHttpStatusSuccess } = require('../../util'); + +// ref: https://github.com/intercom/oauth2-intercom +// Intercom's OAuth implementation does not use refresh tokens. Access tokens are valid until a user revokes access manually, or until an app deauthorizes itself. +const getAuthErrCategory = (status) => { + if (status === 401) { + return AUTH_STATUS_INACTIVE; + } + return ''; +}; + +const errorResponseHandler = (destinationResponse, dest) => { + const { response, status } = destinationResponse; + const message = `[Intercom V2 Response Handler] Request failed for destination ${dest} with status: ${status}`; + if (status === 401) { + throw new TransformerProxyError( + `${message}. ${JSON.stringify(response)}`, + 400, + { + [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), + }, + destinationResponse, + getAuthErrCategory(status), + ); + } + if (status === 408) { + throw new RetryableError(message, 500, destinationResponse, getAuthErrCategory(status)); + } + if (!isHttpStatusSuccess(status)) { + throw new NetworkError( + `${message}. ${JSON.stringify(response)}`, + status, + { + [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), + }, + destinationResponse, + ); + } +}; + +const responseHandler = (responseParams) => { + const { destinationResponse, destType } = responseParams; + errorResponseHandler(destinationResponse, destType); + return { + destinationResponse: destinationResponse.response, + message: 'Request Processed Successfully', + status: destinationResponse.status, + }; +}; + +function networkHandler() { + this.prepareProxy = prepareProxyRequest; + this.proxy = proxyRequest; + this.processAxiosResponse = processAxiosResponse; + this.responseHandler = responseHandler; +} + +module.exports = { networkHandler }; diff --git a/src/v0/destinations/intercom_v2/transform.js b/src/v0/destinations/intercom_v2/transform.js new file mode 100644 index 00000000000..8d97e20bde7 --- /dev/null +++ b/src/v0/destinations/intercom_v2/transform.js @@ -0,0 +1,187 @@ +const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const { + handleRtTfSingleEventError, + getSuccessRespEvents, + getEventType, + constructPayload, + getIntegrationsObj, +} = require('../../util'); +const { EventType } = require('../../../constants'); +const { + getHeaders, + searchContact, + handleDetachUserAndCompany, + getResponse, + createOrUpdateCompany, + attachContactToCompany, + addOrUpdateTagsToCompany, + getStatusCode, + getBaseEndpoint, +} = require('./utils'); +const { + getName, + filterCustomAttributes, + addMetadataToPayload, +} = require('../../../cdk/v2/destinations/intercom/utils'); +const { MappingConfig, ConfigCategory } = require('./config'); + +const transformIdentifyPayload = (event) => { + const { message, destination } = event; + const category = ConfigCategory.IDENTIFY; + const payload = constructPayload(message, MappingConfig[category.name]); + const shouldSendAnonymousId = destination.Config.sendAnonymousId; + if (!payload.external_id && shouldSendAnonymousId) { + payload.external_id = message.anonymousId; + } + if (!(payload.external_id || payload.email)) { + throw new InstrumentationError('Either email or userId is required for Identify call'); + } + payload.name = getName(message); + payload.custom_attributes = message.traits || message.context.traits || {}; + payload.custom_attributes = filterCustomAttributes(payload, 'user', destination); + return payload; +}; + +const transformTrackPayload = (event) => { + const { message, destination } = event; + const category = ConfigCategory.TRACK; + let payload = constructPayload(message, MappingConfig[category.name]); + if (!payload.id) { + const integrationsObj = getIntegrationsObj(message, 'INTERCOM'); + payload.id = integrationsObj?.id; + } + const shouldSendAnonymousId = destination.Config.sendAnonymousId; + if (!payload.user_id && shouldSendAnonymousId) { + payload.user_id = message.anonymousId; + } + if (!(payload.user_id || payload.email || payload.id)) { + throw new InstrumentationError('Either email or userId or id is required for Track call'); + } + payload = addMetadataToPayload(payload); + return payload; +}; + +const transformGroupPayload = (event) => { + const { message, destination } = event; + const category = ConfigCategory.GROUP; + const payload = constructPayload(message, MappingConfig[category.name]); + payload.custom_attributes = message.traits || message.context.traits || {}; + payload.custom_attributes = filterCustomAttributes(payload, 'company', destination); + return payload; +}; + +const constructIdentifyResponse = async (event) => { + const { destination, metadata } = event; + + const payload = transformIdentifyPayload(event); + + let method = 'POST'; + let endpoint = `${getBaseEndpoint(destination)}/contacts`; + const headers = getHeaders(metadata); + + // when contact is found in intercom + const contactId = await searchContact(event); + if (contactId) { + method = 'PUT'; + endpoint += `/${contactId}`; + + // detach user and company if required + await handleDetachUserAndCompany(contactId, event); + } + + return getResponse(method, endpoint, headers, payload); +}; + +const constructTrackResponse = (event) => { + const { destination, metadata } = event; + const payload = transformTrackPayload(event); + const method = 'POST'; + const endpoint = `${getBaseEndpoint(destination)}/events`; + const headers = getHeaders(metadata); + + return getResponse(method, endpoint, headers, payload); +}; + +const constructGroupResponse = async (event) => { + const { destination, metadata } = event; + const payload = transformGroupPayload(event); + + const method = 'POST'; + let endpoint = `${getBaseEndpoint(destination)}/companies`; + const headers = getHeaders(metadata); + let finalPayload = payload; + + // create or update company + const companyId = await createOrUpdateCompany(payload, destination, metadata); + + // when contact is found in intercom + const contactId = await searchContact(event); + if (contactId) { + // attach user and company + finalPayload = { + id: companyId, + }; + endpoint = `${getBaseEndpoint(destination)}/contacts/${contactId}/companies`; + await attachContactToCompany(finalPayload, endpoint, destination, metadata); + } + + // add tags to company + await addOrUpdateTagsToCompany(companyId, event); + + return getResponse(method, endpoint, headers, finalPayload); +}; + +const processEvent = async (event) => { + const { message } = event; + const messageType = getEventType(message); + let response; + switch (messageType) { + case EventType.IDENTIFY: + response = await constructIdentifyResponse(event); + break; + case EventType.TRACK: + response = constructTrackResponse(event); + break; + case EventType.GROUP: + response = await constructGroupResponse(event); + break; + default: + throw new InstrumentationError(`message type ${messageType} is not supported.`); + } + return response; +}; + +const process = async (event) => { + const response = await processEvent(event); + return response; +}; + +const processRouter = async (inputs, reqMetadata) => { + const results = await Promise.all( + inputs.map(async (event) => { + try { + const response = await process(event); + return getSuccessRespEvents( + response, + [event.metadata], + event.destination, + false, + getStatusCode(event), + ); + } catch (error) { + return handleRtTfSingleEventError(event, error, reqMetadata); + } + }), + ); + return results; +}; + +const processRouterDest = async (inputs, reqMetadata) => { + if (!inputs || inputs.length === 0) { + return []; + } + const response = await processRouter(inputs, reqMetadata); + return response; +}; + +module.exports = { processRouterDest }; diff --git a/src/v0/destinations/intercom_v2/utils.js b/src/v0/destinations/intercom_v2/utils.js new file mode 100644 index 00000000000..69ea1385d93 --- /dev/null +++ b/src/v0/destinations/intercom_v2/utils.js @@ -0,0 +1,332 @@ +const { + removeUndefinedAndNullValues, + InstrumentationError, + NetworkError, + InvalidAuthTokenError, +} = require('@rudderstack/integrations-lib'); +const { EventType } = require('../../../constants'); +const { JSON_MIME_TYPE } = require('../../util/constant'); +const tags = require('../../util/tags'); +const { + getFieldValueFromMessage, + isHttpStatusSuccess, + defaultRequestConfig, + getEventType, +} = require('../../util'); +const { HTTP_STATUS_CODES } = require('../../util/constant'); +const { + SEARCH_CONTACT_ENDPOINT, + CREATE_OR_UPDATE_COMPANY_ENDPOINT, + TAGS_ENDPOINT, + BASE_ENDPOINT, + BASE_EU_ENDPOINT, + BASE_AU_ENDPOINT, +} = require('../../../cdk/v2/destinations/intercom/config'); +const { getLookUpField } = require('../../../cdk/v2/destinations/intercom/utils'); +const { handleHttpRequest } = require('../../../adapters/network'); +const { getAccessToken } = require('../../util'); +const { ApiVersions, destType } = require('./config'); +const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); + +/** + * method to handle error during api call + * ref docs: https://developers.intercom.com/docs/references/rest-api/errors/http-responses/ + * e.g. + * 400 - code: parameter_not_found (or parameter_invalid), message: company not specified + * 401 - code: unauthorized, message: Access Token Invalid + * 404 - code: company_not_found, message: Company Not Found + * @param {*} message + * @param {*} processedResponse + */ +const intercomErrorHandler = (message, processedResponse) => { + const errorMessages = JSON.stringify(processedResponse.response); + if (processedResponse.status === 400) { + throw new InstrumentationError(`${message} : ${errorMessages}`); + } + if (processedResponse.status === 401) { + throw new InvalidAuthTokenError(message, 400, errorMessages); + } + if (processedResponse.status === 404) { + throw new InstrumentationError(`${message} : ${errorMessages}`); + } + throw new NetworkError( + `${message} : ${errorMessages}`, + processedResponse.status, + { + [tags]: getDynamicErrorType(processedResponse.status), + }, + processedResponse, + ); +}; + +const getHeaders = (metadata) => ({ + Authorization: `Bearer ${getAccessToken(metadata, 'accessToken')}`, + Accept: JSON_MIME_TYPE, + 'Content-Type': JSON_MIME_TYPE, + 'Intercom-Version': ApiVersions.v2, +}); + +const getBaseEndpoint = (destination) => { + const { apiServer } = destination.Config; + switch (apiServer) { + case 'Europe': + return BASE_EU_ENDPOINT; + case 'Australia': + return BASE_AU_ENDPOINT; + default: + return BASE_ENDPOINT; + } +}; + +const getStatusCode = (event) => { + const { message } = event; + let statusCode = HTTP_STATUS_CODES.OK; + const messageType = getEventType(message); + if (messageType === EventType.GROUP) { + statusCode = HTTP_STATUS_CODES.SUPPRESS_EVENTS; + } + return statusCode; +}; + +const getResponse = (method, endpoint, headers, payload) => { + const response = defaultRequestConfig(); + response.method = method; + response.endpoint = endpoint; + response.headers = headers; + response.body.JSON = removeUndefinedAndNullValues(payload); + return response; +}; + +const searchContact = async (event) => { + const { message, destination, metadata } = event; + const lookupField = getLookUpField(message); + let lookupFieldValue = getFieldValueFromMessage(message, lookupField); + if (!lookupFieldValue) { + lookupFieldValue = message?.context?.traits?.[lookupField]; + } + const data = JSON.stringify({ + query: { + operator: 'AND', + value: [ + { + field: lookupField, + operator: '=', + value: lookupFieldValue, + }, + ], + }, + }); + + const headers = getHeaders(metadata); + const endpoint = `${getBaseEndpoint(destination)}/${SEARCH_CONTACT_ENDPOINT}`; + const statTags = { + destType, + feature: 'transformation', + endpointPath: '/contacts/search', + requestMethod: 'POST', + module: 'router', + metadata, + }; + + const { processedResponse: response } = await handleHttpRequest( + 'POST', + endpoint, + data, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to search contact due to', response); + } + return response.response?.data.length > 0 ? response.response?.data[0]?.id : null; +}; + +const getCompanyId = async (company, destination, metadata) => { + if (!company.id && !company.name) return undefined; + const headers = getHeaders(metadata); + + const queryParam = company.id ? `company_id=${company.id}` : `name=${company.name}`; + const endpoint = `${getBaseEndpoint(destination)}/companies?${queryParam}`; + + const statTags = { + metadata, + destType, + feature: 'transformation', + endpointPath: '/companies', + requestMethod: 'GET', + module: 'router', + }; + + const { processedResponse: response } = await handleHttpRequest( + 'GET', + endpoint, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to get company id due to', response); + } + + return response?.response?.id; +}; + +const detachContactAndCompany = async (contactId, company, destination, metadata) => { + const companyId = await getCompanyId(company, destination, metadata); + if (!companyId) return; + + const headers = getHeaders(metadata); + const endpoint = `${getBaseEndpoint(destination)}/contacts/${contactId}/companies/${companyId}`; + + const statTags = { + metadata, + destType, + feature: 'transformation', + endpointPath: 'contacts/companies', + requestMethod: 'DELETE', + module: 'router', + }; + + const { processedResponse: response } = await handleHttpRequest( + 'DELETE', + endpoint, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to detach contact and company due to', response); + } +}; + +const handleDetachUserAndCompany = async (contactId, event) => { + const { message, destination, metadata } = event; + const company = message?.traits?.company || message?.context?.traits?.company; + const shouldDetachUserAndCompany = company?.remove; + if (shouldDetachUserAndCompany) { + await detachContactAndCompany(contactId, company, destination, metadata); + } +}; + +const createOrUpdateCompany = async (payload, destination, metadata) => { + const headers = getHeaders(metadata); + const endpoint = `${getBaseEndpoint(destination)}/${CREATE_OR_UPDATE_COMPANY_ENDPOINT}`; + + const finalPayload = JSON.stringify(removeUndefinedAndNullValues(payload)); + + const statTags = { + metadata, + destType, + feature: 'transformation', + endpointPath: '/companies', + requestMethod: 'POST', + module: 'router', + }; + + const { processedResponse: response } = await handleHttpRequest( + 'POST', + endpoint, + finalPayload, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to Create or Update Company due to', response); + } + + return response.response?.id; +}; + +const attachContactToCompany = async (payload, endpoint, destination, metadata) => { + const headers = getHeaders(metadata); + const finalPayload = JSON.stringify(removeUndefinedAndNullValues(payload)); + + const statTags = { + metadata, + destType, + feature: 'transformation', + endpointPath: '/contact/{id}/companies', + requestMethod: 'POST', + module: 'router', + }; + + const { processedResponse: response } = await handleHttpRequest( + 'POST', + endpoint, + finalPayload, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to attach Contact or User to Company due to', response); + } +}; + +const addOrUpdateTagsToCompany = async (id, event) => { + const { message, destination, metadata } = event; + const companyTags = message?.traits?.tags || message?.context?.traits?.tags; + if (!companyTags) return; + + const headers = getHeaders(metadata); + const endpoint = `${getBaseEndpoint(destination)}/${TAGS_ENDPOINT}`; + + const statTags = { + destType, + feature: 'transformation', + endpointPath: '/tags', + requestMethod: 'POST', + module: 'router', + metadata, + }; + + await Promise.all( + companyTags.map(async (tag) => { + const finalPayload = { + name: tag, + companies: [ + { + id, + }, + ], + }; + const { processedResponse: response } = await handleHttpRequest( + 'POST', + endpoint, + finalPayload, + { + headers, + }, + statTags, + ); + + if (!isHttpStatusSuccess(response.status)) { + intercomErrorHandler('Unable to Add or Update the Tag to Company due to', response); + } + }), + ); +}; + +module.exports = { + getStatusCode, + getHeaders, + searchContact, + handleDetachUserAndCompany, + getResponse, + createOrUpdateCompany, + attachContactToCompany, + addOrUpdateTagsToCompany, + getBaseEndpoint, +}; diff --git a/test/integrations/destinations/intercom_v2/common.ts b/test/integrations/destinations/intercom_v2/common.ts new file mode 100644 index 00000000000..60c7e02b330 --- /dev/null +++ b/test/integrations/destinations/intercom_v2/common.ts @@ -0,0 +1,150 @@ +import { Destination } from '../../../../src/types'; + +const destTypeInUpperCase = 'INTERCOM_V2'; +const channel = 'web'; +const originalTimestamp = '2023-11-10T14:42:44.724Z'; +const timestamp = '2023-11-22T10:12:44.757+05:30'; +const anonymousId = 'test-anonymous-id'; + +const destination: Destination = { + ID: '123', + Name: destTypeInUpperCase, + DestinationDefinition: { + ID: '123', + Name: destTypeInUpperCase, + DisplayName: 'Intercom V2', + Config: {}, + }, + Config: { + apiServer: 'US', + sendAnonymousId: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +const destinationApiServerEU: Destination = { + ID: '123', + Name: destTypeInUpperCase, + DestinationDefinition: { + ID: '123', + Name: destTypeInUpperCase, + DisplayName: 'Intercom V2', + Config: {}, + }, + Config: { + apiServer: 'Europe', + sendAnonymousId: true, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +const destinationApiServerAU: Destination = { + ID: '123', + Name: destTypeInUpperCase, + DestinationDefinition: { + ID: '123', + Name: destTypeInUpperCase, + DisplayName: 'Intercom V2', + Config: {}, + }, + Config: { + apiServer: 'Australia', + sendAnonymousId: true, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +const userTraits = { + age: 23, + email: 'test@rudderlabs.com', + phone: '+91 9999999999', + firstName: 'John', + lastName: 'Snow', + address: 'california usa', + ownerId: '13', +}; + +const detachUserCompanyUserTraits = { + age: 23, + email: 'detach-user-company@rudderlabs.com', + phone: '+91 9999999999', + firstName: 'John', + lastName: 'Snow', + address: 'california usa', + ownerId: '13', +}; + +const companyTraits = { + email: 'known-email@rudderlabs.com', + name: 'RudderStack', + size: 500, + website: 'www.rudderstack.com', + industry: 'CDP', + plan: 'enterprise', + remoteCreatedAt: '2024-09-12T14:40:33.996+05:30', +}; + +const properties = { + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + price: { + amount: 3000, + currency: 'USD', + }, +}; + +const headers = { + Authorization: 'Bearer default-accessToken', + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Intercom-Version': '2.10', +}; + +const headersWithRevokedAccessToken = { + ...headers, + Authorization: 'Bearer revoked-accessToken', +}; + +const RouterInstrumentationErrorStatTags = { + destType: destTypeInUpperCase, + errorCategory: 'dataValidation', + errorType: 'instrumentation', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + feature: 'router', +}; + +const RouterNetworkErrorStatTags = { + ...RouterInstrumentationErrorStatTags, + errorCategory: 'network', + errorType: 'aborted', +}; + +export { + channel, + destination, + originalTimestamp, + timestamp, + destinationApiServerEU, + destinationApiServerAU, + userTraits, + companyTraits, + properties, + detachUserCompanyUserTraits, + anonymousId, + headers, + headersWithRevokedAccessToken, + RouterInstrumentationErrorStatTags, + RouterNetworkErrorStatTags, +}; diff --git a/test/integrations/destinations/intercom_v2/dataDelivery/business.ts b/test/integrations/destinations/intercom_v2/dataDelivery/business.ts new file mode 100644 index 00000000000..c75993bc7a7 --- /dev/null +++ b/test/integrations/destinations/intercom_v2/dataDelivery/business.ts @@ -0,0 +1,516 @@ +import { + generateMetadata, + generateProxyV0Payload, + generateProxyV1Payload, +} from '../../../testUtils'; +import { headers, RouterNetworkErrorStatTags } from '../common'; +import { ProxyV1TestData } from '../../../testTypes'; + +const createUserPayload = { + email: 'test-unsupported-media@rudderlabs.com', + external_id: 'user-id-1', + name: 'John Snow', +}; + +const conflictUserPayload = { + email: 'conflict@test.com', + user_id: 'conflict_test_user_id_1', +}; + +const statTags = { + ...RouterNetworkErrorStatTags, + errorType: 'retryable', + feature: 'dataDelivery', +}; + +export const testScenariosForV0API = [ + { + id: 'INTERCOM_V2_v0_other_scenario_1', + name: 'intercom_v2', + description: + '[Proxy v0 API] :: Scenario to test Malformed Payload Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + JSON: { + custom_attributes: { + isOpenSource: true, + }, + }, + headers, + endpoint: 'https://api.intercom.io/contacts/proxy-contact-id', + method: 'PUT', + }), + }, + }, + output: { + response: { + status: 400, + body: { + output: { + destinationResponse: { + response: { + errors: [ + { + code: 'parameter_invalid', + message: "Custom attribute 'isOpenSource' does not exist", + }, + ], + request_id: 'request_1', + type: 'error.list', + }, + status: 400, + }, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 400. {"request_id":"request_1","type":"error.list","errors":[{"code":"parameter_invalid","message":"Custom attribute \'isOpenSource\' does not exist"}]}', + status: 400, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v0_other_scenario_2', + name: 'intercom_v2', + description: '[Proxy v0 API] :: Scenario to test Rate Limit Exceeded Handling from Destination', + successCriteria: 'Should return 429 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + JSON: { + email: 'new@test.com', + }, + endpoint: 'https://api.intercom.io/contacts/proxy-contact-id', + method: 'PUT', + headers, + }), + }, + }, + output: { + response: { + status: 429, + body: { + output: { + destinationResponse: { + response: { + errors: [ + { + code: 'rate_limit_exceeded', + message: 'The rate limit for the App has been exceeded', + }, + ], + request_id: 'request125', + type: 'error.list', + }, + status: 429, + }, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 429. {"errors":[{"code":"rate_limit_exceeded","message":"The rate limit for the App has been exceeded"}],"request_id":"request125","type":"error.list"}', + status: 429, + statTags: { + ...statTags, + errorType: 'throttled', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v0_other_scenario_3', + name: 'intercom_v2', + description: '[Proxy v0 API] :: Scenario to test Conflict User Handling from Destination', + successCriteria: 'Should return 409 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + JSON: conflictUserPayload, + headers, + endpoint: 'https://api.intercom.io/contacts', + method: 'POST', + }), + }, + }, + output: { + response: { + status: 409, + body: { + output: { + destinationResponse: { + response: { + errors: [ + { + code: 'conflict', + message: 'A contact matching those details already exists with id=test', + }, + ], + request_id: 'request126', + type: 'error.list', + }, + status: 409, + }, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 409. {"errors":[{"code":"conflict","message":"A contact matching those details already exists with id=test"}],"request_id":"request126","type":"error.list"}', + status: 409, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v0_other_scenario_4', + name: 'intercom_v2', + description: '[Proxy v0 API] :: Scenario to test Unsupported Media Handling from Destination', + successCriteria: 'Should return 406 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + JSON: createUserPayload, + headers: { + ...headers, + Accept: 'test', + 'Content-Type': 'test', + }, + endpoint: 'https://api.intercom.io/contacts', + method: 'POST', + }), + }, + }, + output: { + response: { + status: 406, + body: { + output: { + destinationResponse: { + response: { + errors: [ + { + code: 'media_type_not_acceptable', + message: 'The Accept header should send a media type of application/json', + }, + ], + type: 'error.list', + }, + status: 406, + }, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 406. {"errors":[{"code":"media_type_not_acceptable","message":"The Accept header should send a media type of application/json"}],"type":"error.list"}', + status: 406, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v0_other_scenario_5', + name: 'intercom_v2', + description: '[Proxy v0 API] :: Request Timeout Error Handling from Destination', + successCriteria: 'Should return 500 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + JSON: { + email: 'time-out@gmail.com', + }, + endpoint: 'https://api.intercom.io/contacts', + headers, + method: 'POST', + }), + }, + }, + output: { + response: { + status: 500, + body: { + output: { + status: 500, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 408', + destinationResponse: { + response: { + type: 'error.list', + request_id: 'req-123', + errors: [ + { + code: 'Request Timeout', + message: 'The server would not wait any longer for the client', + }, + ], + }, + status: 408, + }, + statTags, + }, + }, + }, + }, + }, +]; + +export const testScenariosForV1API: ProxyV1TestData[] = [ + { + id: 'INTERCOM_V2_v1_other_scenario_1', + name: 'intercom_v2', + description: + '[Proxy v1 API] :: Scenario to test Malformed Payload Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + JSON: { + custom_attributes: { + isOpenSource: true, + }, + }, + headers, + endpoint: 'https://api.intercom.io/contacts/proxy-contact-id', + method: 'PUT', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + response: [ + { + error: + '{"request_id":"request_1","type":"error.list","errors":[{"code":"parameter_invalid","message":"Custom attribute \'isOpenSource\' does not exist"}]}', + statusCode: 400, + metadata: generateMetadata(1), + }, + ], + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 400. {"request_id":"request_1","type":"error.list","errors":[{"code":"parameter_invalid","message":"Custom attribute \'isOpenSource\' does not exist"}]}', + status: 400, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v1_other_scenario_2', + name: 'intercom_v2', + description: '[Proxy v1 API] :: Scenario to test Rate Limit Exceeded Handling from Destination', + successCriteria: 'Should return 429 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + JSON: { + email: 'new@test.com', + }, + endpoint: 'https://api.intercom.io/contacts/proxy-contact-id', + headers, + method: 'PUT', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + response: [ + { + error: + '{"errors":[{"code":"rate_limit_exceeded","message":"The rate limit for the App has been exceeded"}],"request_id":"request125","type":"error.list"}', + statusCode: 429, + metadata: generateMetadata(1), + }, + ], + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 429. {"errors":[{"code":"rate_limit_exceeded","message":"The rate limit for the App has been exceeded"}],"request_id":"request125","type":"error.list"}', + status: 429, + statTags: { + ...statTags, + errorType: 'throttled', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v1_other_scenario_3', + name: 'intercom_v2', + description: '[Proxy v1 API] :: Scenario to test Conflict User Handling from Destination', + successCriteria: 'Should return 409 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + JSON: conflictUserPayload, + headers, + endpoint: 'https://api.intercom.io/contacts', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + response: [ + { + error: + '{"errors":[{"code":"conflict","message":"A contact matching those details already exists with id=test"}],"request_id":"request126","type":"error.list"}', + statusCode: 409, + metadata: generateMetadata(1), + }, + ], + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 409. {"errors":[{"code":"conflict","message":"A contact matching those details already exists with id=test"}],"request_id":"request126","type":"error.list"}', + status: 409, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v1_other_scenario_4', + name: 'intercom_v2', + description: '[Proxy v1 API] :: Scenario to test Unsupported Media Handling from Destination', + successCriteria: 'Should return 406 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + JSON: createUserPayload, + headers: { + ...headers, + Accept: 'test', + 'Content-Type': 'test', + }, + endpoint: 'https://api.intercom.io/contacts', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + response: [ + { + error: + '{"errors":[{"code":"media_type_not_acceptable","message":"The Accept header should send a media type of application/json"}],"type":"error.list"}', + statusCode: 406, + metadata: generateMetadata(1), + }, + ], + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 406. {"errors":[{"code":"media_type_not_acceptable","message":"The Accept header should send a media type of application/json"}],"type":"error.list"}', + status: 406, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v1_other_scenario_5', + name: 'intercom_v2', + description: '[Proxy v1 API] :: Request Timeout Error Handling from Destination', + successCriteria: 'Should return 500 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + JSON: { + email: 'time-out@gmail.com', + }, + endpoint: 'https://api.intercom.io/contacts', + headers, + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 500, + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 408', + response: [ + { + error: + '{"type":"error.list","request_id":"req-123","errors":[{"code":"Request Timeout","message":"The server would not wait any longer for the client"}]}', + metadata: generateMetadata(1), + statusCode: 500, + }, + ], + statTags, + }, + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/intercom_v2/dataDelivery/data.ts b/test/integrations/destinations/intercom_v2/dataDelivery/data.ts new file mode 100644 index 00000000000..1286b70f28c --- /dev/null +++ b/test/integrations/destinations/intercom_v2/dataDelivery/data.ts @@ -0,0 +1,9 @@ +import { oauthScenariosV0, oauthScenariosV1 } from './oauth'; +import { testScenariosForV0API, testScenariosForV1API } from './business'; + +export const data = [ + ...oauthScenariosV0, + ...oauthScenariosV1, + ...testScenariosForV0API, + ...testScenariosForV1API, +]; diff --git a/test/integrations/destinations/intercom_v2/dataDelivery/oauth.ts b/test/integrations/destinations/intercom_v2/dataDelivery/oauth.ts new file mode 100644 index 00000000000..8f36a4bd55f --- /dev/null +++ b/test/integrations/destinations/intercom_v2/dataDelivery/oauth.ts @@ -0,0 +1,196 @@ +import { ProxyV1TestData } from '../../../testTypes'; +import { generateMetadata, generateProxyV1Payload } from '../../../testUtils'; +import { headers, headersWithRevokedAccessToken, RouterNetworkErrorStatTags } from '../common'; + +const commonRequestParameters = { + endpoint: `https://api.intercom.io/events`, + JSON: { + created_at: 1700628164, + email: 'test@rudderlabs.com', + event_name: 'Product Viewed', + metadata: { + price: { + amount: 3000, + currency: 'USD', + }, + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + }, + user_id: 'user-id-1', + }, +}; + +export const oauthScenariosV0 = [ + { + id: 'INTERCOM_V2_v0_oauth_scenario_1', + name: 'intercom_v2', + description: '[Proxy v0 API] :: [oauth] app event fails due to revoked access token', + successCriteria: 'Should return 400 with revoked access token error', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV1Payload({ + ...commonRequestParameters, + headers: headersWithRevokedAccessToken, + accessToken: 'revoked-accessToken', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 400, + body: { + output: { + destinationResponse: { + response: { + errors: [ + { + code: 'unauthorized', + message: 'Access Token Invalid', + }, + ], + request_id: 'request_id-1', + type: 'error.list', + }, + status: 401, + }, + statTags: { + ...RouterNetworkErrorStatTags, + feature: 'dataDelivery', + }, + authErrorCategory: 'AUTH_STATUS_INACTIVE', + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 401. {"type":"error.list","request_id":"request_id-1","errors":[{"code":"unauthorized","message":"Access Token Invalid"}]}', + status: 400, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v0_oauth_scenario_2', + name: 'intercom_v2', + description: '[Proxy v0 API] :: [oauth] success case', + successCriteria: 'Should return 200 response', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV1Payload({ + ...commonRequestParameters, + headers, + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 202, + message: 'Request Processed Successfully', + destinationResponse: '', + }, + }, + }, + }, + }, +]; + +export const oauthScenariosV1: ProxyV1TestData[] = [ + { + id: 'INTERCOM_V2_v1_oauth_scenario_1', + name: 'intercom_v2', + description: '[Proxy v1 API] :: [oauth] app event fails due to revoked access token', + successCriteria: 'Should return 400 with revoked access token error', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + ...commonRequestParameters, + headers: headersWithRevokedAccessToken, + accessToken: 'revoked-accessToken', + }), + method: 'POST', + }, + }, + output: { + response: { + status: 400, + body: { + output: { + response: [ + { + error: + '{"type":"error.list","request_id":"request_id-1","errors":[{"code":"unauthorized","message":"Access Token Invalid"}]}', + statusCode: 400, + metadata: { + ...generateMetadata(1), + secret: { accessToken: 'revoked-accessToken' }, + }, + }, + ], + statTags: { + ...RouterNetworkErrorStatTags, + feature: 'dataDelivery', + }, + authErrorCategory: 'AUTH_STATUS_INACTIVE', + message: + '[Intercom V2 Response Handler] Request failed for destination intercom_v2 with status: 401. {"type":"error.list","request_id":"request_id-1","errors":[{"code":"unauthorized","message":"Access Token Invalid"}]}', + status: 400, + }, + }, + }, + }, + }, + { + id: 'INTERCOM_V2_v1_oauth_scenario_2', + name: 'intercom_v2', + description: '[Proxy v1 API] :: [oauth] success case', + successCriteria: 'Should return 200 response', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload({ + ...commonRequestParameters, + headers, + }), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 202, + message: 'Request Processed Successfully', + response: [ + { + statusCode: 202, + metadata: generateMetadata(1), + error: '""', + }, + ], + }, + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/intercom_v2/network.ts b/test/integrations/destinations/intercom_v2/network.ts new file mode 100644 index 00000000000..26ff3c38ee2 --- /dev/null +++ b/test/integrations/destinations/intercom_v2/network.ts @@ -0,0 +1,751 @@ +import { headers, headersWithRevokedAccessToken } from './common'; + +const deliveryCallsData = [ + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'test@rudderlabs.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/companies', + data: { + company_id: 'rudderlabs', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + remote_created_at: 1726132233, + }, + headers, + }, + httpRes: { + status: 200, + data: { + type: 'company', + company_id: 'rudderlabs', + id: 'company-id-by-intercom', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + created_at: 1701930212, + updated_at: 1701930212, + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'known-email@rudderlabs.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/tags', + data: { + name: 'tag-1', + companies: [ + { + id: 'company-id-by-intercom', + }, + ], + }, + headers, + }, + httpRes: { + status: 200, + data: { + type: 'tag', + name: 'tag-1', + id: '123', + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/tags', + data: { + name: 'tag-2', + companies: [ + { + id: 'company-id-by-intercom', + }, + ], + }, + headers, + }, + httpRes: { + status: 200, + data: { + type: 'tag', + name: 'tag-2', + id: '123', + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/companies', + data: { + company_id: 'rudderlabs', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + remote_created_at: 1726132233, + custom_attributes: { + isOpenSource: true, + }, + }, + headers, + }, + httpRes: { + status: 400, + data: { + type: 'error.list', + request_id: 'request_id-1', + errors: [ + { + code: 'parameter_invalid', + message: "Custom attribute 'isOpenSource' does not exist", + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.eu.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'test@rudderlabs.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'userId', operator: '=', value: 'known-user-id-1' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'contact-id-by-intercom-known-user-id-1', + workspace_id: 'rudderWorkspace', + external_id: 'user-id-1', + role: 'user', + email: 'test@rudderlabs.com', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/companies', + data: { + company_id: 'rudderlabs', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + remote_created_at: 1726132233, + }, + headers, + }, + httpRes: { + status: 200, + data: { + type: 'company', + company_id: 'rudderlabs', + id: 'au-company-id-by-intercom', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + created_at: 1701930212, + updated_at: 1701930212, + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'known-email@rudderlabs.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'au-contact-id-by-intercom-known-email', + workspace_id: 'rudderWorkspace', + external_id: 'known-user-id-1-au', + role: 'user', + email: 'known-email@rudderlabs.com', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/au-contact-id-by-intercom-known-email/companies', + data: { + id: 'au-company-id-by-intercom', + }, + headers, + }, + httpRes: { + status: 200, + data: { + type: 'company', + company_id: 'rudderlabs', + id: 'company-id-by-intercom', + name: 'RudderStack', + website: 'www.rudderstack.com', + plan: 'enterprise', + size: 500, + industry: 'CDP', + user_count: 1, + remote_created_at: 1374138000, + created_at: 1701930212, + updated_at: 1701930212, + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'detach-user-company@rudderlabs.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'contact-id-by-intercom-detached-from-company', + workspace_id: 'rudderWorkspace', + external_id: 'detach-company-user-id', + role: 'user', + email: 'detach-user-company@rudderlabs.com', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'get', + url: 'https://api.intercom.io/companies?company_id=company id', + data: {}, + headers, + }, + httpRes: { + status: 200, + data: { + id: '123', + }, + }, + }, + { + httpReq: { + method: 'delete', + url: 'https://api.intercom.io/contacts/contact-id-by-intercom-detached-from-company/companies/123', + data: {}, + headers, + }, + httpRes: { + status: 200, + data: {}, + }, + }, + { + httpReq: { + method: 'get', + url: 'https://api.intercom.io/companies?company_id=unavailable company id', + data: {}, + headers, + }, + httpRes: { + status: 404, + data: { + type: 'error.list', + request_id: 'req123', + errors: [ + { + code: 'company_not_found', + message: 'Company Not Found', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'get', + url: 'https://api.intercom.io/companies?company_id=other company id', + data: {}, + headers, + }, + httpRes: { + status: 200, + data: { + id: 'other123', + }, + }, + }, + { + httpReq: { + method: 'delete', + url: 'https://api.intercom.io/contacts/contact-id-by-intercom-detached-from-company/companies/other123', + data: {}, + headers, + }, + httpRes: { + status: 404, + data: { + type: 'error.list', + request_id: 'req123', + errors: [ + { + code: 'company_not_found', + message: 'Company Not Found', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/events', + data: { + created_at: 1700628164, + email: 'test@rudderlabs.com', + event_name: 'Product Viewed', + metadata: { + price: { + amount: 3000, + currency: 'USD', + }, + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + }, + user_id: 'user-id-1', + }, + headers: headersWithRevokedAccessToken, + }, + httpRes: { + status: 401, + data: { + type: 'error.list', + request_id: 'request_id-1', + errors: [ + { + code: 'unauthorized', + message: 'Access Token Invalid', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/events', + data: { + created_at: 1700628164, + email: 'test@rudderlabs.com', + event_name: 'Product Viewed', + metadata: { + price: { + amount: 3000, + currency: 'USD', + }, + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + }, + user_id: 'user-id-1', + }, + headers, + }, + httpRes: { + status: 202, + }, + }, + { + httpReq: { + method: 'put', + url: 'https://api.intercom.io/contacts/proxy-contact-id', + data: { + custom_attributes: { + isOpenSource: true, + }, + }, + headers, + }, + httpRes: { + status: 400, + data: { + request_id: 'request_1', + type: 'error.list', + errors: [ + { + code: 'parameter_invalid', + message: "Custom attribute 'isOpenSource' does not exist", + }, + ], + }, + }, + }, + { + httpReq: { + method: 'put', + url: 'https://api.intercom.io/contacts/proxy-contact-id', + data: { + email: 'new@test.com', + }, + headers, + }, + httpRes: { + status: 429, + data: { + errors: [ + { + code: 'rate_limit_exceeded', + message: 'The rate limit for the App has been exceeded', + }, + ], + request_id: 'request125', + type: 'error.list', + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts', + data: { + email: 'conflict@test.com', + user_id: 'conflict_test_user_id_1', + }, + headers, + }, + httpRes: { + status: 409, + data: { + errors: [ + { + code: 'conflict', + message: 'A contact matching those details already exists with id=test', + }, + ], + request_id: 'request126', + type: 'error.list', + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts', + data: { + email: 'test-unsupported-media@rudderlabs.com', + external_id: 'user-id-1', + name: 'John Snow', + }, + headers: { + ...headers, + Accept: 'test', + 'Content-Type': 'test', + }, + }, + httpRes: { + status: 406, + data: { + errors: [ + { + code: 'media_type_not_acceptable', + message: 'The Accept header should send a media type of application/json', + }, + ], + type: 'error.list', + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts', + data: { + email: 'time-out@gmail.com', + }, + headers, + }, + httpRes: { + status: 408, + data: { + type: 'error.list', + request_id: 'req-123', + errors: [ + { + code: 'Request Timeout', + message: 'The server would not wait any longer for the client', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'test@rudderlabs.com' }], + }, + }, + headers: headersWithRevokedAccessToken, + }, + httpRes: { + status: 401, + data: { + type: 'error.list', + request_id: 'request_id-1', + errors: [ + { + code: 'unauthorized', + message: 'Access Token Invalid', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'known-user-2-company@gmail.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'au-contact-id-by-intercom-known-user-2-company', + workspace_id: 'rudderWorkspace', + external_id: 'known-user-id-2-au', + role: 'user', + email: 'known-user-2-company@gmail.com', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/au-contact-id-by-intercom-known-user-2-company/companies', + data: { + id: 'au-company-id-by-intercom', + }, + headers, + }, + httpRes: { + status: 404, + data: { + type: 'error.list', + request_id: 'req-1234', + errors: [ + { + code: 'company_not_found', + message: 'Company Not Found', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/tags', + data: { + name: 'tag-3', + companies: [ + { + id: 'company-id-by-intercom', + }, + ], + }, + headers, + }, + httpRes: { + status: 404, + data: { + type: 'error.list', + request_id: 'req-1234', + errors: [ + { + code: 'company_not_found', + message: 'Company Not Found', + }, + ], + }, + }, + }, +]; + +export const networkCallsData = [...deliveryCallsData]; diff --git a/test/integrations/destinations/intercom_v2/router/data.ts b/test/integrations/destinations/intercom_v2/router/data.ts new file mode 100644 index 00000000000..76569140590 --- /dev/null +++ b/test/integrations/destinations/intercom_v2/router/data.ts @@ -0,0 +1,883 @@ +import { RouterTransformationRequest } from '../../../../../src/types'; +import { generateMetadata } from '../../../testUtils'; +import { + anonymousId, + channel, + companyTraits, + destination, + destinationApiServerAU, + destinationApiServerEU, + detachUserCompanyUserTraits, + headers, + originalTimestamp, + properties, + RouterInstrumentationErrorStatTags, + RouterNetworkErrorStatTags, + timestamp, + userTraits, +} from '../common'; +import { RouterTestData } from '../../../testTypes'; + +const routerRequest1: RouterTransformationRequest = { + input: [ + { + destination, + message: { + userId: 'user-id-1', + channel, + context: { + traits: { + ...userTraits, + company: { + id: 'company id', + name: 'Test Company', + }, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(1), + }, + { + destination, + message: { + userId: 'user-id-1', + channel, + context: { + traits: userTraits, + }, + properties: properties, + event: 'Product Viewed', + type: 'track', + originalTimestamp, + timestamp, + integrations: { + All: true, + intercom: { + id: 'id-by-intercom', + }, + }, + }, + metadata: generateMetadata(2), + }, + { + destination, + message: { + groupId: 'rudderlabs', + channel, + traits: { + ...companyTraits, + tags: ['tag-1', 'tag-2'], + }, + type: 'group', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(3), + }, + { + destination, + message: { + groupId: 'rudderlabs', + channel, + traits: { + ...companyTraits, + isOpenSource: true, + }, + type: 'group', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(4), + }, + { + destination, + message: { + userId: 'user-id-1', + channel, + context: { + traits: { + ...userTraits, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: { + ...generateMetadata(5), + secret: { + accessToken: 'revoked-accessToken', + }, + }, + }, + { + destination, + message: { + groupId: 'rudderlabs', + channel, + traits: { + ...companyTraits, + tags: ['tag-3'], + }, + type: 'group', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(6), + }, + ], + destType: 'intercom_v2', +}; + +// eu server and send anonymous id true +const routerRequest2: RouterTransformationRequest = { + input: [ + { + destination: destinationApiServerEU, + message: { + anonymousId, + channel, + context: { + traits: userTraits, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(1), + }, + { + destination: destinationApiServerEU, + message: { + anonymousId, + channel, + context: { + traits: userTraits, + }, + properties: properties, + event: 'Product Viewed', + type: 'track', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(2), + }, + ], + destType: 'intercom_v2', +}; + +// au server and when contact found in intercom +const routerRequest3: RouterTransformationRequest = { + input: [ + { + destination: destinationApiServerAU, + message: { + userId: 'known-user-id-1', + channel, + context: { + traits: userTraits, + }, + type: 'identify', + integrations: { + All: true, + Intercom: { + lookup: 'userId', + }, + }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(1), + }, + { + destination: destinationApiServerAU, + message: { + groupId: 'rudderlabs', + channel, + traits: companyTraits, + type: 'group', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(2), + }, + { + destination: destinationApiServerAU, + message: { + groupId: 'rudderlabs', + channel, + traits: { + ...companyTraits, + email: 'known-user-2-company@gmail.com', + }, + type: 'group', + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(3), + }, + ], + destType: 'intercom_v2', +}; + +// detach user and company +const routerRequest4: RouterTransformationRequest = { + input: [ + { + destination, + message: { + userId: 'detach-company-user-id', + channel, + context: { + traits: { + ...detachUserCompanyUserTraits, + company: { + id: 'company id', + name: 'Test Company', + remove: true, + }, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(1), + }, + { + destination: destination, + message: { + userId: 'detach-company-user-id', + channel, + context: { + traits: { + ...detachUserCompanyUserTraits, + company: { + id: 'unavailable company id', + name: 'Test Company', + remove: true, + }, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(2), + }, + { + destination: destination, + message: { + userId: 'detach-company-user-id', + channel, + context: { + traits: { + ...detachUserCompanyUserTraits, + company: { + id: 'other company id', + name: 'Test Company', + remove: true, + }, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(3), + }, + ], + destType: 'intercom_v2', +}; + +// validation +const routerRequest5: RouterTransformationRequest = { + input: [ + { + destination, + message: { + channel, + context: { + traits: { + ...userTraits, + email: null, + }, + }, + type: 'identify', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(1), + }, + { + destination, + message: { + channel, + context: { + traits: { + ...userTraits, + email: null, + }, + }, + event: 'Product Viewed', + type: 'track', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(2), + }, + { + destination, + message: { + channel, + context: { + traits: { + ...userTraits, + }, + }, + type: 'track', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(3), + }, + { + destination, + message: { + channel, + context: { + traits: { + ...companyTraits, + }, + }, + type: 'group', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(4), + }, + { + destination, + message: { + channel, + context: { + traits: { + ...companyTraits, + }, + }, + type: 'dummyGroupType', + integrations: { All: true }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(5), + }, + ], + destType: 'intercom_v2', +}; + +export const data: RouterTestData[] = [ + { + id: 'INTERCOM-V2-router-test-1', + scenario: 'Framework', + successCriteria: + 'Some events should be transformed successfully and some should fail for apiVersion v2', + name: 'intercom_v2', + description: 'INTERCOM V2 router tests', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest1, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + batchedRequest: { + body: { + JSON: { + email: 'test@rudderlabs.com', + external_id: 'user-id-1', + name: 'John Snow', + owner_id: 13, + phone: '+91 9999999999', + custom_attributes: { + address: 'california usa', + age: 23, + }, + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/contacts', + files: {}, + headers, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(1)], + statusCode: 200, + }, + { + batched: false, + batchedRequest: { + body: { + FORM: {}, + JSON: { + created_at: 1700628164, + email: 'test@rudderlabs.com', + event_name: 'Product Viewed', + metadata: { + price: { + amount: 3000, + currency: 'USD', + }, + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + }, + user_id: 'user-id-1', + id: 'id-by-intercom', + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.intercom.io/events', + files: {}, + headers, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(2)], + statusCode: 200, + }, + { + batched: false, + batchedRequest: { + body: { + JSON: { + company_id: 'rudderlabs', + name: 'RudderStack', + size: 500, + website: 'www.rudderstack.com', + industry: 'CDP', + plan: 'enterprise', + remote_created_at: 1726132233, + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/companies', + files: {}, + headers, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(3)], + statusCode: 299, + }, + { + batched: false, + error: + 'Unable to Create or Update Company due to : {"type":"error.list","request_id":"request_id-1","errors":[{"code":"parameter_invalid","message":"Custom attribute \'isOpenSource\' does not exist"}]}', + statTags: { + ...RouterInstrumentationErrorStatTags, + }, + destination, + metadata: [generateMetadata(4)], + statusCode: 400, + }, + { + batched: false, + error: + '{"message":"Unable to search contact due to","destinationResponse":"{\\"type\\":\\"error.list\\",\\"request_id\\":\\"request_id-1\\",\\"errors\\":[{\\"code\\":\\"unauthorized\\",\\"message\\":\\"Access Token Invalid\\"}]}"}', + statTags: { + ...RouterNetworkErrorStatTags, + errorType: 'retryable', + meta: 'invalidAuthToken', + }, + destination, + metadata: [ + { + ...generateMetadata(5), + secret: { + accessToken: 'revoked-accessToken', + }, + }, + ], + statusCode: 400, + }, + { + batched: false, + error: + 'Unable to Add or Update the Tag to Company due to : {"type":"error.list","request_id":"req-1234","errors":[{"code":"company_not_found","message":"Company Not Found"}]}', + statTags: { + ...RouterInstrumentationErrorStatTags, + }, + destination, + metadata: [generateMetadata(6)], + statusCode: 400, + }, + ], + }, + }, + }, + }, + { + id: 'INTERCOM-V2-router-test-2', + scenario: 'Framework', + successCriteria: 'Events should be transformed successfully for apiVersion v2', + name: 'intercom_v2', + description: + 'INTERCOM V2 router tests with sendAnonymousId true for apiVersion v2 and eu apiServer', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest2, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.eu.intercom.io/contacts', + headers, + params: {}, + body: { + JSON: { + email: 'test@rudderlabs.com', + external_id: 'test-anonymous-id', + name: 'John Snow', + owner_id: 13, + phone: '+91 9999999999', + custom_attributes: { + address: 'california usa', + age: 23, + }, + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: false, + statusCode: 200, + destination: destinationApiServerEU, + }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.eu.intercom.io/events', + headers, + params: {}, + body: { + JSON: { + created_at: 1700628164, + email: 'test@rudderlabs.com', + event_name: 'Product Viewed', + metadata: { + price: { + amount: 3000, + currency: 'USD', + }, + revenue: { + amount: 1232, + currency: 'inr', + test: 123, + }, + }, + user_id: 'test-anonymous-id', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(2)], + batched: false, + statusCode: 200, + destination: destinationApiServerEU, + }, + ], + }, + }, + }, + }, + { + id: 'INTERCOM-V2-router-test-3', + scenario: 'Framework', + successCriteria: 'Events should be transformed successfully for apiVersion v2', + name: 'intercom_v2', + description: + 'INTERCOM V2 router tests when contact is found in intercom for au apiServer and apiVersion v2', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest3, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + batchedRequest: { + body: { + JSON: { + email: 'test@rudderlabs.com', + external_id: 'known-user-id-1', + name: 'John Snow', + owner_id: 13, + phone: '+91 9999999999', + custom_attributes: { + address: 'california usa', + age: 23, + }, + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: + 'https://api.au.intercom.io/contacts/contact-id-by-intercom-known-user-id-1', + files: {}, + headers, + method: 'PUT', + params: {}, + type: 'REST', + version: '1', + }, + destination: destinationApiServerAU, + metadata: [generateMetadata(1)], + statusCode: 200, + }, + { + batched: false, + batchedRequest: { + body: { + JSON: { + id: 'au-company-id-by-intercom', + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: + 'https://api.au.intercom.io/contacts/au-contact-id-by-intercom-known-email/companies', + files: {}, + headers, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: destinationApiServerAU, + metadata: [generateMetadata(2)], + statusCode: 299, + }, + { + batched: false, + error: + 'Unable to attach Contact or User to Company due to : {"type":"error.list","request_id":"req-1234","errors":[{"code":"company_not_found","message":"Company Not Found"}]}', + statTags: { + ...RouterInstrumentationErrorStatTags, + }, + destination: destinationApiServerAU, + metadata: [generateMetadata(3)], + statusCode: 400, + }, + ], + }, + }, + }, + }, + { + id: 'INTERCOM-V2-router-test-4', + scenario: 'Framework', + successCriteria: + 'Some identify events should be transformed successfully and some should fail for apiVersion v2', + name: 'intercom', + description: + 'INTERCOM V2 router tests for detaching contact from company in intercom for apiVersion v2', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest4, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + batchedRequest: { + body: { + JSON: { + email: 'detach-user-company@rudderlabs.com', + external_id: 'detach-company-user-id', + name: 'John Snow', + owner_id: 13, + phone: '+91 9999999999', + custom_attributes: { + address: 'california usa', + age: 23, + }, + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: + 'https://api.intercom.io/contacts/contact-id-by-intercom-detached-from-company', + files: {}, + headers, + method: 'PUT', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(1)], + statusCode: 200, + }, + { + batched: false, + error: + 'Unable to get company id due to : {"type":"error.list","request_id":"req123","errors":[{"code":"company_not_found","message":"Company Not Found"}]}', + statTags: RouterInstrumentationErrorStatTags, + destination: destination, + metadata: [generateMetadata(2)], + statusCode: 400, + }, + { + batched: false, + error: + 'Unable to detach contact and company due to : {"type":"error.list","request_id":"req123","errors":[{"code":"company_not_found","message":"Company Not Found"}]}', + statTags: RouterInstrumentationErrorStatTags, + destination: destination, + metadata: [generateMetadata(3)], + statusCode: 400, + }, + ], + }, + }, + }, + }, + { + id: 'INTERCOM-V2-router-test-5', + scenario: 'Framework', + successCriteria: 'validation should pass for apiVersion v2', + name: 'intercom_v2', + description: 'INTERCOM V2 router validation tests', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: routerRequest5, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + error: 'Either email or userId is required for Identify call', + statTags: RouterInstrumentationErrorStatTags, + destination, + metadata: [generateMetadata(1)], + statusCode: 400, + }, + { + batched: false, + error: 'Either email or userId or id is required for Track call', + statTags: RouterInstrumentationErrorStatTags, + destination, + metadata: [generateMetadata(2)], + statusCode: 400, + }, + { + batched: false, + error: 'Missing required value from "event"', + statTags: RouterInstrumentationErrorStatTags, + destination, + metadata: [generateMetadata(3)], + statusCode: 400, + }, + { + batched: false, + error: 'Missing required value from "groupId"', + statTags: RouterInstrumentationErrorStatTags, + destination, + metadata: [generateMetadata(4)], + statusCode: 400, + }, + { + batched: false, + error: 'message type dummygrouptype is not supported.', + statTags: RouterInstrumentationErrorStatTags, + destination, + metadata: [generateMetadata(5)], + statusCode: 400, + }, + ], + }, + }, + }, + }, +]; From f3046f0ae37c113c1239d988d056fc204f2776a0 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:41:12 +0530 Subject: [PATCH 044/147] fix: rakuten amount value rounded up to nearest integer (#3784) * fix: rakuten amount value rounded up to nearest integer * fix: review comments addressed --- src/cdk/v2/destinations/rakuten/utils.js | 22 ++++--- src/cdk/v2/destinations/rakuten/utils.test.js | 62 ++++++++++++++++++- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/cdk/v2/destinations/rakuten/utils.js b/src/cdk/v2/destinations/rakuten/utils.js index 2dd628a2503..b4897c46ed9 100644 --- a/src/cdk/v2/destinations/rakuten/utils.js +++ b/src/cdk/v2/destinations/rakuten/utils.js @@ -17,6 +17,18 @@ const constructProperties = (message) => { return payload; }; +/** + * Calculates the amount for a single product + * @param {Object} product + * @returns {number} + */ +const calculateProductAmount = (product) => { + if (!product?.amount && !product?.price) { + throw new InstrumentationError('Either amount or price is required for every product'); + } + return Math.round(product.amount * 100 || (product.quantity || 1) * 100 * product.price); +}; + /** * This fucntion build the item level list * @param {*} properties @@ -52,14 +64,8 @@ const constructLineItems = (properties) => { }); // Map 'amountList' by evaluating 'amount' or deriving it from 'price' and 'quantity' - const amountList = products.map((product) => { - if (!product?.amount && !product?.price) { - throw new InstrumentationError('Either amount or price is required for every product'); - } - return product.amount * 100 || (product.quantity || 1) * 100 * product.price; - }); - productList.amtlist = amountList.join('|'); + productList.amtlist = products.map(calculateProductAmount).join('|'); return productList; }; -module.exports = { constructProperties, constructLineItems }; +module.exports = { constructProperties, constructLineItems, calculateProductAmount }; diff --git a/src/cdk/v2/destinations/rakuten/utils.test.js b/src/cdk/v2/destinations/rakuten/utils.test.js index 9cc7f5fd4cc..2d82037b1cf 100644 --- a/src/cdk/v2/destinations/rakuten/utils.test.js +++ b/src/cdk/v2/destinations/rakuten/utils.test.js @@ -1,4 +1,5 @@ -const { constructLineItems } = require('./utils'); +const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const { constructLineItems, calculateProductAmount } = require('./utils'); describe('constructLineItems', () => { it('should return a non-empty object when given a valid properties object with at least one product', () => { const properties = { @@ -115,3 +116,62 @@ describe('constructLineItems', () => { ); }); }); + +describe('calculateProductAmount', () => { + // Calculates product amount correctly when amount is defined + it('should return the correct product amount when amount is defined', () => { + const product = { amount: 5 }; + const result = calculateProductAmount(product); + expect(result).toBe(500); + }); + + // Throws error when both amount and price are undefined or null + it('should throw an error when both amount and price are undefined or null', () => { + const product = {}; + expect(() => calculateProductAmount(product)).toThrow(InstrumentationError); + }); + + // Calculates product amount correctly when price and quantity are defined + it('should calculate product amount correctly when price and quantity are defined', () => { + const product = { amount: 10, price: 5, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(1000); + }); + + // Returns correct value when only price is defined and quantity defaults to 1 + it('should return correct value when only price is defined and quantity defaults to 1', () => { + const product = { price: 20 }; + const result = calculateProductAmount(product); + expect(result).toEqual(2000); + }); + + // Handles cases where amount is a floating-point number + it('should handle cases where amount is a floating-point number', () => { + const product = { amount: 5.5, price: 10, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(550); + }); + + it('should handle cases where amount is a floating-point number', () => { + const product = { amount: 5.1, price: 10, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(510); + }); + + it('should handle cases where amount is a floating-point number', () => { + const product = { amount: 5.19, price: 10, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(519); + }); + + it('should handle cases where amount is a floating-point number', () => { + const product = { amount: 5.199, price: 10, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(520); + }); + it('should handle cases where amount is a floating-point number', () => { + const product = { amount: 5.479, price: 10, quantity: 2 }; + const result = calculateProductAmount(product); + expect(result).toEqual(548); + }); +}); From 6d9976c640b98d74492fde587058fb1fcbdb8314 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Tue, 8 Oct 2024 19:00:46 +0530 Subject: [PATCH 045/147] chore: adding salesforce oauth sandbox support for closed testing (#3778) * chore: adding salesforce oauth sandbox support for closed testing * chore: adding test log * fix: throw error for empty secret * fix: processor last test-case * chore: add logical changes for passing test-cases * fix: adding dynamic destination name for rETL connection * fix: adding test case * fix: remove log --------- Co-authored-by: Sai Sankeerth --- src/constants/destinationCanonicalNames.js | 1 + src/features.json | 1 + src/v0/destinations/salesforce/config.js | 2 + src/v0/destinations/salesforce/transform.js | 3 +- src/v0/destinations/salesforce/utils.js | 25 ++- .../networkHandler.js | 34 ++++ .../destinations/salesforce/processor/data.ts | 116 +++++++++++- .../dataDelivery/data.ts | 3 + .../dataDelivery/oauth.ts | 174 ++++++++++++++++++ .../salesforce_oauth_sandbox/network.ts | 51 +++++ 10 files changed, 399 insertions(+), 11 deletions(-) create mode 100644 src/v0/destinations/salesforce_oauth_sandbox/networkHandler.js create mode 100644 test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/data.ts create mode 100644 test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/oauth.ts create mode 100644 test/integrations/destinations/salesforce_oauth_sandbox/network.ts diff --git a/src/constants/destinationCanonicalNames.js b/src/constants/destinationCanonicalNames.js index f99c735e452..e9b7dc136b9 100644 --- a/src/constants/destinationCanonicalNames.js +++ b/src/constants/destinationCanonicalNames.js @@ -1,6 +1,7 @@ const DestHandlerMap = { ga360: 'ga', salesforce_oauth: 'salesforce', + salesforce_oauth_sandbox: 'salesforce', }; const DestCanonicalNames = { diff --git a/src/features.json b/src/features.json index 4c7fc7b231d..f95bd09d7e0 100644 --- a/src/features.json +++ b/src/features.json @@ -26,6 +26,7 @@ "PROFITWELL": true, "SALESFORCE": true, "SALESFORCE_OAUTH": true, + "SALESFORCE_OAUTH_SANDBOX": true, "SFMC": true, "SNAPCHAT_CONVERSION": true, "TIKTOK_ADS": true, diff --git a/src/v0/destinations/salesforce/config.js b/src/v0/destinations/salesforce/config.js index 1425bad51b2..f2e8072755e 100644 --- a/src/v0/destinations/salesforce/config.js +++ b/src/v0/destinations/salesforce/config.js @@ -24,6 +24,7 @@ const SF_TOKEN_REQUEST_URL = 'https://login.salesforce.com/services/oauth2/token const SF_TOKEN_REQUEST_URL_SANDBOX = 'https://test.salesforce.com/services/oauth2/token'; const DESTINATION = 'Salesforce'; +const SALESFORCE_OAUTH_SANDBOX = 'salesforce_oauth_sandbox'; const OAUTH = 'oauth'; const LEGACY = 'legacy'; @@ -41,4 +42,5 @@ module.exports = { DESTINATION, OAUTH, LEGACY, + SALESFORCE_OAUTH_SANDBOX, }; diff --git a/src/v0/destinations/salesforce/transform.js b/src/v0/destinations/salesforce/transform.js index 1dde1ec65ac..7e66dd88106 100644 --- a/src/v0/destinations/salesforce/transform.js +++ b/src/v0/destinations/salesforce/transform.js @@ -293,6 +293,7 @@ async function processIdentify( authorizationData, authorizationFlow, ) { + const { Name } = destination.DestinationDefinition; const mapProperty = destination.Config.mapProperty === undefined ? true : destination.Config.mapProperty; // check the traits before hand @@ -304,7 +305,7 @@ async function processIdentify( // Append external ID to traits if event is mapped to destination and only if identifier type is not id // If identifier type is id, then it should not be added to traits, else saleforce will throw an error const mappedToDestination = get(message, MappedToDestinationKey); - const externalId = getDestinationExternalIDObjectForRetl(message, 'SALESFORCE'); + const externalId = getDestinationExternalIDObjectForRetl(message, Name); if (mappedToDestination && externalId?.identifierType?.toLowerCase() !== 'id') { addExternalIdToTraits(message); } diff --git a/src/v0/destinations/salesforce/utils.js b/src/v0/destinations/salesforce/utils.js index 9a4effc502a..a7731f07de4 100644 --- a/src/v0/destinations/salesforce/utils.js +++ b/src/v0/destinations/salesforce/utils.js @@ -1,4 +1,9 @@ -const { RetryableError, ThrottledError, AbortedError } = require('@rudderstack/integrations-lib'); +const { + RetryableError, + ThrottledError, + AbortedError, + OAuthSecretError, +} = require('@rudderstack/integrations-lib'); const { handleHttpRequest } = require('../../../adapters/network'); const { isHttpStatusSuccess, @@ -13,6 +18,7 @@ const { DESTINATION, LEGACY, OAUTH, + SALESFORCE_OAUTH_SANDBOX, } = require('./config'); const ACCESS_TOKEN_CACHE = new Cache(ACCESS_TOKEN_CACHE_TTL); @@ -104,10 +110,15 @@ const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authori * @param {destination: Record, metadata: Record} * @returns */ -const getAccessTokenOauth = (metadata) => ({ - token: metadata.secret?.access_token, - instanceUrl: metadata.secret?.instance_url, -}); +const getAccessTokenOauth = (metadata) => { + if (!isDefinedAndNotNull(metadata?.secret)) { + throw new OAuthSecretError('secret is undefined/null'); + } + return { + token: metadata.secret?.access_token, + instanceUrl: metadata.secret?.instance_url, + }; +}; const getAccessToken = async ({ destination, metadata }) => { const accessTokenKey = destination.ID; @@ -169,7 +180,9 @@ const getAccessToken = async ({ destination, metadata }) => { const collectAuthorizationInfo = async (event) => { let authorizationFlow; let authorizationData; - if (isDefinedAndNotNull(event.metadata?.secret)) { + const { Name } = event.destination.DestinationDefinition; + const lowerCaseName = Name?.toLowerCase?.(); + if (isDefinedAndNotNull(event?.metadata?.secret) || lowerCaseName === SALESFORCE_OAUTH_SANDBOX) { authorizationFlow = OAUTH; authorizationData = getAccessTokenOauth(event.metadata); } else { diff --git a/src/v0/destinations/salesforce_oauth_sandbox/networkHandler.js b/src/v0/destinations/salesforce_oauth_sandbox/networkHandler.js new file mode 100644 index 00000000000..b6cbed77f95 --- /dev/null +++ b/src/v0/destinations/salesforce_oauth_sandbox/networkHandler.js @@ -0,0 +1,34 @@ +const { proxyRequest, prepareProxyRequest } = require('../../../adapters/network'); +const { processAxiosResponse } = require('../../../adapters/utils/networkUtils'); +const { OAUTH } = require('../salesforce/config'); +const { salesforceResponseHandler } = require('../salesforce/utils'); + +const responseHandler = (responseParams) => { + const { destinationResponse, destType, rudderJobMetadata } = responseParams; + const message = `Request for destination: ${destType} Processed Successfully`; + + salesforceResponseHandler( + destinationResponse, + 'during Salesforce Response Handling', + rudderJobMetadata?.destInfo?.authKey, + OAUTH, + ); + + // else successfully return status as 200, message and original destination response + return { + status: 200, + message, + destinationResponse, + }; +}; + +function networkHandler() { + this.responseHandler = responseHandler; + this.proxy = proxyRequest; + this.prepareProxy = prepareProxyRequest; + this.processAxiosResponse = processAxiosResponse; +} + +module.exports = { + networkHandler, +}; diff --git a/test/integrations/destinations/salesforce/processor/data.ts b/test/integrations/destinations/salesforce/processor/data.ts index 7a44b6b8edd..b33b75b55bd 100644 --- a/test/integrations/destinations/salesforce/processor/data.ts +++ b/test/integrations/destinations/salesforce/processor/data.ts @@ -1373,7 +1373,7 @@ export const data = [ }, { name: 'salesforce', - description: 'Test 10', + description: 'Test 11', feature: 'processor', module: 'destination', version: 'v0', @@ -1389,9 +1389,9 @@ export const data = [ sandbox: true, }, DestinationDefinition: { - DisplayName: 'Salesforce', + DisplayName: 'Salesforce Sandbox', ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', - Name: 'SALESFORCE', + Name: 'SALESFORCE_OAUTH_SANDBOX', }, Enabled: true, ID: '1ut7LcVW1QC56y2EoTNo7ZwBWSY', @@ -1412,7 +1412,7 @@ export const data = [ externalId: [ { id: 'a005g0000383kmUAAQ', - type: 'SALESFORCE-custom_object__c', + type: 'SALESFORCE_OAUTH_SANDBOX-custom_object__c', identifierType: 'Id', }, ], @@ -1499,4 +1499,112 @@ export const data = [ }, }, }, + { + name: 'salesforce', + description: 'Test 12 : Retry happens when no secret information is found', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + initialAccessToken: '7fiy1FKcO9sohsxq1v6J88sg', + password: 'dummyPassword2', + userName: 'test.c97-qvpd@force.com.test', + sandbox: true, + }, + DestinationDefinition: { + DisplayName: 'Salesforce Sandbox', + ID: '1T96GHZ0YZ1qQSLULHCoJkow9KC', + Name: 'SALESFORCE_OAUTH_SANDBOX', + }, + Enabled: true, + ID: '1ut7LcVW1QC56y2EoTNo7ZwBWSY', + Name: 'Test SF', + Transformations: [], + }, + metadata: { + jobId: 1, + }, + message: { + anonymousId: '1e7673da-9473-49c6-97f7-da848ecafa76', + channel: 'web', + context: { + mappedToDestination: true, + externalId: [ + { + id: 'a005g0000383kmUAAQ', + type: 'SALESFORCE_OAUTH_SANDBOX-custom_object__c', + identifierType: 'Id', + }, + ], + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + locale: 'en-US', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + traits: { + email: 'john@rs.com', + firstname: 'john doe', + Id: 'some-id', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', + }, + integrations: { + All: true, + }, + messageId: 'f19c35da-e9de-4c6e-b6e5-9e60cccc12c8', + originalTimestamp: '2020-01-27T12:20:55.301Z', + receivedAt: '2020-01-27T17:50:58.657+05:30', + request_ip: '14.98.244.60', + sentAt: '2020-01-27T12:20:56.849Z', + timestamp: '2020-01-27T17:50:57.109+05:30', + type: 'identify', + userId: '1e7673da-9473-49c6-97f7-da848ecafa76', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + statusCode: 500, + error: 'secret is undefined/null', + metadata: { + jobId: 1, + }, + statTags: { + errorCategory: 'platform', + errorType: 'oAuthSecret', + destType: 'SALESFORCE', + module: 'destination', + implementation: 'native', + feature: 'processor', + }, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/data.ts b/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/data.ts new file mode 100644 index 00000000000..bed8eec8db9 --- /dev/null +++ b/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/data.ts @@ -0,0 +1,3 @@ +import { testScenariosForV1API } from './oauth'; + +export const data = [...testScenariosForV1API]; diff --git a/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/oauth.ts b/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/oauth.ts new file mode 100644 index 00000000000..30ee516e724 --- /dev/null +++ b/test/integrations/destinations/salesforce_oauth_sandbox/dataDelivery/oauth.ts @@ -0,0 +1,174 @@ +import { ProxyMetdata } from '../../../../../src/types'; +import { ProxyV1TestData } from '../../../testTypes'; +import { generateProxyV1Payload } from '../../../testUtils'; + +const commonHeadersForWrongToken = { + Authorization: 'Bearer expiredAccessToken', + 'Content-Type': 'application/json', +}; + +const commonHeadersForRightToken = { + Authorization: 'Bearer correctAccessToken', + 'Content-Type': 'application/json', +}; +const params = { destination: 'salesforce_oauth_sandbox' }; + +const users = [ + { + Email: 'danis.archurav@sbermarket.ru', + Company: 'itus.ru', + LastName: 'Danis', + FirstName: 'Archurav', + LeadSource: 'App Signup', + account_type__c: 'free_trial', + }, +]; + +const statTags = { + retryable: { + destType: 'SALESFORCE_OAUTH_SANDBOX', + destinationId: 'dummyDestinationId', + errorCategory: 'network', + errorType: 'retryable', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', + workspaceId: 'dummyWorkspaceId', + }, +}; + +const commonRequestParametersWithWrongToken = { + headers: commonHeadersForWrongToken, + JSON: users[0], + params, +}; + +const commonRequestParametersWithRightToken = { + headers: commonHeadersForRightToken, + JSON: users[0], + params, +}; + +export const proxyMetdataWithSecretWithWrongAccessToken: ProxyMetdata = { + jobId: 1, + attemptNum: 1, + userId: 'dummyUserId', + sourceId: 'dummySourceId', + destinationId: 'dummyDestinationId', + workspaceId: 'dummyWorkspaceId', + secret: { + access_token: 'expiredAccessToken', + instanceUrl: 'https://rudderstack.my.salesforce_oauth_sandbox.com', + }, + destInfo: { authKey: 'dummyDestinationId' }, + dontBatch: false, +}; + +export const proxyMetdataWithSecretWithRightAccessToken: ProxyMetdata = { + jobId: 1, + attemptNum: 1, + userId: 'dummyUserId', + sourceId: 'dummySourceId', + destinationId: 'dummyDestinationId', + workspaceId: 'dummyWorkspaceId', + secret: { + access_token: 'expiredRightToken', + instanceUrl: 'https://rudderstack.my.salesforce_oauth_sandbox.com', + }, + destInfo: { authKey: 'dummyDestinationId' }, + dontBatch: false, +}; + +export const reqMetadataArrayWithWrongSecret = [proxyMetdataWithSecretWithWrongAccessToken]; +export const reqMetadataArray = [proxyMetdataWithSecretWithRightAccessToken]; + +export const testScenariosForV1API: ProxyV1TestData[] = [ + { + id: 'salesforce_v1_scenario_1', + name: 'salesforce_oauth_sandbox', + description: '[Proxy v1 API] :: Test with expired access token scenario', + successCriteria: + 'Should return 5XX with error category REFRESH_TOKEN and Session expired or invalid, INVALID_SESSION_ID', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + ...commonRequestParametersWithWrongToken, + endpoint: + 'https://rudderstack.my.salesforce_oauth_sandbox.com/services/data/v50.0/sobjects/Lead/20', + }, + reqMetadataArrayWithWrongSecret, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 500, + body: { + output: { + status: 500, + authErrorCategory: 'REFRESH_TOKEN', + message: + 'Salesforce Request Failed - due to "INVALID_SESSION_ID", (Retryable) during Salesforce Response Handling', + response: [ + { + error: + '[{"message":"Session expired or invalid","errorCode":"INVALID_SESSION_ID"}]', + metadata: proxyMetdataWithSecretWithWrongAccessToken, + statusCode: 500, + }, + ], + statTags: statTags.retryable, + }, + }, + }, + }, + }, + { + id: 'salesforce_v1_scenario_2', + name: 'salesforce', + description: + '[Proxy v1 API] :: Test for a valid request - Lead creation with existing unchanged leadId and unchanged data', + successCriteria: 'Should return 200 with no error with destination response', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + ...commonRequestParametersWithRightToken, + endpoint: + 'https://rudderstack.my.salesforce.com/services/data/v50.0/sobjects/Lead/existing_unchanged_leadId', + }, + reqMetadataArray, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: 'Request for destination: salesforce Processed Successfully', + response: [ + { + error: '{"statusText":"No Content"}', + metadata: proxyMetdataWithSecretWithRightAccessToken, + statusCode: 200, + }, + ], + }, + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/salesforce_oauth_sandbox/network.ts b/test/integrations/destinations/salesforce_oauth_sandbox/network.ts new file mode 100644 index 00000000000..09d2c759d2e --- /dev/null +++ b/test/integrations/destinations/salesforce_oauth_sandbox/network.ts @@ -0,0 +1,51 @@ +const headerWithWrongAccessToken = { + Authorization: 'Bearer expiredAccessToken', + 'Content-Type': 'application/json', +}; + +const headerWithRightAccessToken = { + Authorization: 'Bearer correctAccessToken', + 'Content-Type': 'application/json', +}; + +const dataValue = { + Email: 'danis.archurav@sbermarket.ru', + Company: 'itus.ru', + LastName: 'Danis', + FirstName: 'Archurav', + LeadSource: 'App Signup', + account_type__c: 'free_trial', +}; + +const businessMockData = [ + { + description: 'Mock response from destination depicting an expired access token', + httpReq: { + method: 'post', + url: 'https://rudderstack.my.salesforce_oauth_sandbox.com/services/data/v50.0/sobjects/Lead/20', + headers: headerWithWrongAccessToken, + data: dataValue, + params: { destination: 'salesforce_oauth_sandbox' }, + }, + httpRes: { + data: [{ message: 'Session expired or invalid', errorCode: 'INVALID_SESSION_ID' }], + status: 401, + }, + }, + { + description: + 'Mock response from destination depicting a valid lead request, with no changed data', + httpReq: { + method: 'post', + url: 'https://rudderstack.my.salesforce.com/services/data/v50.0/sobjects/Lead/existing_unchanged_leadId', + data: dataValue, + headers: headerWithRightAccessToken, + }, + httpRes: { + data: { statusText: 'No Content' }, + status: 204, + }, + }, +]; + +export const networkCallsData = [...businessMockData]; From 5ac81860c51f9971343df8c61bfd0b2de8161735 Mon Sep 17 00:00:00 2001 From: Anant Jain <62471433+anantjain45823@users.noreply.github.com> Date: Tue, 8 Oct 2024 20:20:06 +0530 Subject: [PATCH 046/147] feat: onboard Amazon Audience (#3727) --- package-lock.json | 6 + package.json | 1 + src/features.json | 1 + src/v0/destinations/amazon_audience/config.js | 5 + .../amazon_audience/networkHandler.js | 139 ++++++++++ .../destinations/amazon_audience/transform.js | 58 +++++ src/v0/destinations/amazon_audience/utils.js | 175 +++++++++++++ .../destinations/amazon_audience/common.ts | 30 +++ .../amazon_audience/dataDelivery/data.ts | 197 ++++++++++++++ .../destinations/amazon_audience/network.ts | 123 +++++++++ .../amazon_audience/processor/data.ts | 246 ++++++++++++++++++ .../amazon_audience/router/data.ts | 226 ++++++++++++++++ 12 files changed, 1207 insertions(+) create mode 100644 src/v0/destinations/amazon_audience/config.js create mode 100644 src/v0/destinations/amazon_audience/networkHandler.js create mode 100644 src/v0/destinations/amazon_audience/transform.js create mode 100644 src/v0/destinations/amazon_audience/utils.js create mode 100644 test/integrations/destinations/amazon_audience/common.ts create mode 100644 test/integrations/destinations/amazon_audience/dataDelivery/data.ts create mode 100644 test/integrations/destinations/amazon_audience/network.ts create mode 100644 test/integrations/destinations/amazon_audience/processor/data.ts create mode 100644 test/integrations/destinations/amazon_audience/router/data.ts diff --git a/package-lock.json b/package-lock.json index 243b989a6d7..b8f677520fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "ajv": "^8.12.0", "ajv-draft-04": "^1.0.0", "ajv-formats": "^2.1.1", + "amazon-dsp-formatter": "^1.0.2", "axios": "^1.7.3", "btoa": "^1.2.1", "component-each": "^0.2.6", @@ -8197,6 +8198,11 @@ } } }, + "node_modules/amazon-dsp-formatter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/amazon-dsp-formatter/-/amazon-dsp-formatter-1.0.2.tgz", + "integrity": "sha512-CfsssMzLFh0IK6oz3j38ENGgp5LZ/q21YX4yXSavfI50CU2cJbupKOk+Bgg0sY67V0lWsYsmYrpkEI2aFG/duA==" + }, "node_modules/ansi-align": { "version": "3.0.1", "dev": true, diff --git a/package.json b/package.json index 8a104f3081f..7aedc782bac 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "ajv": "^8.12.0", "ajv-draft-04": "^1.0.0", "ajv-formats": "^2.1.1", + "amazon-dsp-formatter": "^1.0.2", "axios": "^1.7.3", "btoa": "^1.2.1", "component-each": "^0.2.6", diff --git a/src/features.json b/src/features.json index f95bd09d7e0..63862eefed4 100644 --- a/src/features.json +++ b/src/features.json @@ -82,6 +82,7 @@ "BLOOMREACH_CATALOG": true, "SMARTLY": true, "HTTP": true, + "AMAZON_AUDIENCE": true, "INTERCOM_V2": true }, "regulations": [ diff --git a/src/v0/destinations/amazon_audience/config.js b/src/v0/destinations/amazon_audience/config.js new file mode 100644 index 00000000000..f377bceaaef --- /dev/null +++ b/src/v0/destinations/amazon_audience/config.js @@ -0,0 +1,5 @@ +const CREATE_USERS_URL = 'https://advertising-api.amazon.com/dp/records/hashed/'; +const ASSOCIATE_USERS_URL = 'https://advertising-api.amazon.com/v2/dp/audience'; +const MAX_PAYLOAD_SIZE_IN_BYTES = 4000000; +const DESTINATION = 'amazon_audience'; +module.exports = { CREATE_USERS_URL, MAX_PAYLOAD_SIZE_IN_BYTES, ASSOCIATE_USERS_URL, DESTINATION }; diff --git a/src/v0/destinations/amazon_audience/networkHandler.js b/src/v0/destinations/amazon_audience/networkHandler.js new file mode 100644 index 00000000000..c1fbeeccead --- /dev/null +++ b/src/v0/destinations/amazon_audience/networkHandler.js @@ -0,0 +1,139 @@ +const { + NetworkError, + ThrottledError, + AbortedError, + RetryableError, +} = require('@rudderstack/integrations-lib'); +const { prepareProxyRequest, handleHttpRequest } = require('../../../adapters/network'); +const { isHttpStatusSuccess } = require('../../util/index'); +const { + processAxiosResponse, + getDynamicErrorType, +} = require('../../../adapters/utils/networkUtils'); +const { REFRESH_TOKEN } = require('../../../adapters/networkhandler/authConstants'); +const { DESTINATION, CREATE_USERS_URL, ASSOCIATE_USERS_URL } = require('./config'); +const { TAG_NAMES } = require('../../util/tags'); + +const amazonAudienceRespHandler = (destResponse, stageMsg) => { + const { status, response } = destResponse; + + // to handle the case when authorization-token is invalid + // docs for error codes: https://advertising.amazon.com/API/docs/en-us/reference/concepts/errors#tag/Audiences/operation/dspCreateAudiencesPost + if (status === 401 && response.message === 'Unauthorized') { + // 401 takes place in case of authorization isue meaning token is epxired or access is not enough. + // Since acces is configured from dashboard only refresh token makes sense + throw new NetworkError( + `${response?.message} ${stageMsg}`, + status, + { + [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), + }, + response, + REFRESH_TOKEN, + ); + } else if (status === 429) { + throw new ThrottledError( + `Request Failed: ${stageMsg} - due to Request Limit exceeded, (Throttled)`, + destResponse, + ); + } else if (status === 504 || status === 502 || status === 500) { + // see if its 5xx internal error + throw new RetryableError(`Request Failed: ${stageMsg} (Retryable)`, 500, destResponse); + } + // else throw the error + throw new AbortedError( + `Request Failed: ${stageMsg} with status "${status}" due to "${JSON.stringify( + response, + )}", (Aborted) `, + 400, + destResponse, + ); +}; + +const responseHandler = (responseParams) => { + const { destinationResponse } = responseParams; + const message = `[${DESTINATION} Response Handler] - Request Processed Successfully`; + const { status } = destinationResponse; + + if (!isHttpStatusSuccess(status)) { + // if error, successfully return status, message and original destination response + amazonAudienceRespHandler( + destinationResponse, + 'during amazon_audience response transformation', + ); + } + return { + status, + message, + destinationResponse, + }; +}; + +const makeRequest = async (url, data, headers, metadata, method, args) => { + const { httpResponse } = await handleHttpRequest(method, url, data, { headers }, args); + return httpResponse; +}; + +const amazonAudienceProxyRequest = async (request) => { + const { body, metadata } = request; + const { headers } = request; + const { createUsers, associateUsers } = body.JSON; + + // step 1: Create users + const firstResponse = await makeRequest( + CREATE_USERS_URL, + createUsers, + headers, + metadata, + 'post', + { + destType: 'amazon_audience', + feature: 'proxy', + requestMethod: 'POST', + module: 'dataDelivery', + endpointPath: '/records/hashed', + metadata, + }, + ); + // validate response success + if (!firstResponse.success && !isHttpStatusSuccess(firstResponse?.response?.status)) { + amazonAudienceRespHandler( + { + response: firstResponse.response?.response?.data || firstResponse, + status: firstResponse.response?.response?.status || firstResponse, + }, + 'during creating users', + ); + } + // we are returning above in case of failure because if first step is not executed then there is no sense of executing second step + // step2: Associate Users to Audience Id + const secondResponse = await makeRequest( + ASSOCIATE_USERS_URL, + associateUsers, + headers, + metadata, + 'patch', + { + destType: 'amazon_audience', + feature: 'proxy', + requestMethod: 'PATCH', + module: 'dataDelivery', + endpointPath: '/v2/dp/audience', + metadata, + }, + ); + return secondResponse; +}; +// eslint-disable-next-line @typescript-eslint/naming-convention +class networkHandler { + constructor() { + this.responseHandler = responseHandler; + this.proxy = amazonAudienceProxyRequest; + this.prepareProxy = prepareProxyRequest; + this.processAxiosResponse = processAxiosResponse; + } +} + +module.exports = { + networkHandler, +}; diff --git a/src/v0/destinations/amazon_audience/transform.js b/src/v0/destinations/amazon_audience/transform.js new file mode 100644 index 00000000000..834810de547 --- /dev/null +++ b/src/v0/destinations/amazon_audience/transform.js @@ -0,0 +1,58 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const { handleRtTfSingleEventError } = require('../../util'); +const { batchEvents, buildResponseWithUsers, getUserDetails } = require('./utils'); +/** + * This function returns the user traits list required in request for + * making a call to create a group of users in amazon_audience + * @param {*} record + * @param {*} destination + * @param {*} metadata + */ +const processRecord = (record, config) => { + const { fields, action, type } = record; + if (type !== 'record') { + throw new InstrumentationError(`[AMAZON AUDIENCE]: ${type} is not supported`); + } + return { user: getUserDetails(fields, config), action: action !== 'delete' ? 'add' : 'remove' }; +}; + +// This function is used to process a single record +const process = (event) => { + const { message, destination, metadata } = event; + const { Config } = destination; + const { user, action } = processRecord(message, Config); + return buildResponseWithUsers([user], action, Config, [metadata.jobId], metadata.secret); +}; +// This function is used to process multiple records +const processRouterDest = async (inputs, reqMetadata) => { + const responseList = []; // list containing all successful responses + const errorRespList = []; // list of error + const { destination } = inputs[0]; + const { Config } = destination; + inputs.map(async (event) => { + try { + if (event.message.statusCode) { + // already transformed event + responseList.push(event); + } else { + // if not transformed + responseList.push({ + message: processRecord(event.message, Config), + metadata: event.metadata, + destination, + }); + } + } catch (error) { + const errRespEvent = handleRtTfSingleEventError(event, error, reqMetadata); + errorRespList.push(errRespEvent); + } + }); + let batchedResponseList = []; + if (responseList.length > 0) { + batchedResponseList = batchEvents(responseList, destination); + } + return [...batchedResponseList, ...errorRespList]; +}; + +module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/amazon_audience/utils.js b/src/v0/destinations/amazon_audience/utils.js new file mode 100644 index 00000000000..c25f3013782 --- /dev/null +++ b/src/v0/destinations/amazon_audience/utils.js @@ -0,0 +1,175 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const sha256 = require('sha256'); +const AmazonAdsFormatter = require('amazon-dsp-formatter'); +const lodash = require('lodash'); +const { ConfigurationError, OAuthSecretError } = require('@rudderstack/integrations-lib'); +const { + defaultRequestConfig, + defaultPostRequestConfig, + getSuccessRespEvents, + removeUndefinedAndNullAndEmptyValues, +} = require('../../util'); + +const buildResponseWithUsers = (users, action, config, jobIdList, secret) => { + const { audienceId } = config; + if (!audienceId) { + throw new ConfigurationError('[AMAZON AUDIENCE]: Audience Id not found'); + } + if (!secret?.accessToken) { + throw new OAuthSecretError('OAuth - access token not found'); + } + if (!secret?.clientId) { + throw new OAuthSecretError('OAuth - Client Id not found'); + } + const externalId = `Rudderstack_${sha256(`${jobIdList}`)}`; + const response = defaultRequestConfig(); + response.endpoint = ''; + response.method = defaultPostRequestConfig.requestMethod; + response.headers = { + 'Amazon-Advertising-API-ClientId': `${secret.clientId}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${secret.accessToken}`, + }; + response.body.JSON = { + createUsers: { + records: [ + { + hashedRecords: users, + externalId, + }, + ], + }, + associateUsers: { + patches: [ + { + op: action, + path: `/EXTERNAL_USER_ID-${externalId}/audiences`, + value: [audienceId], + }, + ], + }, + }; + return response; +}; + +/** + * This function groups the response list based upon `operation` + * @param {*} respList + * @returns object + */ +const groupResponsesUsingOperation = (respList) => { + const eventGroups = lodash.groupBy(respList, (item) => item.message.action); + return eventGroups; +}; + +/** + * Input: [{ + message: { + users: {} + action + }, + }, + metadata, + destination, +}] + * @param {*} responseList + */ +const batchEvents = (responseList, destination) => { + const { secret } = responseList[0].metadata; + const eventGroups = groupResponsesUsingOperation(responseList); + const respList = []; + const opList = ['remove', 'add']; + opList.forEach((op) => { + if (eventGroups?.[op]) { + const { userList, jobIdList, metadataList } = eventGroups[op].reduce( + (acc, event) => ({ + userList: acc.userList.concat(event.message.user), + jobIdList: acc.jobIdList.concat(event.metadata.jobId), + metadataList: acc.metadataList.concat(event.metadata), + }), + { userList: [], metadataList: [], jobIdList: [] }, + ); + respList.push( + getSuccessRespEvents( + buildResponseWithUsers( + userList, + op, + destination.config || destination.Config, + jobIdList, + secret, + ), + metadataList, + destination, + true, + ), + ); + } + }); + return respList; +}; + +/** + * This function fetches the user details and + * hash them after normalizing if enable hash is turned on in config + * @param {*} fields + * @param {*} config + * @returns + */ +const getUserDetails = (fields, config) => { + const { enableHash } = config; + const { + email, + phone: phone_number, + firstName, + lastName, + address, + country, + city, + state, + postalCode, + } = fields; + if (!enableHash) { + return removeUndefinedAndNullAndEmptyValues({ + email, + phone: phone_number, + firstName, + lastName, + address, + country, + city, + state, + postalCode, + }); + } + // Since all fields are optional hence notusing formatRecord function from formatter but doing it for every parameter + const formatter = new AmazonAdsFormatter(); + const user = { + email: sha256(formatter.formatEmail(email)), + firstName: sha256(formatter.formatName(firstName)), + lastName: sha256(formatter.formatName(lastName)), + city: sha256(formatter.formatCity(city)), + state: sha256(formatter.formatState(state, country)), + postalCode: sha256(formatter.formatPostal(postalCode)), + }; + // formating guidelines https://advertising.amazon.com/help/GCCXMZYCK4RXWS6C + if (country) { + const country_code = formatter.formatCountry(country); + user.country = sha256(country_code); + if (phone_number) { + user.phone = sha256(formatter.formatPhone(phone_number, country_code)); + } + } + if (address) { + const formatted_address = + address + ?.normalize('NFD') + ?.replace(/[\u0300-\u036f]/g, '') + ?.trim() + ?.toLowerCase() + .replace(/[^\dA-Za-z]/g, '') || undefined; + user.address = sha256(formatter.formatAddress(formatted_address, country)); + } + return removeUndefinedAndNullAndEmptyValues(user); +}; + +module.exports = { batchEvents, getUserDetails, buildResponseWithUsers }; diff --git a/test/integrations/destinations/amazon_audience/common.ts b/test/integrations/destinations/amazon_audience/common.ts new file mode 100644 index 00000000000..728bdf1d257 --- /dev/null +++ b/test/integrations/destinations/amazon_audience/common.ts @@ -0,0 +1,30 @@ +export const destination = { + DestinationDefinition: { + Config: { + excludeKeys: [], + includeKeys: [], + }, + }, + Config: { + advertiserId: '{"Dummy Name":"1234"}', + audienceId: 'dummyId', + }, + ID: 'amazonAud-1234', +}; + +export const generateMetadata = (jobId: number, userId?: string): any => { + return { + jobId, + attemptNum: 1, + userId: userId || 'default-userId', + sourceId: 'default-sourceId', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + dontBatch: false, + secret: { + accessToken: 'dummyAccessToken', + refreshToken: 'dummyRefreshToken', + clientId: 'dummyClientId', + }, + }; +}; diff --git a/test/integrations/destinations/amazon_audience/dataDelivery/data.ts b/test/integrations/destinations/amazon_audience/dataDelivery/data.ts new file mode 100644 index 00000000000..c78a53c8994 --- /dev/null +++ b/test/integrations/destinations/amazon_audience/dataDelivery/data.ts @@ -0,0 +1,197 @@ +import { generateMetadata, generateProxyV0Payload } from '../../../testUtils'; + +const commonStatTags = { + destType: 'AMAZON_AUDIENCE', + errorCategory: 'network', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + errorType: 'aborted', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', +}; +export const data = [ + { + name: 'amazon_audience', + id: 'Test 0', + description: 'Successfull Delivery case', + successCriteria: 'It should be passed with 200 Ok with no errors', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + headers: { + Authorization: 'Bearer success_access_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + endpoint: '', + JSON: { + associateUsers: { + patches: [ + { + op: 'remove', + path: '/EXTERNAL_USER_ID-Rudderstack_c73bcaadd94985269eeafd457c9f395135874dad5536cf1f6d75c132f602a14c/audiences', + value: ['dummyId'], + }, + ], + }, + createUsers: { + records: [ + { + externalId: + 'Rudderstack_c73bcaadd94985269eeafd457c9f395135874dad5536cf1f6d75c132f602a14c', + hashedRecords: [ + { + email: 'email4@abc.com', + }, + ], + }, + ], + }, + }, + }), + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[amazon_audience Response Handler] - Request Processed Successfully', + destinationResponse: { + response: { + requestId: 'dummy request id', + jobId: 'dummy job id', + }, + status: 200, + }, + }, + }, + }, + }, + }, + { + name: 'amazon_audience', + id: 'Test 1', + description: 'Unsuccessfull Delivery case for step 2', + successCriteria: 'It should be passed with 500 Internal with error with invalid payload', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + headers: { + Authorization: 'Bearer success_access_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + endpoint: '', + JSON: { + associateUsers: { + patches: [ + { + op: 'add', + path: '/EXTERNAL_USER_ID-Fail_Case/audiences', + value: ['dummyId'], + }, + ], + }, + createUsers: { + records: [ + { + externalId: + 'Rudderstack_c73bcaadd94985269eeafd457c9f395135874dad5536cf1f6d75c132f602a14c', + hashedRecords: [ + { + email: 'email4@abc.com', + }, + ], + }, + ], + }, + }, + }), + }, + }, + output: { + response: { + status: 500, + body: { + output: { + status: 500, + destinationResponse: { + response: { + code: 'Internal Error', + }, + status: 500, + }, + message: 'Request Failed: during amazon_audience response transformation (Retryable)', + statTags: { + destType: 'AMAZON_AUDIENCE', + errorCategory: 'network', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + errorType: 'retryable', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', + }, + }, + }, + }, + }, + }, + { + name: 'amazon_audience', + id: 'Test 2 - Oauth Refresh Token', + description: 'Unsuccessfull Access Error for step 1', + successCriteria: 'It should be passed with 401 Unauthorized error', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: generateProxyV0Payload({ + headers: { + Authorization: 'Bearer fail_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + endpoint: '', + JSON: { + associateUsers: [], + createUsers: { + records: [ + { + externalId: 'access token expired fail case', + hashedRecords: [], + }, + ], + }, + }, + }), + }, + }, + output: { + response: { + status: 401, + body: { + output: { + status: 401, + destinationResponse: { + message: 'Unauthorized', + }, + authErrorCategory: 'REFRESH_TOKEN', + message: 'Unauthorized during creating users', + statTags: commonStatTags, + }, + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/amazon_audience/network.ts b/test/integrations/destinations/amazon_audience/network.ts new file mode 100644 index 00000000000..b0941712c6a --- /dev/null +++ b/test/integrations/destinations/amazon_audience/network.ts @@ -0,0 +1,123 @@ +const headers = { + 'Amazon-Advertising-API-ClientId': 'dummyClientId', + 'Content-Type': 'application/json', + Authorization: 'Bearer success_access_token', +}; +export const networkCallsData = [ + { + description: 'successful step 1', + httpReq: { + url: 'https://advertising-api.amazon.com/dp/records/hashed/', + data: { + records: [ + { + externalId: + 'Rudderstack_c73bcaadd94985269eeafd457c9f395135874dad5536cf1f6d75c132f602a14c', + hashedRecords: [ + { + email: 'email4@abc.com', + }, + ], + }, + ], + }, + params: {}, + headers: { + Authorization: 'Bearer success_access_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + method: 'post', + }, + httpRes: { + data: { + requestId: 'dummy request id', + }, + status: 200, + }, + }, + { + description: 'successful step 2', + httpReq: { + url: 'https://advertising-api.amazon.com/v2/dp/audience', + data: { + patches: [ + { + op: 'remove', + path: '/EXTERNAL_USER_ID-Rudderstack_c73bcaadd94985269eeafd457c9f395135874dad5536cf1f6d75c132f602a14c/audiences', + value: ['dummyId'], + }, + ], + }, + params: {}, + headers: { + Authorization: 'Bearer success_access_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + method: 'patch', + }, + httpRes: { + data: { + requestId: 'dummy request id', + jobId: 'dummy job id', + }, + status: 200, + }, + }, + { + description: 'unsuccessful step 2', + httpReq: { + url: 'https://advertising-api.amazon.com/v2/dp/audience', + data: { + patches: [ + { + op: 'add', + path: '/EXTERNAL_USER_ID-Fail_Case/audiences', + value: ['dummyId'], + }, + ], + }, + params: {}, + headers: { + Authorization: 'Bearer success_access_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + method: 'patch', + }, + httpRes: { + data: { + code: 'Internal Error', + }, + status: 500, + }, + }, + { + description: 'unsuccessful step 1', + httpReq: { + url: 'https://advertising-api.amazon.com/dp/records/hashed/', + data: { + records: [ + { + externalId: 'access token expired fail case', + hashedRecords: [], + }, + ], + }, + params: {}, + headers: { + Authorization: 'Bearer fail_token', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + method: 'post', + }, + httpRes: { + data: { + message: 'Unauthorized', + }, + status: 401, + }, + }, +]; diff --git a/test/integrations/destinations/amazon_audience/processor/data.ts b/test/integrations/destinations/amazon_audience/processor/data.ts new file mode 100644 index 00000000000..49931ed92bc --- /dev/null +++ b/test/integrations/destinations/amazon_audience/processor/data.ts @@ -0,0 +1,246 @@ +import { destination, generateMetadata } from '../common'; +const sha256 = require('sha256'); + +const fields = { + email: 'abc@xyz.com', + phone: '9876543323', + firstName: 'test', + lastName: 'user', + address: ' Été très chaud! ', +}; + +export const data = [ + { + name: 'amazon_audience', + id: 'Test 1', + description: 'All traits are present with hash enbaled for the audience with insert operation', + successCriteria: 'It should be passed with 200 Ok with all traits mapped after hashing', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'record', + action: 'insert', + fields: { + ...fields, + city: 'Edmonton', + state: 'alberta', + country: 'Canada', + postalCode: '12345', + }, + context: {}, + recordId: '1', + }, + destination: { ...destination, Config: { ...destination.Config, enableHash: true } }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + FORM: {}, + JSON_ARRAY: {}, + JSON: { + createUsers: { + records: [ + { + hashedRecords: [ + { + country: + '6959097001d10501ac7d54c0bdb8db61420f658f2922cc26e46d536119a31126', + address: + '7e68f87b9675dca9a6cbd0b3b715af6cd9e0b75b72b96feec98dd334d665a76c', + city: '5ae1b46bce91b626720727f9d8d1eb8998e5b6586b339b97c2288595fe25116a', + firstName: + '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + email: + 'ee278943de84e5d6243578ee1a1057bcce0e50daad9755f45dfa64b60b13bc5d', + lastName: + '04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb', + phone: + '3daf505bba309a952bb4bbd010d1d39e413e40c679ac3bbcee1ea9b009023ffa', + postalCode: + '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', + state: + 'fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603', + }, + ], + externalId: + 'Rudderstack_6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', + }, + ], + }, + associateUsers: { + patches: [ + { + op: 'add', + path: `/EXTERNAL_USER_ID-Rudderstack_6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b/audiences`, + value: ['dummyId'], + }, + ], + }, + }, + XML: {}, + }, + endpoint: '', + files: {}, + headers: { + 'Amazon-Advertising-API-ClientId': 'dummyClientId', + 'Content-Type': 'application/json', + Authorization: 'Bearer dummyAccessToken', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, + { + name: 'amazon_audience', + id: 'Test 2', + description: 'All traits are present with hash disabled for the audience with delete operation', + successCriteria: 'It should be passed with 200 Ok with all traits mapped without hashing', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'record', + action: 'delete', + fields, + channel: 'sources', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: '', + headers: { + 'Amazon-Advertising-API-ClientId': 'dummyClientId', + 'Content-Type': 'application/json', + Authorization: 'Bearer dummyAccessToken', + }, + params: {}, + body: { + JSON: { + createUsers: { + records: [ + { + hashedRecords: [ + { + email: 'abc@xyz.com', + phone: '9876543323', + firstName: 'test', + lastName: 'user', + address: ' Été très chaud! ', + }, + ], + externalId: + 'Rudderstack_6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', + }, + ], + }, + associateUsers: { + patches: [ + { + op: 'remove', + path: `/EXTERNAL_USER_ID-Rudderstack_6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b/audiences`, + value: ['dummyId'], + }, + ], + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'amazon_audience', + id: 'Test 3', + description: 'Type Validation case', + successCriteria: 'It should be passed with 200 Ok giving validation error', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'identify', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + statusCode: 400, + error: '[AMAZON AUDIENCE]: identify is not supported', + statTags: { + errorCategory: 'dataValidation', + destinationId: 'default-destinationId', + errorType: 'instrumentation', + destType: 'AMAZON_AUDIENCE', + module: 'destination', + implementation: 'native', + workspaceId: 'default-workspaceId', + feature: 'processor', + }, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/amazon_audience/router/data.ts b/test/integrations/destinations/amazon_audience/router/data.ts new file mode 100644 index 00000000000..6787e03160e --- /dev/null +++ b/test/integrations/destinations/amazon_audience/router/data.ts @@ -0,0 +1,226 @@ +import { destination, generateMetadata } from '../common'; + +export const data = [ + { + name: 'amazon_audience', + id: 'router-test-1', + description: 'batching based upon action', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + message: { + type: 'record', + action: 'delete', + fields: { email: 'email4@abc.com' }, + channel: 'sources', + context: {}, + recordId: '4', + }, + metadata: generateMetadata(1), + }, + { + destination, + message: { + type: 'record', + action: 'delete', + fields: { + email: 'email5@abc.com', + }, + channel: 'sources', + context: {}, + recordId: '5', + }, + metadata: generateMetadata(2), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { email: 'email3@abc.com' }, + channel: 'sources', + context: {}, + recordId: '3', + }, + metadata: generateMetadata(3), + }, + { + destination, + message: { + type: 'record', + action: 'update', + fields: { + email: 'email1@abc.com', + }, + channel: 'sources', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(4), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { email: 'email2@abc.com' }, + channel: 'sources', + context: {}, + recordId: '2', + }, + metadata: generateMetadata(5), + }, + { + destination, + message: { + type: 'identify', + context: {}, + recordId: '1', + }, + metadata: generateMetadata(6), + }, + ], + destType: 'amazon_audience', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: true, + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: '', + headers: { + 'Amazon-Advertising-API-ClientId': 'dummyClientId', + 'Content-Type': 'application/json', + Authorization: 'Bearer dummyAccessToken', + }, + params: {}, + body: { + JSON: { + associateUsers: { + patches: [ + { + op: 'remove', + path: '/EXTERNAL_USER_ID-Rudderstack_17f8af97ad4a7f7639a4c9171d5185cbafb85462877a4746c21bdb0a4f940ca0/audiences', + value: ['dummyId'], + }, + ], + }, + createUsers: { + records: [ + { + externalId: + 'Rudderstack_17f8af97ad4a7f7639a4c9171d5185cbafb85462877a4746c21bdb0a4f940ca0', + hashedRecords: [ + { + email: 'email4@abc.com', + }, + { + email: 'email5@abc.com', + }, + ], + }, + ], + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + destination, + metadata: [generateMetadata(1), generateMetadata(2)], + statusCode: 200, + }, + { + batched: true, + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: '', + headers: { + 'Amazon-Advertising-API-ClientId': 'dummyClientId', + 'Content-Type': 'application/json', + Authorization: 'Bearer dummyAccessToken', + }, + params: {}, + body: { + JSON: { + associateUsers: { + patches: [ + { + op: 'add', + path: '/EXTERNAL_USER_ID-Rudderstack_a752d8ffaabe4c4d8a7a10cbdb2ee1525130a56a8290eef5d8a695434c49928f/audiences', + value: ['dummyId'], + }, + ], + }, + createUsers: { + records: [ + { + externalId: + 'Rudderstack_a752d8ffaabe4c4d8a7a10cbdb2ee1525130a56a8290eef5d8a695434c49928f', + hashedRecords: [ + { + email: 'email3@abc.com', + }, + { + email: 'email1@abc.com', + }, + { + email: 'email2@abc.com', + }, + ], + }, + ], + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + destination, + metadata: [generateMetadata(3), generateMetadata(4), generateMetadata(5)], + statusCode: 200, + }, + { + metadata: [generateMetadata(6)], + destination, + batched: false, + statusCode: 400, + error: '[AMAZON AUDIENCE]: identify is not supported', + statTags: { + errorCategory: 'dataValidation', + destinationId: 'default-destinationId', + errorType: 'instrumentation', + destType: 'AMAZON_AUDIENCE', + module: 'destination', + implementation: 'native', + workspaceId: 'default-workspaceId', + feature: 'router', + }, + }, + ], + }, + }, + }, + }, +]; From f2231cb87f48767889be781f93ee8da5d4ef1f29 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Wed, 9 Oct 2024 12:17:11 +0530 Subject: [PATCH 047/147] chore: fix delete endpoint for braze (#3791) * chore: fix delete endpoint for braze * chore: add example inline --- src/v0/destinations/braze/deleteUsers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/v0/destinations/braze/deleteUsers.js b/src/v0/destinations/braze/deleteUsers.js index 33c0f2ef7fa..a83763e90de 100644 --- a/src/v0/destinations/braze/deleteUsers.js +++ b/src/v0/destinations/braze/deleteUsers.js @@ -21,11 +21,12 @@ const userDeletionHandler = async (userAttributes, config) => { } // Endpoints different for different data centers. // DOC: https://www.braze.com/docs/user_guide/administrative/access_braze/braze_instances/ + // Example Data Center: "EU-01", "US-01" let endPoint; const endpointPath = '/users/delete'; const dataCenterArr = dataCenter.trim().split('-'); if (dataCenterArr[0].toLowerCase() === 'eu') { - endPoint = 'https://rest.fra-01.braze.eu/users/delete'; + endPoint = `https://rest.fra-${dataCenterArr[1]}.braze.eu/users/delete`; } else { endPoint = `https://rest.iad-${dataCenterArr[1]}.braze.com/users/delete`; } From b357dd4e8a49ed66576f731a6aac84da55397475 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:21:44 +0530 Subject: [PATCH 048/147] fix: add list of the props, which need to be placed at the root (#3777) * fix: add list of the props, which need to be placed at the root * chore: fix lint issue * chore: fix lint issue * chore: address comment * chore: address comment again --- src/v0/destinations/af/transform.js | 27 +++--- .../destinations/af/processor/data.ts | 92 +++++++++++++++++++ 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/src/v0/destinations/af/transform.js b/src/v0/destinations/af/transform.js index a611dcc249c..064cf003a84 100644 --- a/src/v0/destinations/af/transform.js +++ b/src/v0/destinations/af/transform.js @@ -1,6 +1,6 @@ const get = require('get-value'); const set = require('set-value'); - +const lodash = require('lodash'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { EventType } = require('../../../constants'); const { @@ -130,28 +130,29 @@ function getEventValueForUnIdentifiedTrackEvent(message) { function getEventValueMapFromMappingJson(message, mappingJson, isMultiSupport, config) { let eventValue = {}; - const { addPropertiesAtRoot, afCurrencyAtRoot } = config; - + const { addPropertiesAtRoot, afCurrencyAtRoot, listOfProps } = config; + const clonedProp = message.properties && lodash.cloneDeep(message.properties); if (addPropertiesAtRoot) { - eventValue = message.properties; + eventValue = clonedProp; } else { - set(eventValue, 'properties', message.properties); + if (Array.isArray(listOfProps) && listOfProps.length > 0) { + listOfProps.forEach((prop) => { + eventValue[prop.property] = clonedProp[prop.property]; + delete clonedProp[prop.property]; + }); + } + eventValue.properties = clonedProp; } const sourceKeys = Object.keys(mappingJson); sourceKeys.forEach((sourceKey) => { set(eventValue, mappingJson[sourceKey], get(message, sourceKey)); }); - if ( - isMultiSupport && - message.properties && - message.properties.products && - message.properties.products.length > 0 - ) { + if (isMultiSupport && clonedProp && clonedProp.products && clonedProp.products.length > 0) { const contentIds = []; const quantities = []; const prices = []; - message.properties.products.forEach((product) => { + clonedProp.products.forEach((product) => { contentIds.push(product.product_id); quantities.push(product.quantity); prices.push(product.price); @@ -164,7 +165,7 @@ function getEventValueMapFromMappingJson(message, mappingJson, isMultiSupport, c }; } if (afCurrencyAtRoot) { - eventValue.af_currency = message.properties.currency; + eventValue.af_currency = clonedProp.currency; } eventValue = removeUndefinedValues(eventValue); if (Object.keys(eventValue).length > 0) { diff --git a/test/integrations/destinations/af/processor/data.ts b/test/integrations/destinations/af/processor/data.ts index 9812f7f9025..dacef389431 100644 --- a/test/integrations/destinations/af/processor/data.ts +++ b/test/integrations/destinations/af/processor/data.ts @@ -1716,6 +1716,98 @@ export const existingTestCases = [ }, }, }, + { + name: 'af', + description: 'Place selected properties at root track call with af data', + id: 'selectedPropsAtRoot', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'track', + event: 'Order Completed', + sentAt: '2020-08-14T05:30:30.118Z', + context: commonContextWithExternalId, + messageId: '7208bbb6-2c4e-45bb-bf5b-ad426f3593e9', + timestamp: '2020-08-14T05:30:30.118Z', + properties: { + ...commonPropertiesWithProduct, + prop1: 'value1', + prop2: 'value2', + Prop3: 'value3', + }, + anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', + integrations: { AF: { af_uid: 'afUid' } }, + }, + destination: { + Config: { + devKey: 'abcde', + androidAppId: 'com.rudderlabs.javascript', + groupTypeTrait: 'email', + groupValueTrait: 'age', + trackProductsOnce: false, + trackRevenuePerProduct: false, + addPropertiesAtRoot: false, + listOfProps: [ + { + property: 'prop1', + }, + { + property: 'prop2', + }, + { + property: 'prop3', + }, + { + property: 'prop4', + }, + ], + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: commonV1EndPoint, + headers: commonHeader, + params: {}, + body: { + JSON: { + bundleIdentifier: 'com.rudderlabs.javascript', + eventValue: + '{"prop1":"value1","prop2":"value2","properties":{"tax":2,"total":27.5,"coupon":"hasbros","revenue":48,"price":25,"quantity":2,"currency":"ZAR","discount":2.5,"order_id":"50314b8e9bcf000000000000","products":[{"sku":"45790-32","url":"https://www.example.com/product/path","name":"Monopoly: 3rd Edition","price":19,"category":"Games","quantity":1,"image_url":"https:///www.example.com/product/path.jpg","product_id":"507f1f77bcf86cd799439011"},{"sku":"46493-32","name":"Uno Card Game","price":3,"category":"Games","quantity":2,"product_id":"505bd76785ebb509fc183733"}],"shipping":3,"subtotal":22.5,"affiliation":"Google Store","checkout_id":"fksdjfsdjfisjf9sdfjsd9f","Prop3":"value3"},"af_revenue":48,"af_price":[19,3],"af_quantity":[1,2],"af_order_id":"50314b8e9bcf000000000000","af_content_id":["507f1f77bcf86cd799439011","505bd76785ebb509fc183733"]}', + eventName: 'Order Completed', + eventCurrency: 'ZAR', + eventTime: '2020-08-14T05:30:30.118Z', + appsflyer_id: 'afUid', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, ]; export const data = [...existingTestCases, ...newConfigValidationTests]; From 644e97ee53e4075bc9d10977698618f419c14fb0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 9 Oct 2024 09:54:34 +0000 Subject: [PATCH 049/147] chore(release): 1.82.0 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a79be1db383..7b832a76021 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.82.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.81.0...v1.82.0) (2024-10-09) + + +### Features + +* onboard Amazon Audience ([#3727](https://github.com/rudderlabs/rudder-transformer/issues/3727)) ([5ac8186](https://github.com/rudderlabs/rudder-transformer/commit/5ac81860c51f9971343df8c61bfd0b2de8161735)) +* onboard intercom v2 destination ([#3721](https://github.com/rudderlabs/rudder-transformer/issues/3721)) ([f8cde8c](https://github.com/rudderlabs/rudder-transformer/commit/f8cde8c072eb9415368fb97f53a3070027a3943b)) + + +### Bug Fixes + +* add list of the props, which need to be placed at the root ([#3777](https://github.com/rudderlabs/rudder-transformer/issues/3777)) ([b357dd4](https://github.com/rudderlabs/rudder-transformer/commit/b357dd4e8a49ed66576f731a6aac84da55397475)) +* rakuten amount value rounded up to nearest integer ([#3784](https://github.com/rudderlabs/rudder-transformer/issues/3784)) ([f3046f0](https://github.com/rudderlabs/rudder-transformer/commit/f3046f0ae37c113c1239d988d056fc204f2776a0)) +* webhook proc workflow object assign bug ([#3775](https://github.com/rudderlabs/rudder-transformer/issues/3775)) ([de8e503](https://github.com/rudderlabs/rudder-transformer/commit/de8e503524c1e8e3320f7458c66b8581f121b9bb)) + ## [1.81.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.79.1...v1.81.0) (2024-10-04) diff --git a/package-lock.json b/package-lock.json index b8f677520fd..7502bbf5bf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.81.0", + "version": "1.82.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.81.0", + "version": "1.82.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 7aedc782bac..ca39df7ff3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.81.0", + "version": "1.82.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 0f2edb338711748298386637a68b02ee7fcf5b47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 10:04:41 +0530 Subject: [PATCH 050/147] chore(deps): bump actions/checkout from 4.1.1 to 4.2.1 (#3796) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.2.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.1...v4.2.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-pr-artifacts.yml | 2 +- .github/workflows/build-push-docker-image.yml | 6 +++--- .github/workflows/commitlint.yml | 2 +- .github/workflows/component-test-report.yml | 2 +- .github/workflows/draft-new-release.yml | 2 +- .github/workflows/dt-test-and-report-code-coverage.yml | 2 +- .github/workflows/housekeeping.yml | 2 +- .github/workflows/prepare-for-dev-deploy.yml | 2 +- .github/workflows/prepare-for-prod-dt-deploy.yml | 4 ++-- .github/workflows/prepare-for-prod-ut-deploy.yml | 4 ++-- .github/workflows/prepare-for-staging-deploy.yml | 4 ++-- .github/workflows/publish-new-release.yml | 2 +- .github/workflows/slack-notify.yml | 2 +- .github/workflows/ut-tests.yml | 2 +- .github/workflows/verify-server-start.yml | 2 +- .github/workflows/verify.yml | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-pr-artifacts.yml b/.github/workflows/build-pr-artifacts.yml index f6aaa189404..46670fba846 100644 --- a/.github/workflows/build-pr-artifacts.yml +++ b/.github/workflows/build-pr-artifacts.yml @@ -22,7 +22,7 @@ jobs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index cffb5f91da4..acc06496c27 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -64,7 +64,7 @@ jobs: should_execute_tests: ${{ steps.processing.outputs.should_execute_tests }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 - id: files @@ -92,7 +92,7 @@ jobs: needs: [get_sha, get_changed_files] steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 @@ -145,7 +145,7 @@ jobs: needs: [get_sha, get_changed_files] steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 7f6d068e157..68b9eb01afe 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 0 diff --git a/.github/workflows/component-test-report.yml b/.github/workflows/component-test-report.yml index 02df1478d4f..489104bf359 100644 --- a/.github/workflows/component-test-report.yml +++ b/.github/workflows/component-test-report.yml @@ -27,7 +27,7 @@ jobs: aws-region: us-east-1 - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index 82174d1d724..c91649db9ee 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -11,7 +11,7 @@ jobs: if: (github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/hotfix/')) && (github.actor == 'ItsSudip' || github.actor == 'krishna2020' || github.actor == 'saikumarrs' || github.actor == 'sandeepdsvs' || github.actor == 'koladilip' || github.actor == 'shrouti1507' || github.actor == 'anantjain45823' || github.actor == 'chandumlg' || github.actor == 'mihir-4116' || github.actor == 'yashasvibajpai' || github.actor == 'sanpj2292' || github.actor == 'utsabc') && (github.triggering_actor == 'ItsSudip' || github.triggering_actor == 'krishna2020' || github.triggering_actor == 'koladilip' || github.triggering_actor == 'saikumarrs' || github.triggering_actor == 'sandeepdsvs' || github.triggering_actor == 'shrouti1507' || github.triggering_actor == 'anantjain45823' || github.triggering_actor == 'chandumlg' || github.triggering_actor == 'mihir-4116' || github.triggering_actor == 'yashasvibajpai' || github.triggering_actor == 'sanpj2292' || github.triggering_actor == 'utsabc') steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 0 diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 85625a1558e..1c94dc07990 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -31,7 +31,7 @@ jobs: tests_run_outcome: ${{steps.run_tests.outcome}} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/housekeeping.yml b/.github/workflows/housekeeping.yml index 388b80c15f5..bd66a936899 100644 --- a/.github/workflows/housekeeping.yml +++ b/.github/workflows/housekeeping.yml @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 - name: Delete Old Branches uses: beatlabs/delete-old-branches-action@v0.0.10 diff --git a/.github/workflows/prepare-for-dev-deploy.yml b/.github/workflows/prepare-for-dev-deploy.yml index a1fdda8ccda..b5482bcddf1 100644 --- a/.github/workflows/prepare-for-dev-deploy.yml +++ b/.github/workflows/prepare-for-dev-deploy.yml @@ -32,7 +32,7 @@ jobs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/prepare-for-prod-dt-deploy.yml b/.github/workflows/prepare-for-prod-dt-deploy.yml index 8e589f5b208..0a61a359bfa 100644 --- a/.github/workflows/prepare-for-prod-dt-deploy.yml +++ b/.github/workflows/prepare-for-prod-dt-deploy.yml @@ -32,7 +32,7 @@ jobs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 @@ -71,7 +71,7 @@ jobs: TF_IMAGE_REPOSITORY: rudderstack/rudder-transformer steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/prepare-for-prod-ut-deploy.yml b/.github/workflows/prepare-for-prod-ut-deploy.yml index 468307b94a9..3053979b3e0 100644 --- a/.github/workflows/prepare-for-prod-ut-deploy.yml +++ b/.github/workflows/prepare-for-prod-ut-deploy.yml @@ -31,7 +31,7 @@ jobs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 @@ -74,7 +74,7 @@ jobs: TF_IMAGE_REPOSITORY: rudderstack/rudder-transformer steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/prepare-for-staging-deploy.yml b/.github/workflows/prepare-for-staging-deploy.yml index 60a6238aa8e..8eeafc376ee 100644 --- a/.github/workflows/prepare-for-staging-deploy.yml +++ b/.github/workflows/prepare-for-staging-deploy.yml @@ -24,7 +24,7 @@ jobs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 @@ -82,7 +82,7 @@ jobs: UT_TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name_ut }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/publish-new-release.yml b/.github/workflows/publish-new-release.yml index ee9f28e2350..b3eca58d7f7 100644 --- a/.github/workflows/publish-new-release.yml +++ b/.github/workflows/publish-new-release.yml @@ -25,7 +25,7 @@ jobs: echo "release_version=$version" >> $GITHUB_OUTPUT - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 0 diff --git a/.github/workflows/slack-notify.yml b/.github/workflows/slack-notify.yml index 1c5dbdbc063..3c4223752b4 100644 --- a/.github/workflows/slack-notify.yml +++ b/.github/workflows/slack-notify.yml @@ -16,7 +16,7 @@ jobs: if: ${{ inputs.should_notify }} steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 - name: notify uses: slackapi/slack-github-action@v1.27.0 diff --git a/.github/workflows/ut-tests.yml b/.github/workflows/ut-tests.yml index b825bdb9d3f..64d6501a9a7 100644 --- a/.github/workflows/ut-tests.yml +++ b/.github/workflows/ut-tests.yml @@ -25,7 +25,7 @@ jobs: run: go install sigs.k8s.io/kind@v0.17.0 - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/verify-server-start.yml b/.github/workflows/verify-server-start.yml index f87ed57eb8b..63213bae3f1 100644 --- a/.github/workflows/verify-server-start.yml +++ b/.github/workflows/verify-server-start.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: fetch-depth: 1 diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 0d389f0e555..c34c0012439 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.1 with: # Make sure the actual branch is checked out when running on pull requests ref: ${{ github.head_ref }} From 0ff2ac4193261c4f35db258467500754d4575691 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 10:16:46 +0530 Subject: [PATCH 051/147] chore(deps): bump actions/setup-node from 4.0.3 to 4.0.4 (#3749) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.0.3 to 4.0.4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4.0.3...v4.0.4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sankeerth --- .github/workflows/commitlint.yml | 2 +- .github/workflows/component-test-report.yml | 2 +- .github/workflows/draft-new-release.yml | 2 +- .github/workflows/dt-test-and-report-code-coverage.yml | 2 +- .github/workflows/publish-new-release.yml | 2 +- .github/workflows/ut-tests.yml | 2 +- .github/workflows/verify-server-start.yml | 2 +- .github/workflows/verify.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 68b9eb01afe..74e7f0e6041 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -16,7 +16,7 @@ jobs: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/component-test-report.yml b/.github/workflows/component-test-report.yml index 489104bf359..8d739c5aee6 100644 --- a/.github/workflows/component-test-report.yml +++ b/.github/workflows/component-test-report.yml @@ -32,7 +32,7 @@ jobs: fetch-depth: 1 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index c91649db9ee..602ded980fd 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -16,7 +16,7 @@ jobs: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 1c94dc07990..86963b62703 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -36,7 +36,7 @@ jobs: fetch-depth: 1 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/publish-new-release.yml b/.github/workflows/publish-new-release.yml index b3eca58d7f7..a91a1e2b22b 100644 --- a/.github/workflows/publish-new-release.yml +++ b/.github/workflows/publish-new-release.yml @@ -30,7 +30,7 @@ jobs: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/ut-tests.yml b/.github/workflows/ut-tests.yml index 64d6501a9a7..34442f83c55 100644 --- a/.github/workflows/ut-tests.yml +++ b/.github/workflows/ut-tests.yml @@ -30,7 +30,7 @@ jobs: fetch-depth: 1 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/verify-server-start.yml b/.github/workflows/verify-server-start.yml index 63213bae3f1..5f9c247428a 100644 --- a/.github/workflows/verify-server-start.yml +++ b/.github/workflows/verify-server-start.yml @@ -19,7 +19,7 @@ jobs: fetch-depth: 1 - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index c34c0012439..115cad42488 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -20,7 +20,7 @@ jobs: ref: ${{ github.head_ref }} - name: Setup Node - uses: actions/setup-node@v4.0.3 + uses: actions/setup-node@v4.0.4 with: node-version-file: .nvmrc cache: 'npm' From fa620e00db13b7bcdc599cb99966395cfbe53f96 Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 16 Oct 2024 10:40:39 +0530 Subject: [PATCH 052/147] fix: heap userId extraction --- .../v2/destinations/heap/procWorkflow.yaml | 4 +- .../destinations/heap/processor/data.ts | 118 ++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/cdk/v2/destinations/heap/procWorkflow.yaml b/src/cdk/v2/destinations/heap/procWorkflow.yaml index ac12e7e02a2..6e038bc66da 100644 --- a/src/cdk/v2/destinations/heap/procWorkflow.yaml +++ b/src/cdk/v2/destinations/heap/procWorkflow.yaml @@ -22,7 +22,7 @@ steps: $.assert(.message.traits ?? .message.context.traits, "traits are required"); $.context.endpoint = 'https://heapanalytics.com/api/add_user_properties'; $.context.payload = .message.({ - identity: {{{{$.getGenericPaths("userId")}}}}, + identity: {{{{$.getGenericPaths("userId", "||")}}}}, properties: $.flattenJson(.traits ?? .context.traits){~["idempotencyKey"]}, app_id: ^.destination.Config.appId }) @@ -32,7 +32,7 @@ steps: $.assert(.message.event, "event is required"); $.context.endpoint = 'https://heapanalytics.com/api/track'; $.context.payload = .message.({ - identity: {{{{$.getGenericPaths("userId")}}}}, + identity: {{{{$.getGenericPaths("userId", "||")}}}}, properties: $.flattenJson(.properties){~["idempotencyKey"]}, app_id: ^.destination.Config.appId, event: .event, diff --git a/test/integrations/destinations/heap/processor/data.ts b/test/integrations/destinations/heap/processor/data.ts index f503134148f..cb1aeb75632 100644 --- a/test/integrations/destinations/heap/processor/data.ts +++ b/test/integrations/destinations/heap/processor/data.ts @@ -117,6 +117,124 @@ export const data = [ }, }, }, + { + name: 'heap', + description: 'Blank user id', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + appId: '', + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + DisplayName: 'Heap.io', + ID: '1WTbl0l5GjOQKOvfmcGwk0T49kV', + Name: 'HEAP', + }, + Enabled: true, + ID: '1WTcDSEOE437e4ePH10BJNELXmE', + Name: 'heap test', + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + message: { + userId: '', + anonymousId: 'sampath', + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + locale: 'en-US', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', + }, + integrations: { + All: true, + }, + traits: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, + messageId: 'fca2e71a-5d30-48e1-ba45-761c16e3820f', + originalTimestamp: '2020-01-16T13:21:59.076Z', + receivedAt: '2020-01-16T18:52:03.871+05:30', + request_ip: '[::1]:62312', + sentAt: '2020-01-16T13:22:03.85Z', + timestamp: '2020-01-16T18:51:59.097+05:30', + type: 'identify', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://heapanalytics.com/api/add_user_properties', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + params: {}, + body: { + JSON: { + identity: 'sampath', + properties: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, + app_id: '', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + userId: 'sampath', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, { name: 'heap', description: 'Test 1', From e57841396ad666d716e195fbd4e9b74a63bf5191 Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:50:51 +0530 Subject: [PATCH 053/147] fix: heap userId extraction (#3801) --- .../v2/destinations/heap/procWorkflow.yaml | 4 +- .../destinations/heap/processor/data.ts | 118 ++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/cdk/v2/destinations/heap/procWorkflow.yaml b/src/cdk/v2/destinations/heap/procWorkflow.yaml index ac12e7e02a2..6e038bc66da 100644 --- a/src/cdk/v2/destinations/heap/procWorkflow.yaml +++ b/src/cdk/v2/destinations/heap/procWorkflow.yaml @@ -22,7 +22,7 @@ steps: $.assert(.message.traits ?? .message.context.traits, "traits are required"); $.context.endpoint = 'https://heapanalytics.com/api/add_user_properties'; $.context.payload = .message.({ - identity: {{{{$.getGenericPaths("userId")}}}}, + identity: {{{{$.getGenericPaths("userId", "||")}}}}, properties: $.flattenJson(.traits ?? .context.traits){~["idempotencyKey"]}, app_id: ^.destination.Config.appId }) @@ -32,7 +32,7 @@ steps: $.assert(.message.event, "event is required"); $.context.endpoint = 'https://heapanalytics.com/api/track'; $.context.payload = .message.({ - identity: {{{{$.getGenericPaths("userId")}}}}, + identity: {{{{$.getGenericPaths("userId", "||")}}}}, properties: $.flattenJson(.properties){~["idempotencyKey"]}, app_id: ^.destination.Config.appId, event: .event, diff --git a/test/integrations/destinations/heap/processor/data.ts b/test/integrations/destinations/heap/processor/data.ts index f503134148f..cb1aeb75632 100644 --- a/test/integrations/destinations/heap/processor/data.ts +++ b/test/integrations/destinations/heap/processor/data.ts @@ -117,6 +117,124 @@ export const data = [ }, }, }, + { + name: 'heap', + description: 'Blank user id', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + appId: '', + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + DisplayName: 'Heap.io', + ID: '1WTbl0l5GjOQKOvfmcGwk0T49kV', + Name: 'HEAP', + }, + Enabled: true, + ID: '1WTcDSEOE437e4ePH10BJNELXmE', + Name: 'heap test', + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + message: { + userId: '', + anonymousId: 'sampath', + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + locale: 'en-US', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', + }, + integrations: { + All: true, + }, + traits: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, + messageId: 'fca2e71a-5d30-48e1-ba45-761c16e3820f', + originalTimestamp: '2020-01-16T13:21:59.076Z', + receivedAt: '2020-01-16T18:52:03.871+05:30', + request_ip: '[::1]:62312', + sentAt: '2020-01-16T13:22:03.85Z', + timestamp: '2020-01-16T18:51:59.097+05:30', + type: 'identify', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://heapanalytics.com/api/add_user_properties', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + params: {}, + body: { + JSON: { + identity: 'sampath', + properties: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, + app_id: '', + }, + XML: {}, + JSON_ARRAY: {}, + FORM: {}, + }, + files: {}, + userId: 'sampath', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, { name: 'heap', description: 'Test 1', From 369e7cab0b2f28a6ff289c8ba8d430714577e78e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 16 Oct 2024 09:47:01 +0000 Subject: [PATCH 054/147] chore(release): 1.82.1 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b832a76021..a81c5b5feeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.82.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.0...v1.82.1) (2024-10-16) + + +### Bug Fixes + +* heap userId extraction ([fa620e0](https://github.com/rudderlabs/rudder-transformer/commit/fa620e00db13b7bcdc599cb99966395cfbe53f96)) + ## [1.82.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.81.0...v1.82.0) (2024-10-09) diff --git a/package-lock.json b/package-lock.json index 7502bbf5bf4..a4295bd74c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.82.0", + "version": "1.82.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.82.0", + "version": "1.82.1", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index ca39df7ff3a..6b41457633a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.82.0", + "version": "1.82.1", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 6c11be97cc3b86df70e1b9d82dd7c4d3771b814c Mon Sep 17 00:00:00 2001 From: Will Date: Thu, 17 Oct 2024 04:59:12 +0100 Subject: [PATCH 055/147] Should filter out falsey reserved attributes from Intercom destination (#3767) * Should filter out reserved attributes from Intercom destination even if they are falsey * Fix presence check to allow null values --------- Co-authored-by: Manish Kumar <144022547+manish339k@users.noreply.github.com> --- src/cdk/v2/destinations/intercom/utils.js | 2 +- src/cdk/v2/destinations/intercom/utils.test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cdk/v2/destinations/intercom/utils.js b/src/cdk/v2/destinations/intercom/utils.js index 22af726e846..a75f8155aff 100644 --- a/src/cdk/v2/destinations/intercom/utils.js +++ b/src/cdk/v2/destinations/intercom/utils.js @@ -257,7 +257,7 @@ const filterCustomAttributes = (payload, type, destination, message) => { let customAttributes = { ...get(payload, 'custom_attributes') }; if (customAttributes) { ReservedAttributesList.forEach((trait) => { - if (customAttributes[trait]) delete customAttributes[trait]; + if (trait in customAttributes) delete customAttributes[trait]; }); if (isDefinedAndNotNull(customAttributes) && Object.keys(customAttributes).length > 0) { customAttributes = diff --git a/src/cdk/v2/destinations/intercom/utils.test.js b/src/cdk/v2/destinations/intercom/utils.test.js index c2bf3f8e892..e2c1fb9a072 100644 --- a/src/cdk/v2/destinations/intercom/utils.test.js +++ b/src/cdk/v2/destinations/intercom/utils.test.js @@ -318,6 +318,18 @@ describe('filterCustomAttributes utility test', () => { expect(result).toBeUndefined(); }); + it('Should filter out custom attributes that are reserved attributes and that are false', () => { + const payload = { custom_attributes: { unsubscribedFromEmails: false } }; + const result = filterCustomAttributes(payload, 'user', { Config: { apiVersion: 'v2' } }); + expect(result).toBeUndefined(); + }); + + it('Should filter out custom attributes that are reserved attributes and that are null', () => { + const payload = { custom_attributes: { unsubscribedFromEmails: null } }; + const result = filterCustomAttributes(payload, 'user', { Config: { apiVersion: 'v2' } }); + expect(result).toBeUndefined(); + }); + it('Should return a flattened object when custom attributes are not null, not reserved attributes and nested', () => { const payload = { custom_attributes: { source: 'rudder-js-sdk', data: { nestedAttribute: 'nestedValue' } }, From b33eadca7000d7364a8c22c9627e96135270a6a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:26:21 +0530 Subject: [PATCH 056/147] chore(deps): bump koa and @types/koa (#3709) Bumps [koa](https://github.com/koajs/koa) and [@types/koa](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/koa). These dependencies needed to be updated together. Updates `koa` from 2.15.0 to 2.15.3 - [Changelog](https://github.com/koajs/koa/blob/2.15.3/History.md) - [Commits](https://github.com/koajs/koa/compare/2.15.0...2.15.3) Updates `@types/koa` from 2.13.12 to 2.15.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/koa) --- updated-dependencies: - dependency-name: koa dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: "@types/koa" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> --- package-lock.json | 14 ++++++++------ package.json | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4295bd74c3..d3b578f6856 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "json-size": "^1.0.0", "jsontoxml": "^1.0.1", "jstoxml": "^5.0.2", - "koa": "^2.14.1", + "koa": "^2.15.3", "koa-bodyparser": "^4.4.0", "koa2-swagger-ui": "^5.7.0", "libphonenumber-js": "^1.11.1", @@ -83,7 +83,7 @@ "@types/fast-json-stable-stringify": "^2.1.0", "@types/jest": "^29.5.1", "@types/jsonpath": "^0.2.4", - "@types/koa": "^2.13.6", + "@types/koa": "^2.15.0", "@types/koa-bodyparser": "^4.3.10", "@types/lodash": "^4.14.197", "@types/node": "^20.2.5", @@ -7791,8 +7791,9 @@ "license": "MIT" }, "node_modules/@types/koa": { - "version": "2.13.12", - "license": "MIT", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.15.0.tgz", + "integrity": "sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==", "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", @@ -16327,8 +16328,9 @@ } }, "node_modules/koa": { - "version": "2.15.0", - "license": "MIT", + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.15.3.tgz", + "integrity": "sha512-j/8tY9j5t+GVMLeioLaxweJiKUayFhlGqNTzf2ZGwL0ZCQijd2RLHK0SLW5Tsko8YyyqCZC2cojIb0/s62qTAg==", "dependencies": { "accepts": "^1.3.5", "cache-content-type": "^1.0.0", diff --git a/package.json b/package.json index 6b41457633a..f5d44d8e2b2 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "json-size": "^1.0.0", "jsontoxml": "^1.0.1", "jstoxml": "^5.0.2", - "koa": "^2.14.1", + "koa": "^2.15.3", "koa-bodyparser": "^4.4.0", "koa2-swagger-ui": "^5.7.0", "libphonenumber-js": "^1.11.1", @@ -128,7 +128,7 @@ "@types/fast-json-stable-stringify": "^2.1.0", "@types/jest": "^29.5.1", "@types/jsonpath": "^0.2.4", - "@types/koa": "^2.13.6", + "@types/koa": "^2.15.0", "@types/koa-bodyparser": "^4.3.10", "@types/lodash": "^4.14.197", "@types/node": "^20.2.5", From d730dafbbd2de30b67c35db8ca05396a98a8d2e0 Mon Sep 17 00:00:00 2001 From: Akash Chetty Date: Thu, 17 Oct 2024 12:12:42 +0530 Subject: [PATCH 057/147] fix: populate source destination info env set properly (#3806) --- src/warehouse/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 4afa8f72c2d..3491a257da0 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -30,7 +30,7 @@ const whExtractEventTableColumnMappingRules = require('./config/WHExtractEventTa const maxColumnsInEvent = parseInt(process.env.WH_MAX_COLUMNS_IN_EVENT || '200', 10); const WH_POPULATE_SRC_DEST_INFO_IN_CONTEXT = - process.env.WH_POPULATE_SRC_DEST_INFO_IN_CONTEXT || true; + process.env.WH_POPULATE_SRC_DEST_INFO_IN_CONTEXT !== 'false'; const getDataType = (key, val, options, jsonKey = false) => { const type = typeof val; From 88c6175391cf4575a57936aced898465ad78b55e Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:40:44 +0530 Subject: [PATCH 058/147] fix: add missing fields to pinterest_tag mapping (#3814) * feat: add missing fields on the pinterest_tag mapping * chore: fix test cases * chore: remove redundant old implementation * chore: remove test cases related to pinterest_tag * chore: fix test cases * chore: fix lint issue * chore: fix lint issue again * chore: revert service.api.test.ts changes --- .../v2/destinations/pinterest_tag/config.js | 19 + .../pinterest_tag/procWorkflow.yaml | 24 +- .../pinterest_tag/rtWorkflow.yaml | 2 +- .../v2/destinations/pinterest_tag/utils.js | 150 +++++++ .../destinations/pinterest_tag/utils.test.js | 2 +- src/v0/destinations/pinterest_tag/config.js | 31 -- .../data/pinterestCommonConfig.json | 61 --- .../data/pinterestCustomConfig.json | 38 -- .../data/pinterestUserConfig.json | 93 ---- .../destinations/pinterest_tag/transform.js | 202 --------- src/v0/destinations/pinterest_tag/utils.js | 416 ------------------ test/__tests__/data/pinterest_tag_input.json | 15 + test/__tests__/data/pinterest_tag_output.json | 61 +++ .../pinterest_tag_router_batch_output.json | 104 ++++- .../data/pinterest_tag_router_input.json | 16 + .../data/pinterest_tag_router_output.json | 72 +++ test/__tests__/pinterestConversion.test.js | 54 --- .../proc/batch_input_multiplex.json | 2 + .../destination/proc/multiplex_failure.json | 5 +- .../proc/multiplex_partial_failure.json | 6 +- .../destination/proc/multiplex_success.json | 1 + .../destination/router/failure_test.json | 7 +- test/apitests/service.api.test.ts | 1 - .../pinterest_tag/processor/data.ts | 200 +++++++-- .../destinations/pinterest_tag/router/data.ts | 148 ++++++- .../destinations/pinterest_tag/step/data.ts | 286 ++++++++++-- 26 files changed, 997 insertions(+), 1019 deletions(-) create mode 100644 src/cdk/v2/destinations/pinterest_tag/config.js create mode 100644 src/cdk/v2/destinations/pinterest_tag/utils.js rename src/{v0 => cdk/v2}/destinations/pinterest_tag/utils.test.js (97%) delete mode 100644 src/v0/destinations/pinterest_tag/config.js delete mode 100644 src/v0/destinations/pinterest_tag/data/pinterestCommonConfig.json delete mode 100644 src/v0/destinations/pinterest_tag/data/pinterestCustomConfig.json delete mode 100644 src/v0/destinations/pinterest_tag/data/pinterestUserConfig.json delete mode 100644 src/v0/destinations/pinterest_tag/transform.js delete mode 100644 src/v0/destinations/pinterest_tag/utils.js delete mode 100644 test/__tests__/pinterestConversion.test.js diff --git a/src/cdk/v2/destinations/pinterest_tag/config.js b/src/cdk/v2/destinations/pinterest_tag/config.js new file mode 100644 index 00000000000..9e019e14368 --- /dev/null +++ b/src/cdk/v2/destinations/pinterest_tag/config.js @@ -0,0 +1,19 @@ +const ENDPOINT = 'https://ct.pinterest.com/events/v3'; +// ref: https://developers.pinterest.com/docs/api/v5/#tag/conversion_events +const getV5EventsEndpoint = (adAccountId) => + `https://api.pinterest.com/v5/ad_accounts/${adAccountId}/events`; + +const API_VERSION = { + v3: 'legacyApi', + v5: 'newApi', +}; + +// ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html +const MAX_BATCH_SIZE = 1000; + +module.exports = { + ENDPOINT, + MAX_BATCH_SIZE, + getV5EventsEndpoint, + API_VERSION, +}; diff --git a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml index 1122a80404c..64d391c8882 100644 --- a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml @@ -3,8 +3,8 @@ bindings: path: ../../../../constants - path: ../../bindings/jsontemplate exportAll: true - - path: ../../../../v0/destinations/pinterest_tag/utils - - path: ../../../../v0/destinations/pinterest_tag/config + - path: ./utils + - path: ./config - name: removeUndefinedValues path: ../../../../v0/util - name: removeUndefinedAndNullAndEmptyValues @@ -66,7 +66,10 @@ steps: "opt_out": .context.device.adTrackingEnabled !== undefined ? !.context.device.adTrackingEnabled, "event_id": $.getOneByPaths(., ^.destination.Config.deduplicationKey) ?? .messageId, "app_id": ^.destination.Config.appId, - "advertiser_id": ^.destination.Config.advertiserId + "advertiser_id": ^.destination.Config.advertiserId, + "partner_name": .properties.partnerName, + "device_carrier": .context.network.carrier, + "wifi": .context.network.wifi }); $.outputs.apiVersion === {{$.API_VERSION.v5}} ? commonFields = commonFields{~["advertiser_id"]}; $.removeUndefinedValues(commonFields) @@ -103,7 +106,8 @@ steps: "client_ip_address": .context.ip ?? .request_ip, "client_user_agent": .context.userAgent, "external_id": {{{{$.getGenericPaths("userId")}}}}, - "click_id": .properties.clickId + "click_id": .properties.clickId, + "partner_id": .traits.partnerId ?? .context.traits.partnerId }); !.destination.Config.sendExternalId ? userFields = userFields{~["external_id"]} : null; userFields = $.removeUndefinedAndNullAndEmptyValues(userFields); @@ -129,7 +133,11 @@ steps: "num_items": .properties.numOfItems && Number(.properties.numOfItems), "order_id": .properties.order_id, "search_string": .properties.query, - "opt_out_type": .properties.optOutType + "opt_out_type": .properties.optOutType, + "content_name": .properties.contentName, + "content_category": .properties.contentCategory, + "content_brand": .properties.contentBrand, + "np": .properties.np }); $.removeUndefinedValues(customFields) @@ -143,7 +151,11 @@ steps: "content_ids": products.(.product_id ?? .sku ?? .id)[], "contents": .message.properties@prop.products.({ "quantity": Number(.quantity ?? prop.quantity ?? 1), - "item_price": String(.price ?? prop.price) + "item_price": String(.price ?? prop.price), + "item_name": String(.name), + "id": .product_id ?? .sku, + "item_category": .category, + "item_brand": .brand })[] } else: diff --git a/src/cdk/v2/destinations/pinterest_tag/rtWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/rtWorkflow.yaml index 215ead12b12..bd4a9439f0f 100644 --- a/src/cdk/v2/destinations/pinterest_tag/rtWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/rtWorkflow.yaml @@ -1,5 +1,5 @@ bindings: - - path: ../../../../v0/destinations/pinterest_tag/config + - path: ./config - name: batchMultiplexedEvents path: ../../../../v0/util/index steps: diff --git a/src/cdk/v2/destinations/pinterest_tag/utils.js b/src/cdk/v2/destinations/pinterest_tag/utils.js new file mode 100644 index 00000000000..31a897f1338 --- /dev/null +++ b/src/cdk/v2/destinations/pinterest_tag/utils.js @@ -0,0 +1,150 @@ +/* eslint-disable no-param-reassign */ +const sha256 = require('sha256'); +const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); + +const { API_VERSION } = require('./config'); + +const VALID_ACTION_SOURCES = ['app_android', 'app_ios', 'web', 'offline']; + +const ecomEventMaps = [ + { + src: ['order completed'], + dest: 'checkout', + }, + { + src: ['product added'], + dest: 'add_to_cart', + }, + { + src: ['products searched', 'product list filtered'], + dest: 'search', + }, +]; + +const USER_NON_ARRAY_PROPERTIES = ['client_user_agent', 'client_ip_address']; + +const getHashedValue = (key, value) => { + switch (key) { + case 'em': + case 'ct': + case 'st': + case 'country': + case 'ln': + case 'fn': + case 'ge': + value = Array.isArray(value) + ? value.map((val) => val.toString().trim().toLowerCase()) + : value.toString().trim().toLowerCase(); + break; + case 'ph': + // phone numbers should only contain digits & should not contain leading zeros + value = Array.isArray(value) + ? value.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')) + : value.toString().replace(/\D/g, '').replace(/^0+/, ''); + break; + case 'zp': + // zip fields should only contain digits + value = Array.isArray(value) + ? value.map((val) => val.toString().trim().replace(/\D/g, '')) + : value.toString().replace(/\D/g, ''); + break; + case 'hashed_maids': + case 'external_id': + case 'db': + // no action needed on value + break; + default: + return String(value); + } + return Array.isArray(value) ? value.map((val) => sha256(val)) : [sha256(value)]; +}; + +/** + * + * @param {*} userPayload Payload mapped from user fields + * @returns + * Further Processing the user fields following the instructions of Pinterest Conversion API + * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html + */ +const processUserPayload = (userPayload) => { + Object.keys(userPayload).forEach((key) => { + userPayload[key] = getHashedValue(key, userPayload[key]); + }); + return userPayload; +}; + +/** + * + * @param {*} eventName // ["WatchVideo", "ViewCategory", "Custom"] + * @returns // ["watch_video", "view_category", "custom""] + * This function will return the snake case name of the destination config mapped event + */ +const convertToSnakeCase = (eventName) => + eventName.map((str) => + str + .replace(/([a-z])([A-Z])/g, '$1_$2') + .replace(/\s+/g, '_') + .toLowerCase(), + ); + +/** + * + * @param {*} userPayload + * @param {*} message + * @returns converts every single hashed user data property to array, except for + * "client_user_agent", "client_ip_address" + * + */ +const processHashedUserPayload = (userPayload, message) => { + const processedHashedUserPayload = {}; + Object.keys(userPayload).forEach((key) => { + if (!USER_NON_ARRAY_PROPERTIES.includes(key)) { + if (Array.isArray(userPayload[key])) { + processedHashedUserPayload[key] = [...userPayload[key]]; + } else { + processedHashedUserPayload[key] = [userPayload[key]]; + } + } else { + processedHashedUserPayload[key] = userPayload[key]; + } + }); + // multiKeyMap will works on only specific values like m, male, MALE, f, F, Female + // if hashed data is sent from the user, it is directly set over here + const gender = message.traits?.gender || message.context?.traits?.gender; + if (gender && Array.isArray(gender)) { + processedHashedUserPayload.ge = [...gender]; + } else if (gender) { + processedHashedUserPayload.ge = [gender]; + } + return processedHashedUserPayload; +}; + +const validateInput = (message, { Config }) => { + const { apiVersion = API_VERSION.v3, advertiserId, adAccountId, conversionToken } = Config; + if (apiVersion === API_VERSION.v3 && !advertiserId) { + throw new ConfigurationError('Advertiser Id not found. Aborting'); + } + + if (apiVersion === API_VERSION.v5) { + if (!adAccountId) { + throw new ConfigurationError('Ad Account ID not found. Aborting'); + } + + if (!conversionToken) { + throw new ConfigurationError('Conversion Token not found. Aborting'); + } + } + + if (!message.type) { + throw new InstrumentationError('Event type is required'); + } +}; + +module.exports = { + processUserPayload, + processHashedUserPayload, + VALID_ACTION_SOURCES, + ecomEventMaps, + convertToSnakeCase, + validateInput, +}; diff --git a/src/v0/destinations/pinterest_tag/utils.test.js b/src/cdk/v2/destinations/pinterest_tag/utils.test.js similarity index 97% rename from src/v0/destinations/pinterest_tag/utils.test.js rename to src/cdk/v2/destinations/pinterest_tag/utils.test.js index 6b4cef95677..1c1d080ef51 100644 --- a/src/v0/destinations/pinterest_tag/utils.test.js +++ b/src/cdk/v2/destinations/pinterest_tag/utils.test.js @@ -1,4 +1,4 @@ -const { processUserPayload } = require('../../../../src/v0/destinations/pinterest_tag/utils'); +const { processUserPayload } = require('./utils'); const userFields = [ { diff --git a/src/v0/destinations/pinterest_tag/config.js b/src/v0/destinations/pinterest_tag/config.js deleted file mode 100644 index 9216b6f61b4..00000000000 --- a/src/v0/destinations/pinterest_tag/config.js +++ /dev/null @@ -1,31 +0,0 @@ -const { getMappingConfig } = require('../../util'); - -const ENDPOINT = 'https://ct.pinterest.com/events/v3'; -// ref: https://developers.pinterest.com/docs/api/v5/#tag/conversion_events -const getV5EventsEndpoint = (adAccountId) => - `https://api.pinterest.com/v5/ad_accounts/${adAccountId}/events`; - -const API_VERSION = { - v3: 'legacyApi', - v5: 'newApi', -}; - -// ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html -const MAX_BATCH_SIZE = 1000; - -const CONFIG_CATEGORIES = { - USER_CONFIGS: { name: 'pinterestUserConfig' }, - COMMON_CONFIGS: { name: 'pinterestCommonConfig' }, - CUSTOM_CONFIGS: { name: 'pinterestCustomConfig' }, -}; -const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); - -module.exports = { - ENDPOINT, - MAX_BATCH_SIZE, - USER_CONFIGS: MAPPING_CONFIG[CONFIG_CATEGORIES.USER_CONFIGS.name], - COMMON_CONFIGS: MAPPING_CONFIG[CONFIG_CATEGORIES.COMMON_CONFIGS.name], - CUSTOM_CONFIGS: MAPPING_CONFIG[CONFIG_CATEGORIES.CUSTOM_CONFIGS.name], - getV5EventsEndpoint, - API_VERSION, -}; diff --git a/src/v0/destinations/pinterest_tag/data/pinterestCommonConfig.json b/src/v0/destinations/pinterest_tag/data/pinterestCommonConfig.json deleted file mode 100644 index 52645fa25a0..00000000000 --- a/src/v0/destinations/pinterest_tag/data/pinterestCommonConfig.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "destKey": "event_name", - "sourceKeys": "event" - }, - { - "destKey": "event_time", - "sourceKeys": "timestamp", - "sourceFromGenericMap": true, - "required": true, - "metadata": { - "type": "secondTimestamp" - } - }, - { - "destKey": "event_source_url", - "sourceKeys": "pageUrl", - "sourceFromGenericMap": true - }, - { - "destKey": "action_source", - "sourceKeys": [ - "traits.action_source", - "context.traits.action_source", - "traits.actionSource", - "context.traits.actionSource", - "properties.action_source", - "properties.actionSource", - "channel" - ], - "required": true - }, - { - "destKey": "app_name", - "sourceKeys": ["properties.appName", "context.app.name"] - }, - { - "destKey": "app_version", - "sourceKeys": ["properties.appVersion", "context.app.version"] - }, - { - "destKey": "device_brand", - "sourceKeys": ["properties.manufacturer", "context.device.manufacturer"] - }, - { - "destKey": "device_model", - "sourceKeys": ["properties.deviceModel", "context.device.model"] - }, - { - "destKey": "device_type", - "sourceKeys": ["properties.deviceType", "context.device.type"] - }, - { - "destKey": "os_version", - "sourceKeys": "context.os.version" - }, - { - "destKey": "language", - "sourceKeys": ["properties.language", "context.traits.language", "context.locale"] - } -] diff --git a/src/v0/destinations/pinterest_tag/data/pinterestCustomConfig.json b/src/v0/destinations/pinterest_tag/data/pinterestCustomConfig.json deleted file mode 100644 index 55c9e1e9ed0..00000000000 --- a/src/v0/destinations/pinterest_tag/data/pinterestCustomConfig.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "destKey": "currency", - "sourceKeys": "properties.currency", - "required": false - }, - { - "destKey": "value", - "sourceKeys": ["properties.value", "properties.total", "properties.revenue"], - "required": false, - "metadata": { - "type": "toString" - } - }, - { - "destKey": "num_items", - "sourceKeys": "properties.numOfItems", - "metadata": { - "type": "toInt" - }, - "required": false - }, - { - "destKey": "order_id", - "sourceKeys": "properties.order_id", - "required": false - }, - { - "destKey": "search_string", - "sourceKeys": "properties.query", - "required": false - }, - { - "destKey": "opt_out_type", - "sourceKeys": "properties.optOutType", - "required": false - } -] diff --git a/src/v0/destinations/pinterest_tag/data/pinterestUserConfig.json b/src/v0/destinations/pinterest_tag/data/pinterestUserConfig.json deleted file mode 100644 index b95f539e7ce..00000000000 --- a/src/v0/destinations/pinterest_tag/data/pinterestUserConfig.json +++ /dev/null @@ -1,93 +0,0 @@ -[ - { - "destKey": "em", - "sourceKeys": "emailOnly", - "sourceFromGenericMap": true, - "required": false - }, - { - "destKey": "ph", - "sourceKeys": "phone", - "sourceFromGenericMap": true, - "required": false - }, - { - "destKey": "ge", - "sourceKeys": ["traits.gender", "context.traits.gender"], - "required": false, - "metadata": { - "multikeyMap": [ - { - "sourceVal": ["f", "F", "Female", "female", "FEMALE"], - "destVal": "f" - }, - { - "sourceVal": ["m", "M", "Male", "male", "MALE"], - "destVal": "m" - }, - { - "sourceVal": ["n", "N", "non-binary", "non binary", "Non-Binary", "Non Binary"], - "destVal": "n" - } - ] - } - }, - { - "destKey": "db", - "sourceKeys": "birthday", - "required": false, - "sourceFromGenericMap": true - }, - { - "destKey": "ln", - "sourceKeys": "lastName", - "required": false, - "sourceFromGenericMap": true - }, - { - "destKey": "fn", - "sourceKeys": "firstName", - "required": false, - "sourceFromGenericMap": true - }, - { - "destKey": "ct", - "sourceKeys": ["traits.address.city", "context.traits.address.city"], - "required": false - }, - { - "destKey": "st", - "sourceKeys": ["traits.address.state", "context.traits.address.state"], - "required": false - }, - { - "destKey": "zp", - "sourceKeys": ["traits.address.zip", "context.traits.address.zip"], - "required": false - }, - { - "destKey": "country", - "sourceKeys": ["traits.address.country", "context.traits.address.country"], - "required": false - }, - { - "destKey": "hashed_maids", - "sourceKeys": ["context.device.advertisingId"], - "required": false - }, - { - "destKey": "client_ip_address", - "sourceKeys": ["context.ip", "request_ip"], - "required": false - }, - { - "destKey": "client_user_agent", - "sourceKeys": "context.userAgent", - "required": false - }, - { - "destKey": "external_id", - "sourceKeys": "userId", - "sourceFromGenericMap": true - } -] diff --git a/src/v0/destinations/pinterest_tag/transform.js b/src/v0/destinations/pinterest_tag/transform.js deleted file mode 100644 index f8ccfd48eab..00000000000 --- a/src/v0/destinations/pinterest_tag/transform.js +++ /dev/null @@ -1,202 +0,0 @@ -const { get } = require('lodash'); -const { InstrumentationError } = require('@rudderstack/integrations-lib'); -const { EventType } = require('../../../constants'); -const { - defaultRequestConfig, - defaultPostRequestConfig, - getSuccessRespEvents, - constructPayload, - defaultBatchRequestConfig, - removeUndefinedAndNullValues, - batchMultiplexedEvents, - handleRtTfSingleEventError, -} = require('../../util'); -const { - processUserPayload, - processCommonPayload, - deduceEventName, - postProcessEcomFields, - checkUserPayloadValidity, - processHashedUserPayload, - validateInput, -} = require('./utils'); - -const { - ENDPOINT, - MAX_BATCH_SIZE, - USER_CONFIGS, - getV5EventsEndpoint, - API_VERSION, -} = require('./config'); - -const responseBuilderSimple = (finalPayload, { Config }) => { - const { apiVersion = API_VERSION.v3, adAccountId, conversionToken, sendAsTestEvent } = Config; - const response = defaultRequestConfig(); - response.endpoint = ENDPOINT; - response.method = defaultPostRequestConfig.requestMethod; - response.body.JSON = removeUndefinedAndNullValues(finalPayload); - - response.headers = { 'Content-Type': 'application/json' }; - - if (apiVersion === API_VERSION.v5) { - response.endpoint = getV5EventsEndpoint(adAccountId); - response.headers = { - 'Content-Type': 'application/json', - Authorization: `Bearer ${conversionToken}`, - }; - } - if (sendAsTestEvent) { - response.params = { - test: true, - }; - } - - return response; -}; - -/** - * - * @param {*} message - * @param {*} destination.Config - * @param {*} messageType - * @param {*} eventName - * @returns the output of each input payload. - * message deduplication logic looks like below: - * This facility is provided *only* for the users who are using the *new configuration*. - * if "enableDeduplication" is set to *true* and "deduplicationKey" is set via webapp, that key value will be - * sent as "event_id". On it's absence it will fallback to "messageId". - * And if "enableDeduplication" is set to false, it will fallback to "messageId" - */ -const commonFieldResponseBuilder = (message, { Config }, messageType, eventName) => { - let processedUserPayload; - const { appId, advertiserId, deduplicationKey, sendingUnHashedData, sendExternalId, apiVersion } = - Config; - // ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html - const processedCommonPayload = processCommonPayload(message); - - processedCommonPayload.event_id = get(message, `${deduplicationKey}`) || message.messageId; - const userPayload = constructPayload(message, USER_CONFIGS, 'pinterest'); - - if (!sendExternalId) { - delete userPayload.external_id; - } - - const isValidUserPayload = checkUserPayloadValidity(userPayload); - if (isValidUserPayload === false) { - throw new InstrumentationError( - 'It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent', - ); - } - - /** - * User can configure hashed checkbox to false if they are sending already hashed data to Rudderstack - * Otherwise we will hash data user data by default. - */ - if (sendingUnHashedData) { - processedUserPayload = processUserPayload(userPayload); - } else { - // when user is sending already hashed data to Rudderstack - processedUserPayload = processHashedUserPayload(userPayload, message); - } - - let response = { - ...processedCommonPayload, - event_name: eventName, - app_id: appId, - advertiser_id: advertiserId, - user_data: processedUserPayload, - }; - - if (apiVersion === API_VERSION.v5) { - delete response.advertiser_id; - } - - if (messageType === EventType.TRACK) { - response = postProcessEcomFields(message, response); - } - - return response; -}; - -const process = (event) => { - const toSendEvents = []; - const respList = []; - const deducedEventNameArray = []; - const { message, destination } = event; - const messageType = message.type?.toLowerCase(); - - validateInput(message, destination); - - switch (messageType) { - case EventType.PAGE: - case EventType.SCREEN: - case EventType.TRACK: - deducedEventNameArray.push(...deduceEventName(message, destination.Config)); - deducedEventNameArray.forEach((eventName) => { - toSendEvents.push(commonFieldResponseBuilder(message, destination, messageType, eventName)); - }); - - break; - default: - throw new InstrumentationError(`message type ${messageType} is not supported`); - } - - toSendEvents.forEach((sendEvent) => { - respList.push(responseBuilderSimple(sendEvent, destination)); - }); - return respList; -}; - -const generateBatchedPayloadForArray = (events) => { - const { batchedRequest } = defaultBatchRequestConfig(); - const batchResponseList = events.map((event) => event.body.JSON); - batchedRequest.body.JSON = { data: batchResponseList }; - batchedRequest.endpoint = events[0].endpoint; - batchedRequest.headers = events[0].headers; - - return batchedRequest; -}; - -const batchEvents = (successRespList) => { - const batchResponseList = []; - const batchedEvents = batchMultiplexedEvents(successRespList, MAX_BATCH_SIZE); - batchedEvents.forEach((batch) => { - const batchedRequest = generateBatchedPayloadForArray(batch.events); - batchResponseList.push( - getSuccessRespEvents(batchedRequest, batch.metadata, batch.destination, true), - ); - }); - - return batchResponseList; -}; - -const processRouterDest = (inputs, reqMetadata) => { - const successRespList = []; - const batchErrorRespList = []; - inputs.forEach((input) => { - try { - let resp = input.message; - // transform if not already done - if (!input.message.statusCode) { - resp = process(input); - } - - successRespList.push({ - message: Array.isArray(resp) ? resp : [resp], - metadata: input.metadata, - destination: input.destination, - }); - } catch (error) { - batchErrorRespList.push(handleRtTfSingleEventError(input, error, reqMetadata)); - } - }); - - let batchResponseList = []; - if (successRespList.length > 0) { - batchResponseList = batchEvents(successRespList); - } - - return [...batchResponseList, ...batchErrorRespList]; -}; - -module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/pinterest_tag/utils.js b/src/v0/destinations/pinterest_tag/utils.js deleted file mode 100644 index 57d595571fd..00000000000 --- a/src/v0/destinations/pinterest_tag/utils.js +++ /dev/null @@ -1,416 +0,0 @@ -/* eslint-disable no-param-reassign */ -const sha256 = require('sha256'); -const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); -const { EventType } = require('../../../constants'); -const { - constructPayload, - isDefinedAndNotNull, - isDefined, - getHashFromArrayWithDuplicate, - removeUndefinedAndNullValues, - validateEventName, -} = require('../../util'); -const { COMMON_CONFIGS, CUSTOM_CONFIGS, API_VERSION } = require('./config'); - -const VALID_ACTION_SOURCES = ['app_android', 'app_ios', 'web', 'offline']; - -const ecomEventMaps = [ - { - src: ['order completed'], - dest: 'checkout', - }, - { - src: ['product added'], - dest: 'add_to_cart', - }, - { - src: ['products searched', 'product list filtered'], - dest: 'search', - }, -]; - -const USER_NON_ARRAY_PROPERTIES = ['client_user_agent', 'client_ip_address']; - -const getHashedValue = (key, value) => { - switch (key) { - case 'em': - case 'ct': - case 'st': - case 'country': - case 'ln': - case 'fn': - case 'ge': - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().toLowerCase()) - : value.toString().trim().toLowerCase(); - break; - case 'ph': - // phone numbers should only contain digits & should not contain leading zeros - value = Array.isArray(value) - ? value.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')) - : value.toString().replace(/\D/g, '').replace(/^0+/, ''); - break; - case 'zp': - // zip fields should only contain digits - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().replace(/\D/g, '')) - : value.toString().replace(/\D/g, ''); - break; - case 'hashed_maids': - case 'external_id': - case 'db': - // no action needed on value - break; - default: - return String(value); - } - return Array.isArray(value) ? value.map((val) => sha256(val)) : [sha256(value)]; -}; - -/** - * - * @param {*} userPayload Payload mapped from user fields - * @returns - * Further Processing the user fields following the instructions of Pinterest Conversion API - * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html - */ -const processUserPayload = (userPayload) => { - Object.keys(userPayload).forEach((key) => { - userPayload[key] = getHashedValue(key, userPayload[key]); - }); - return userPayload; -}; - -/** - * - * @param {*} message - * @returns opt_out status - * - */ - -const deduceOptOutStatus = (message) => { - const adTrackingEnabled = message.context?.device?.adTrackingEnabled; - let optOut; - - // for ios - if (isDefinedAndNotNull(adTrackingEnabled)) { - if (adTrackingEnabled === true) { - optOut = false; - } else if (adTrackingEnabled === false) { - optOut = true; - } - } - - return optOut; -}; - -/** - * - * @param {*} message - * @returns - * Maps the required common parameters accross event types. Checks for the correct - * action source types and deduces opt_out status - * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html - */ -const processCommonPayload = (message) => { - const commonPayload = constructPayload(message, COMMON_CONFIGS); - const presentActionSource = commonPayload.action_source; - if (presentActionSource && !VALID_ACTION_SOURCES.includes(presentActionSource.toLowerCase())) { - throw new InstrumentationError( - `Action source must be one of ${VALID_ACTION_SOURCES.join(', ')}`, - ); - } - - commonPayload.opt_out = deduceOptOutStatus(message); - - return commonPayload; -}; - -/** - * - * @param {*} eventName // ["WatchVideo", "ViewCategory", "Custom"] - * @returns // ["watch_video", "view_category", "custom""] - * This function will return the snake case name of the destination config mapped event - */ -const convertToSnakeCase = (eventName) => - eventName.map((str) => - str - .replace(/([a-z])([A-Z])/g, '$1_$2') - .replace(/\s+/g, '_') - .toLowerCase(), - ); - -/** - * - * @param {*} message - * @param {*} Config - * @returns - * For the few ecommerce events the mapping is like following: - * const ecomEventMaps = [ - { - src: ["order completed"], - dest: "checkout", - }, - { - src: ["product added"], - dest: "add_to_cart", - }, - { - src: ["products searched", "product list filtered"], - dest: "search", - }, - ]; - * For others, it depends on mapping from the UI. If any event, other than mapped events are sent, - * will be labled as "custom" events. - */ -const deduceTrackScreenEventName = (message, Config) => { - let eventName; - const { event, name } = message; - const { eventsMapping, sendAsCustomEvent } = Config; - const trackEventOrScreenName = event || name; - if (!trackEventOrScreenName) { - throw new InstrumentationError('event_name could not be mapped. Aborting'); - } - validateEventName(trackEventOrScreenName); - - /* - Step 1: If the event is not amongst the above list of ecommerce events, will look for - the event mapping in the UI. In case it is similar, will map to that. - */ - if (eventsMapping.length > 0) { - const keyMap = getHashFromArrayWithDuplicate(eventsMapping, 'from', 'to', false); - eventName = keyMap[trackEventOrScreenName]; - } - if (isDefined(eventName)) { - return convertToSnakeCase([...eventName]); - } - - /* - Step 2: To find if the particular event is amongst the list of standard - Rudderstack ecommerce events, used specifically for Pinterest Conversion API - mappings. - */ - if (!eventName) { - const eventMapInfo = ecomEventMaps.find((eventMap) => { - if (eventMap.src.includes(trackEventOrScreenName.toLowerCase())) { - return eventMap; - } - return false; - }); - - if (isDefinedAndNotNull(eventMapInfo)) { - return [eventMapInfo.dest]; - } - } - - /* - Step 3: In case both of the above stated cases fail, will check if sendAsCustomEvent toggle is enabled in UI. - If yes, then we will send it as custom event - */ - if (sendAsCustomEvent) { - return ['custom']; - } - - /* - Step 4: In case all of the above stated cases failed, will send the event name as it is. - This is going to be reflected as "unknown" event in conversion API dashboard. - */ - return [trackEventOrScreenName]; -}; - -/** - * - * @param {*} message event.message - * @param {*} Config event.destination.Config - * @returns - * Returns the appropriate event name for each event types - * For identify : "identify". - * For page : "ViewCategory" in case category is present, "PageVisit" otherwise. - * For track : Depends on the event name - */ -const deduceEventName = (message, Config) => { - const { type, category } = message; - let eventName = []; - switch (type) { - case EventType.PAGE: - eventName = isDefinedAndNotNull(category) ? ['view_category'] : ['page_visit']; - break; - case EventType.TRACK: - case EventType.SCREEN: - eventName = deduceTrackScreenEventName(message, Config); - break; - default: - throw new InstrumentationError(`The event of type ${type} is not supported`); - } - return eventName; -}; - -/** - * - * @param {*} rootObject object from where the price, quantity and ids will be fetched - * @param {*} message event.message - * @returns - * Object containing the deduced parameters - */ -const setIdPriceQuantity = (rootObject, message) => { - const contentObj = { - // we are yet to check how the destination behaves if one of quantity and item_price is missing - quantity: parseInt(rootObject.quantity || message.properties.quantity || 1, 10), - item_price: String(rootObject.price || message.properties.price), - }; - return { - contentId: rootObject.product_id || rootObject.sku || rootObject.id, - content: contentObj, - }; -}; - -/** - * @param {*} userPayload Payload mapped from user fields - * @returns returns true if at least one of: em, hashed_maids or combination of client_ip_address and - * client_user_agent is present. And false otherwise. - */ -const checkUserPayloadValidity = (userPayload) => { - const userFields = Object.keys(userPayload); - if (userFields.includes('em') || userFields.includes('hashed_maids')) { - return true; - } - return userFields.includes('client_ip_address') && userFields.includes('client_user_agent'); -}; - -/** - * - * @param {*} userPayload - * @param {*} message - * @returns converts every single hashed user data property to array, except for - * "client_user_agent", "client_ip_address" - * - */ -const processHashedUserPayload = (userPayload, message) => { - const processedHashedUserPayload = {}; - Object.keys(userPayload).forEach((key) => { - if (!USER_NON_ARRAY_PROPERTIES.includes(key)) { - if (Array.isArray(userPayload[key])) { - processedHashedUserPayload[key] = [...userPayload[key]]; - } else { - processedHashedUserPayload[key] = [userPayload[key]]; - } - } else { - processedHashedUserPayload[key] = userPayload[key]; - } - }); - // multiKeyMap will works on only specific values like m, male, MALE, f, F, Female - // if hashed data is sent from the user, it is directly set over here - const gender = message.traits?.gender || message.context?.traits?.gender; - if (gender && Array.isArray(gender)) { - processedHashedUserPayload.ge = [...gender]; - } else if (gender) { - processedHashedUserPayload.ge = [gender]; - } - return processedHashedUserPayload; -}; - -/** - * This function will process the ecommerce fields and return the final payload - * @param {*} message - * @param {*} mandatoryPayload - * @returns - */ -const postProcessEcomFields = (message, mandatoryPayload) => { - let totalQuantity = 0; - let quantityInconsistent = false; - const contentArray = []; - const contentIds = []; - const { properties } = message; - // ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html - let customPayload = constructPayload(message, CUSTOM_CONFIGS); - - // if product array is present will look for the product level information - if (properties.products && Array.isArray(properties.products) && properties.products.length > 0) { - const { products, quantity } = properties; - products.forEach((product) => { - const prodParams = setIdPriceQuantity(product, message); - if (prodParams.contentId) { - contentIds.push(prodParams.contentId); - } - contentArray.push(prodParams.content); - if (!product.quantity) { - quantityInconsistent = true; - } - totalQuantity = product.quantity ? totalQuantity + product.quantity : totalQuantity; - }); - - if (totalQuantity === 0) { - /* - in case any of the products inside product array does not have quantity, - will map the quantity of root level - */ - totalQuantity = quantity; - } - } else { - /* - for the events where product array is not present, root level id, price and - quantity are taken into consideration - */ - const prodParams = setIdPriceQuantity(properties, message); - if (prodParams.contentId) { - contentIds.push(prodParams.contentId); - } - contentArray.push(prodParams.content); - totalQuantity = properties.quantity ? totalQuantity + properties.quantity : totalQuantity; - } - /* - if properties.numOfItems is not provided by the user, the total quantity of the products - will be sent as num_items - */ - if (!isDefinedAndNotNull(customPayload.num_items) && quantityInconsistent === false) { - customPayload.num_items = parseInt(totalQuantity, 10); - } - customPayload = { - ...customPayload, - contents: contentArray, - }; - - if (contentIds.length > 0) { - customPayload.content_ids = contentIds; - } - - return { - ...mandatoryPayload, - custom_data: { ...removeUndefinedAndNullValues(customPayload) }, - }; -}; - -const validateInput = (message, { Config }) => { - const { apiVersion = API_VERSION.v3, advertiserId, adAccountId, conversionToken } = Config; - if (apiVersion === API_VERSION.v3 && !advertiserId) { - throw new ConfigurationError('Advertiser Id not found. Aborting'); - } - - if (apiVersion === API_VERSION.v5) { - if (!adAccountId) { - throw new ConfigurationError('Ad Account ID not found. Aborting'); - } - - if (!conversionToken) { - throw new ConfigurationError('Conversion Token not found. Aborting'); - } - } - - if (!message.type) { - throw new InstrumentationError('Event type is required'); - } -}; - -module.exports = { - processUserPayload, - processCommonPayload, - deduceEventName, - setIdPriceQuantity, - checkUserPayloadValidity, - processHashedUserPayload, - VALID_ACTION_SOURCES, - postProcessEcomFields, - ecomEventMaps, - convertToSnakeCase, - validateInput, -}; diff --git a/test/__tests__/data/pinterest_tag_input.json b/test/__tests__/data/pinterest_tag_input.json index f0755ddb383..15e378caf6f 100644 --- a/test/__tests__/data/pinterest_tag_input.json +++ b/test/__tests__/data/pinterest_tag_input.json @@ -47,6 +47,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -57,6 +58,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -153,6 +155,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -163,6 +166,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -554,6 +558,7 @@ "numOfItems": 2, "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -564,6 +569,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -981,6 +987,7 @@ "numOfItems": 2, "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -991,6 +998,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -1773,6 +1781,7 @@ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -1954,6 +1963,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -1964,6 +1974,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -2065,6 +2076,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -2075,6 +2087,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -2176,6 +2189,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -2186,6 +2200,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, diff --git a/test/__tests__/data/pinterest_tag_output.json b/test/__tests__/data/pinterest_tag_output.json index 9fb809d112d..dccdb248c99 100644 --- a/test/__tests__/data/pinterest_tag_output.json +++ b/test/__tests__/data/pinterest_tag_output.json @@ -41,10 +41,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -58,6 +66,7 @@ "files": {} } ], + [ { "version": "1", @@ -96,10 +105,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -210,10 +227,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -277,10 +302,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -649,6 +682,10 @@ "content_ids": ["507f1f77bcf86cd799439011"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" } @@ -752,10 +789,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -808,10 +853,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -888,10 +941,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } diff --git a/test/__tests__/data/pinterest_tag_router_batch_output.json b/test/__tests__/data/pinterest_tag_router_batch_output.json index 995d68428a4..0eb8f0532ae 100644 --- a/test/__tests__/data/pinterest_tag_router_batch_output.json +++ b/test/__tests__/data/pinterest_tag_router_batch_output.json @@ -43,10 +43,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -83,10 +91,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -122,10 +138,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -272,10 +296,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -311,10 +343,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -572,12 +612,20 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { - "item_price": "19", - "quantity": 1 + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", + "quantity": 1, + "item_price": "19" }, { - "item_price": "3", - "quantity": 2 + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", + "quantity": 2, + "item_price": "3" } ], "currency": "USD", @@ -611,12 +659,20 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { - "item_price": "19", - "quantity": 1 + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", + "quantity": 1, + "item_price": "19" }, { - "item_price": "3", - "quantity": 2 + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", + "quantity": 2, + "item_price": "3" } ], "currency": "USD", @@ -650,12 +706,20 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { - "item_price": "19", - "quantity": 1 + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", + "quantity": 1, + "item_price": "19" }, { - "item_price": "3", - "quantity": 2 + "item_brand": "testBrand", + "id": "505bd76785ebb509fc183733", + "item_category": "Games", + "item_name": "Uno Card Game", + "quantity": 2, + "item_price": "3" } ], "currency": "USD", @@ -767,12 +831,20 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { - "item_price": "19", - "quantity": 1 + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", + "quantity": 1, + "item_price": "19" }, { - "item_price": "3", - "quantity": 2 + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", + "quantity": 2, + "item_price": "3" } ], "currency": "USD", diff --git a/test/__tests__/data/pinterest_tag_router_input.json b/test/__tests__/data/pinterest_tag_router_input.json index 26febec456a..c1639382d72 100644 --- a/test/__tests__/data/pinterest_tag_router_input.json +++ b/test/__tests__/data/pinterest_tag_router_input.json @@ -48,6 +48,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -58,6 +59,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -170,6 +172,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -180,6 +183,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -395,6 +399,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -405,6 +410,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -517,6 +523,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -527,6 +534,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -639,6 +647,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -649,6 +658,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -866,6 +876,7 @@ "optOutType": "LDP", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -876,6 +887,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -990,6 +1002,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -1000,6 +1013,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, @@ -1114,6 +1128,7 @@ "requestIP": "123.0.0.0", "products": [ { + "brand": "testBrand", "sku": "45790-32", "url": "https://www.example.com/product/path", "name": "Monopoly: 3rd Edition", @@ -1124,6 +1139,7 @@ "product_id": "507f1f77bcf86cd799439011" }, { + "brand": "testBrand", "sku": "46493-32", "name": "Uno Card Game", "price": 3, diff --git a/test/__tests__/data/pinterest_tag_router_output.json b/test/__tests__/data/pinterest_tag_router_output.json index 2bfc7c3cf57..a54d3289786 100644 --- a/test/__tests__/data/pinterest_tag_router_output.json +++ b/test/__tests__/data/pinterest_tag_router_output.json @@ -43,10 +43,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -83,10 +91,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -122,10 +138,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -196,10 +220,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -235,10 +267,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -465,10 +505,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -504,10 +552,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -542,10 +598,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } @@ -580,10 +644,18 @@ "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], "contents": [ { + "id": "507f1f77bcf86cd799439011", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Monopoly: 3rd Edition", "quantity": 1, "item_price": "19" }, { + "id": "505bd76785ebb509fc183733", + "item_brand": "testBrand", + "item_category": "Games", + "item_name": "Uno Card Game", "quantity": 2, "item_price": "3" } diff --git a/test/__tests__/pinterestConversion.test.js b/test/__tests__/pinterestConversion.test.js deleted file mode 100644 index 4c145f0383b..00000000000 --- a/test/__tests__/pinterestConversion.test.js +++ /dev/null @@ -1,54 +0,0 @@ -const integration = "pinterest_tag"; -const name = "Pinterest Conversion API"; - -const fs = require("fs"); -const path = require("path"); - -const version = "v0"; - -const transformer = require(`../../src/${version}/destinations/${integration}/transform`); -const { assertRouterOutput } = require('../testHelper'); - -const inputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_input.json`) -); -const outputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_output.json`) -); -const inputData = JSON.parse(inputDataFile); -const expectedData = JSON.parse(outputDataFile); - -// Router Test Data -const inputRouterDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_input.json`) -); -const outputRouterDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_output.json`) -); -const inputRouterData = JSON.parse(inputRouterDataFile); -const expectedRouterData = JSON.parse(outputRouterDataFile); - -describe(`${name} Tests`, () => { - describe("Processor Tests", () => { - inputData.forEach((input, index) => { - it(`${name} - payload: ${index}`, async () => { - try { - const output = await transformer.process(input); - expect(output).toEqual(expectedData[index]); - } catch (error) { - expect(error.message).toEqual(expectedData[index].error); - } - }); - }); - }); - - describe("Router Tests", () => { - inputRouterData.forEach((input, index) => { - it(`Payload: ${index}`, async () => { - let output = await transformer.processRouterDest(input); - assertRouterOutput(output, input); - expect(output).toEqual(expectedRouterData[index]); - }); - }); - }); -}); diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 7dd8984f282..3ce7c150918 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -78,6 +78,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -254,6 +255,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json index dc9919fb1a5..68c7fc3baa9 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json @@ -77,6 +77,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -206,13 +207,13 @@ "destinationDefinitionId": "" }, "statusCode": 400, - "error": "Missing required value from [\"traits.action_source\",\"context.traits.action_source\",\"traits.actionSource\",\"context.traits.actionSource\",\"properties.action_source\",\"properties.actionSource\",\"channel\"]", + "error": "action_source is required: Workflow: procWorkflow, Step: validateCommonFields, ChildStep: undefined, OriginalError: action_source is required", "statTags": { "errorCategory": "dataValidation", "errorType": "instrumentation", "destType": "PINTEREST_TAG", "module": "destination", - "implementation": "native", + "implementation": "cdkV2", "feature": "processor", "destinationId": "2JIqVoWNvSOHa9ppKOqSo4hPuc0", "workspaceId": "27O0bhB6p5ehfOWeeZlOSsSDTLg" diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index 63194f1b87a..0e467c26d0b 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -78,6 +78,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -254,6 +255,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -543,13 +545,13 @@ "destinationDefinitionId": "" }, "statusCode": 400, - "error": "Action source must be one of app_android, app_ios, web, offline", + "error": "Action source must be one of app_android, app_ios, web, offline: Workflow: procWorkflow, Step: validateCommonFields, ChildStep: undefined, OriginalError: Action source must be one of app_android, app_ios, web, offline", "statTags": { "errorCategory": "dataValidation", "errorType": "instrumentation", "destType": "PINTEREST_TAG", "module": "destination", - "implementation": "native", + "implementation": "cdkV2", "feature": "processor", "destinationId": "2JIqVoWNvSOHa9ppKOqSo4hPuc0", "workspaceId": "27O0bhB6p5ehfOWeeZlOSsSDTLg" diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index bf1b1aae81c..66b6c870a9e 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -78,6 +78,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 96c5cff54fe..9e36da50cb8 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -141,6 +141,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -378,6 +379,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -615,6 +617,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -991,6 +994,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", @@ -1192,7 +1196,7 @@ "errorType": "instrumentation", "destType": "PINTEREST_TAG", "module": "destination", - "implementation": "native", + "implementation": "cdkV2", "feature": "router", "destinationId": "2JIqVoWNvSOHa9ppKOqSo4hPuc0", "workspaceId": "27O0bhB6p5ehfOWeeZlOSsSDTLg" @@ -1206,6 +1210,7 @@ "DisplayName": "Pinterest Tag", "Config": { "cdkV2TestThreshold": 1, + "cdkV2Enabled": true, "destConfig": { "defaultConfig": [ "tagId", diff --git a/test/apitests/service.api.test.ts b/test/apitests/service.api.test.ts index 30d2c568a6e..2a0db6978e0 100644 --- a/test/apitests/service.api.test.ts +++ b/test/apitests/service.api.test.ts @@ -449,7 +449,6 @@ describe('Destination api tests', () => { expect(response.status).toEqual(200); expect(JSON.parse(response.text)).toEqual(data.output); }); - test('(webhook) success snceario for batch of input', async () => { const data = getDataFromPath('./data_scenarios/destination/proc/batch_input.json'); const response = await request(server) diff --git a/test/integrations/destinations/pinterest_tag/processor/data.ts b/test/integrations/destinations/pinterest_tag/processor/data.ts index 48b624645f9..b856d247d71 100644 --- a/test/integrations/destinations/pinterest_tag/processor/data.ts +++ b/test/integrations/destinations/pinterest_tag/processor/data.ts @@ -26,13 +26,21 @@ export const data = [ lastname: 'Rudderlabs', firstName: 'Test', address: { city: 'Kolkata', state: 'WB', zip: '700114', country: 'IN' }, + partnerId: '12345678', }, device: { advertisingId: 'abc123' }, library: { name: 'rudder-sdk-ruby-sync', version: '1.0.6' }, + network: { + carrier: 'VI', + wifi: true, + }, }, messageId: '7208bbb6-2c4e-45bb-bf5b-ad426f3593e9', timestamp: '2020-08-14T05:30:30.118Z', properties: { + contentBrand: 'LV', + partnerName: 'testPartner', + contentName: 'testContent', tax: 2, total: 27.5, coupon: 'hasbros', @@ -106,55 +114,77 @@ export const data = [ { metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://ct.pinterest.com/events/v3', - headers: { 'Content-Type': 'application/json' }, - params: { test: true }, body: { + FORM: {}, JSON: { action_source: 'web', + advertiser_id: '429047995', + app_id: '429047995', + custom_data: { + content_brand: 'LV', + content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], + content_name: 'testContent', + contents: [ + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + item_price: '19', + quantity: 1, + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + item_price: '3', + quantity: 2, + }, + ], + currency: 'USD', + num_items: 3, + opt_out_type: 'LDP', + order_id: '50314b8e9bcf000000000000', + value: '27.5', + }, + device_carrier: 'VI', + event_id: '7208bbb6-2c4e-45bb-bf5b-ad426f3593e9', event_name: 'watch_video', event_time: 1597383030, - event_id: '7208bbb6-2c4e-45bb-bf5b-ad426f3593e9', - app_id: '429047995', - advertiser_id: '429047995', + partner_name: 'testPartner', user_data: { + click_id: 'dummy_clickId', + client_user_agent: 'chrome', + country: ['582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf'], + ct: ['6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85'], em: ['48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08'], - ph: ['d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b'], - ln: ['dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251'], fn: ['9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'], - ct: ['6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85'], - st: ['3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd'], - zp: ['1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c'], - country: ['582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf'], + ge: ['1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9'], hashed_maids: [ '6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090', ], - client_user_agent: 'chrome', - click_id: 'dummy_clickId', - ge: ['1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9'], - }, - custom_data: { - currency: 'USD', - value: '27.5', - order_id: '50314b8e9bcf000000000000', - opt_out_type: 'LDP', - num_items: 3, - content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], - contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, - ], + ln: ['dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251'], + partner_id: '12345678', + ph: ['d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b'], + st: ['3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd'], + zp: ['1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c'], }, + wifi: true, }, JSON_ARRAY: {}, XML: {}, - FORM: {}, }, + endpoint: 'https://ct.pinterest.com/events/v3', files: {}, + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + params: { + test: true, + }, + type: 'REST', userId: '', + version: '1', }, statusCode: 200, }, @@ -302,8 +332,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -835,8 +877,20 @@ export const data = [ order_id: '50314b8e9bcf000000000000', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1357,8 +1411,20 @@ export const data = [ order_id: '50314b8e9bcf000000000000', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -2486,7 +2552,15 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 1, content_ids: ['507f1f77bcf86cd799439011'], - contents: [{ quantity: 1, item_price: '19' }], + contents: [ + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + ], }, }, JSON_ARRAY: {}, @@ -2785,8 +2859,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -2951,8 +3037,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -2980,7 +3078,7 @@ export const data = [ body: [ { description: - 'Custom event with v5 Api version, with unhashed User Data and the values are an array of strings', + 'Custom event with v5 Api version, with unhashed User Data and the values are an of strings', message: { type: 'track', event: 'random', @@ -3147,8 +3245,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, diff --git a/test/integrations/destinations/pinterest_tag/router/data.ts b/test/integrations/destinations/pinterest_tag/router/data.ts index c02b1781e32..c9ab29a45a9 100644 --- a/test/integrations/destinations/pinterest_tag/router/data.ts +++ b/test/integrations/destinations/pinterest_tag/router/data.ts @@ -674,8 +674,20 @@ export const data = [ opt_out_type: 'LDP', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -710,8 +722,20 @@ export const data = [ opt_out_type: 'LDP', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -745,8 +769,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -812,8 +848,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -847,8 +895,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -981,7 +1041,7 @@ export const data = [ }, { destType: 'pinterest_tag', - description: 'Test 0', + description: 'Test 1', feature: 'router', module: 'destination', version: 'v0', @@ -1328,8 +1388,20 @@ export const data = [ opt_out_type: 'LDP', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1363,8 +1435,20 @@ export const data = [ opt_out_type: 'LDP', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1397,8 +1481,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1431,8 +1527,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1488,7 +1596,7 @@ export const data = [ }, { destType: 'pinterest_tag', - description: 'Test 0', + description: 'Test 2', feature: 'router', module: 'destination', version: 'v0', diff --git a/test/integrations/destinations/pinterest_tag/step/data.ts b/test/integrations/destinations/pinterest_tag/step/data.ts index cbd0b243bbf..b607e3c9faf 100644 --- a/test/integrations/destinations/pinterest_tag/step/data.ts +++ b/test/integrations/destinations/pinterest_tag/step/data.ts @@ -75,6 +75,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -90,6 +91,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -101,6 +103,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -139,8 +144,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -232,6 +249,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -247,6 +265,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -258,6 +277,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -294,8 +316,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -368,6 +402,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -383,6 +418,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -394,6 +430,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -519,6 +558,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -534,6 +574,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -545,13 +586,17 @@ export const data = [ status: 200, body: [ { - error: 'Advertiser Id not found. Aborting', + error: + 'Advertiser Id not found. Aborting: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: Advertiser Id not found. Aborting', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'configuration', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -633,6 +678,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -648,6 +694,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -660,13 +707,16 @@ export const data = [ body: [ { error: - 'It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent', + 'It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent: Workflow: procWorkflow, Step: validateUserFields, ChildStep: undefined, OriginalError: It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'instrumentation', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -751,6 +801,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -766,6 +817,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -777,6 +829,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -813,8 +868,20 @@ export const data = [ order_id: '50314b8e9bcf000000000000', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -907,6 +974,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -922,6 +990,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -933,13 +1002,17 @@ export const data = [ status: 200, body: [ { - error: 'Advertiser Id not found. Aborting', + error: + 'Advertiser Id not found. Aborting: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: Advertiser Id not found. Aborting', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'configuration', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -1023,6 +1096,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1038,6 +1112,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1049,13 +1124,17 @@ export const data = [ status: 200, body: [ { - error: 'message type group is not supported', + error: + 'message type group is not supported: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: message type group is not supported', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'instrumentation', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -1140,6 +1219,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1155,6 +1235,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1166,13 +1247,17 @@ export const data = [ status: 200, body: [ { - error: 'Action source must be one of app_android, app_ios, web, offline', + error: + 'Action source must be one of app_android, app_ios, web, offline: Workflow: procWorkflow, Step: validateCommonFields, ChildStep: undefined, OriginalError: Action source must be one of app_android, app_ios, web, offline', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'instrumentation', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -1257,6 +1342,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1273,6 +1359,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1284,6 +1371,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1320,8 +1410,20 @@ export const data = [ order_id: '50314b8e9bcf000000000000', content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -1378,6 +1480,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1393,6 +1496,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1404,6 +1508,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1488,6 +1595,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1503,6 +1611,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1514,6 +1623,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1598,6 +1710,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1613,6 +1726,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1624,6 +1738,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1709,6 +1826,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1724,6 +1842,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1735,6 +1854,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1821,6 +1943,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1834,6 +1957,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1845,6 +1969,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -1933,6 +2060,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -1946,6 +2074,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -1957,6 +2086,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -2096,6 +2228,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2114,6 +2247,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2125,6 +2259,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { body: { JSON: { @@ -2216,6 +2353,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2232,6 +2370,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2243,6 +2382,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -2360,6 +2502,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2376,6 +2519,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2387,6 +2531,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -2422,7 +2569,15 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 1, content_ids: ['507f1f77bcf86cd799439011'], - contents: [{ quantity: 1, item_price: '19' }], + contents: [ + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + ], }, }, JSON_ARRAY: {}, @@ -2491,6 +2646,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2506,6 +2662,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2517,6 +2674,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { body: { FORM: {}, @@ -2644,6 +2804,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2662,6 +2823,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2673,6 +2835,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -2715,8 +2880,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -2810,6 +2987,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2828,6 +3006,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -2839,6 +3018,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -2878,8 +3060,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -2979,6 +3173,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -2997,6 +3192,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -3008,6 +3204,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', @@ -3071,8 +3270,20 @@ export const data = [ num_items: 3, content_ids: ['507f1f77bcf86cd799439011', '505bd76785ebb509fc183733'], contents: [ - { quantity: 1, item_price: '19' }, - { quantity: 2, item_price: '3' }, + { + id: '507f1f77bcf86cd799439011', + item_category: 'Games', + item_name: 'Monopoly: 3rd Edition', + quantity: 1, + item_price: '19', + }, + { + id: '505bd76785ebb509fc183733', + item_category: 'Games', + item_name: 'Uno Card Game', + quantity: 2, + item_price: '3', + }, ], }, }, @@ -3129,6 +3340,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -3147,6 +3359,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -3158,13 +3371,17 @@ export const data = [ status: 200, body: [ { - error: 'Ad Account ID not found. Aborting', + error: + 'Ad Account ID not found. Aborting: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: Ad Account ID not found. Aborting', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'configuration', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -3213,6 +3430,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -3231,6 +3449,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -3242,13 +3461,17 @@ export const data = [ status: 200, body: [ { - error: 'Conversion Token not found. Aborting', + error: + 'Conversion Token not found. Aborting: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: Conversion Token not found. Aborting', + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, statTags: { destType: 'PINTEREST_TAG', errorCategory: 'dataValidation', errorType: 'configuration', feature: 'processor', - implementation: 'native', + implementation: 'cdkV2', module: 'destination', }, statusCode: 400, @@ -3310,6 +3533,7 @@ export const data = [ destination: { ID: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', Name: 'PINTEREST_TAG', + DestinationDefinition: { Config: { cdkV2Enabled: true } }, Config: { sendAsTestEvent: false, tagId: '123456789', @@ -3328,6 +3552,7 @@ export const data = [ Enabled: true, Transformations: [], }, + metadata: { destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq' }, }, ], method: 'POST', @@ -3339,6 +3564,9 @@ export const data = [ status: 200, body: [ { + metadata: { + destintionId: '1pYpzzvcn7AQ2W9GGIAZSsN6Mfq', + }, output: { version: '1', type: 'REST', From dc6d78fc5870ba31e6f3fa557ab31a3f073b72ca Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Fri, 18 Oct 2024 15:03:39 +0530 Subject: [PATCH 059/147] chore: cleanup pinterest tag old tests (#3815) Co-authored-by: Sai Sankeerth --- test/__tests__/data/pinterest_tag_input.json | 2491 ----------------- test/__tests__/data/pinterest_tag_output.json | 1027 ------- .../pinterest_tag_router_batch_output.json | 943 ------- .../pinterest_tag_router_error_input.json | 124 - .../pinterest_tag_router_error_output.json | 59 - .../data/pinterest_tag_router_input.json | 1212 -------- .../data/pinterest_tag_router_output.json | 735 ----- .../data/pinterest_tag_step_input.json | 2476 ---------------- .../data/pinterest_tag_step_output.json | 911 ------ .../__tests__/pinterestConversion-cdk.test.ts | 135 - 10 files changed, 10113 deletions(-) delete mode 100644 test/__tests__/data/pinterest_tag_input.json delete mode 100644 test/__tests__/data/pinterest_tag_output.json delete mode 100644 test/__tests__/data/pinterest_tag_router_batch_output.json delete mode 100644 test/__tests__/data/pinterest_tag_router_error_input.json delete mode 100644 test/__tests__/data/pinterest_tag_router_error_output.json delete mode 100644 test/__tests__/data/pinterest_tag_router_input.json delete mode 100644 test/__tests__/data/pinterest_tag_router_output.json delete mode 100644 test/__tests__/data/pinterest_tag_step_input.json delete mode 100644 test/__tests__/data/pinterest_tag_step_output.json delete mode 100644 test/__tests__/pinterestConversion-cdk.test.ts diff --git a/test/__tests__/data/pinterest_tag_input.json b/test/__tests__/data/pinterest_tag_input.json deleted file mode 100644 index 15e378caf6f..00000000000 --- a/test/__tests__/data/pinterest_tag_input.json +++ /dev/null @@ -1,2491 +0,0 @@ -[ - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "gender": "non-binary", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsTestEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Order completed", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "product added", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "product_id": "123", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Product List Filtered", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Product List Filtered", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "group", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "enhancedMatch": true, - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "channel": "abc", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123", - "adTrackingEnabled": true - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "ip": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "adTrackingEnabled": false - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "requestIP": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "Hashed phone", - "gender": "Hashed Gender", - "dob": "Hashed DB", - "lastname": "Hashed Lastname", - "firstName": "Hashed FirstName", - "address": { - "city": "Hashed City", - "state": "Hashed State", - "zip": "Hashed Zip", - "country": "Hashed country" - } - }, - "device": { - "adTrackingEnabled": false, - "advertisingId": "Hashed maids" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": false, - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "requestIP": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": ["Hashed phone", "Hashed phone1"], - "gender": ["Hashed Gender", "Hashed Gender1"], - "dob": ["Hashed DB", "Hashed DB1"], - "lastname": ["Hashed Lastname", "Hashed Lastname1"], - "firstName": ["Hashed FirstName", "Hashed FirstName1"], - "address": { - "city": ["Hashed City", "Hashed City1"], - "state": ["Hashed State", "Hashed State1"], - "zip": ["Hashed Zip", "Hashed Zip1"], - "country": ["Hashed country", "Hashed country1"] - } - }, - "device": { - "adTrackingEnabled": false, - "advertisingId": "Hashed maids" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": false, - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "name": "Test Tool", - "type": "page", - "sentAt": "2023-02-01T00:00:00.379Z", - "userId": "", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "version": "2.22.3", - "namespace": "com.rudderlabs.javascript" - }, - "page": { - "url": "https://www.abc.com/s598907", - "path": "/test-path/s598907", - "title": "Test Tool + Reviews | Rudderstack", - "search": "", - "tab_url": "https://www.abc.com/s598907", - "referrer": "$direct", - "initial_referrer": "$direct", - "referring_domain": "", - "initial_referring_domain": "" - }, - "locale": "en-US", - "screen": { - "width": 1024, - "height": 1024, - "density": 1, - "innerWidth": 1024, - "innerHeight": 1024 - }, - "traits": {}, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "2.22.3" - }, - "campaign": {}, - "doNotSell": false, - "sessionId": 1675209600203, - "userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/109.0.5414.101 Safari/537.36", - "gaClientId": { - "integrations": { - "Google Ads": { - "gclid": "" - }, - "Google Analytics": { - "clientId": "1518934611.1234569600" - } - } - }, - "sessionStart": true - }, - "rudderId": "7291a10f-e7dd-49f9-94ce-0154f53897y6", - "messageId": "1c77a616-13a7-4a2e-a8e7-e1a0971897y6", - "timestamp": "2023-02-01T12:47:30.030Z", - "properties": { - "sku": "45790-32", - "url": "https://www.abc.com/23rty", - "name": "Test Tool", - "path": "/test-path/tool", - "email": "", - "title": "Test Tool + Reviews | Rudderstack", - "review": { - "reviewCount": 2, - "averageReview": 5, - "reviewContentID": ["238300132"] - }, - "search": "", - "tab_url": "https://www.abc/com", - "pageInfo": { - "pageId": "s592897", - "category": { - "pageType": "product", - "subCategory": "Dining & Kitchen Furniture", - "pageTemplate": "product detail grouper", - "primaryCategory": "Furniture" - }, - "brandType": "new brand" - }, - "referrer": "", - "subCategory": "Dining & Kitchen Furniture", - "primaryCategory": "Furniture", - "initial_referrer": "$direct", - "referring_domain": "", - "initial_referring_domain": "" - }, - "receivedAt": "2023-02-01T12:47:30.038Z", - "request_ip": "66.249.72.218", - "anonymousId": "a61c77a6-1613-474a-aee8-e7e1a0971047", - "integrations": { - "All": true - }, - "originalTimestamp": "2023-02-01T00:00:00.371Z" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123478671210", - "sendingUnHashedData": false, - "enableDeduplication": false, - "eventsMapping": [ - { - "from": "Product Added", - "to": "AddToCart" - }, - { - "from": "Order Completed", - "to": "Checkout" - }, - { - "from": "Product Viewed", - "to": "PageVisit" - }, - { - "from": "Lead", - "to": "Lead" - }, - { - "from": "Signup", - "to": "Signup" - } - ], - "enhancedMatch": true - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "test", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "sku": "1234", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "sku": "1234", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - } - ] - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Track call with v5 Api version and send external_id toggle enabled", - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendExternalId": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Custom event with v5 Api version", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Custom event with v5 Api version, with unhashed User Data and the values are an array of strings", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": ["abc@gmail.com", "def@gmail.com"], - "phone": ["+1234589947", "+1234589948"], - "ge": ["male", "male"], - "db": ["19950715", "19970615"], - "lastname": ["Rudderlabs", "Xu"], - "firstName": ["Test", "Alex"], - "address": { - "city": ["Kolkata", "Mumbai"], - "state": ["WB", "MH"], - "zip": ["700114", "700115"], - "country": ["IN", "IN"] - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Ad Account Id check in V5", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Conversion Token check in V5", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": false, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } -] diff --git a/test/__tests__/data/pinterest_tag_output.json b/test/__tests__/data/pinterest_tag_output.json deleted file mode 100644 index dccdb248c99..00000000000 --- a/test/__tests__/data/pinterest_tag_output.json +++ /dev/null @@ -1,1027 +0,0 @@ -[ - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": { - "test": true - }, - "body": { - "JSON": { - "action_source": "web", - "event_name": "watch_video", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome", - "ge": ["1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9"] - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "checkout", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "add_to_cart", - "action_source": "web", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 2, - "content_ids": ["123"], - "contents": [ - { - "quantity": 2, - "item_price": "25" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Advertiser Id not found. Aborting" - }, - { - "statusCode": 400, - "error": "It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent" - }, - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "watch_video", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "num_items": 2, - "order_id": "50314b8e9bcf000000000000", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Advertiser Id not found. Aborting" - }, - { - "statusCode": 400, - "error": "message type group is not supported" - }, - { - "statusCode": 400, - "error": "Action source must be one of app_android, app_ios, web, offline" - }, - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "action_source": "web", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "num_items": 2, - "order_id": "50314b8e9bcf000000000000", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "page_visit", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "opt_out": false, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "opt_out": true, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "client_ip_address": "127.0.0.0", - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "action_source": "web", - "opt_out": true, - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "user_data": { - "ph": ["Hashed phone"], - "db": ["Hashed DB"], - "ln": ["Hashed Lastname"], - "fn": ["Hashed FirstName"], - "ct": ["Hashed City"], - "st": ["Hashed State"], - "zp": ["Hashed Zip"], - "country": ["Hashed country"], - "hashed_maids": ["Hashed maids"], - "ge": ["Hashed Gender"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "action_source": "web", - "opt_out": true, - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "user_data": { - "ph": ["Hashed phone", "Hashed phone1"], - "db": ["Hashed DB", "Hashed DB1"], - "ln": ["Hashed Lastname", "Hashed Lastname1"], - "fn": ["Hashed FirstName", "Hashed FirstName1"], - "ct": ["Hashed City", "Hashed City1"], - "st": ["Hashed State", "Hashed State1"], - "zp": ["Hashed Zip", "Hashed Zip1"], - "country": ["Hashed country", "Hashed country1"], - "hashed_maids": ["Hashed maids"], - "ge": ["Hashed Gender", "Hashed Gender1"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "body": { - "JSON": { - "event_time": 1675255650, - "event_source_url": "https://www.abc.com/s598907", - "action_source": "web", - "app_name": "RudderLabs JavaScript SDK", - "app_version": "2.22.3", - "language": "en-US", - "event_id": "1c77a616-13a7-4a2e-a8e7-e1a0971897y6", - "advertiser_id": "123478671210", - "user_data": { - "client_ip_address": "66.249.72.218", - "client_user_agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/109.0.5414.101 Safari/537.36" - }, - "event_name": "page_visit" - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 0, - "content_ids": ["1234"], - "contents": [ - { - "quantity": 1, - "item_price": "undefined" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 1, - "content_ids": ["507f1f77bcf86cd799439011"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "body": { - "FORM": {}, - "JSON": { - "action_source": "web", - "advertiser_id": "123456", - "app_id": "429047995", - "custom_data": { - "contents": [ - { - "item_price": "undefined", - "quantity": 1 - } - ], - "currency": "USD", - "num_items": 0, - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "custom event", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - }, - "JSON_ARRAY": {}, - "XML": {} - }, - "endpoint": "https://ct.pinterest.com/events/v3", - "files": {}, - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "params": {}, - "type": "REST", - "version": "1" - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "watch_video", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome", - "external_id": ["3217d71a74c219d6e31e28267b313a7ceb6a2c032db1a091c9416b25b2ae2bc8"] - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": [ - "48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08", - "c392e50ebeca7bea4405e9c545023451ac56620031f81263f681269bde14218b" - ], - "ph": [ - "d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b", - "22bdde2594851294f2a6f4c34af704e68b398b03129ea9ceb58f0ffe33f6db52" - ], - "ln": [ - "dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251", - "9c2f138690fca4890c3c4a6691610fbbbdf32091cc001f7355cfdf574baa52b9" - ], - "fn": [ - "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", - "4135aa9dc1b842a653dea846903ddb95bfb8c5a10c504a7fa16e10bc31d1fdf0" - ], - "ct": [ - "6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85", - "d209bcc17778fd19fd2bc0c99a3868bf011da5162d3a75037a605768ebc276e2" - ], - "st": [ - "3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd", - "1b0316ed1cfed044035c55363e02ccafab26d66b1c2746b94d17285f043324aa" - ], - "zp": [ - "1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c", - "4d6755aa1e85517191f06cc91448696c173e1195ae51f94a1670116ac7b5c47b" - ], - "country": [ - "582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf", - "582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf" - ], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Ad Account ID not found. Aborting" - }, - { - "statusCode": 400, - "error": "Conversion Token not found. Aborting" - }, - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom event", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 0, - "contents": [ - { - "quantity": 1, - "item_price": "undefined" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ] -] diff --git a/test/__tests__/data/pinterest_tag_router_batch_output.json b/test/__tests__/data/pinterest_tag_router_batch_output.json deleted file mode 100644 index 0eb8f0532ae..00000000000 --- a/test/__tests__/data/pinterest_tag_router_batch_output.json +++ /dev/null @@ -1,943 +0,0 @@ -[ - [ - { - "batchedRequest": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "data": [ - { - "event_name": "watch_video", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "signup", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "checkout", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": [ - { - "jobId": 1, - "userId": "u1" - }, - { - "jobId": 2, - "userId": "u1" - } - ], - "batched": true, - "statusCode": 200, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "batchedRequest": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "data": [ - { - "event_name": "add_to_cart", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 2, - "content_ids": ["123"], - "contents": [ - { - "quantity": 2, - "item_price": "25" - } - ] - } - }, - { - "event_name": "search", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "signup", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": [ - { - "jobId": 3, - "userId": "u1" - }, - { - "jobId": 4, - "userId": "u1" - }, - { - "jobId": 6, - "userId": "u1" - } - ], - "batched": true, - "statusCode": 200, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "batchedRequest": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "data": [ - { - "action_source": "web", - "event_name": "WatchVideo", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["bdfdee6414a89d72bfbf5ee90b1f85924467bae1e3980d83c2cd348dc31d5819"], - "fn": ["ee5db3fe0253b651aca3676692e0c59b25909304f5c51d223a02a215d104144b"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": [ - { - "jobId": 7, - "userId": "u1" - } - ], - "batched": true, - "statusCode": 200, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "metadata": [ - { - "jobId": 5, - "userId": "u1" - } - ], - "batched": false, - "statusCode": 400, - "error": "message type identify is not supported", - "statTags": { - "errorCategory": "dataValidation", - "errorType": "instrumentation" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } - ], - [ - { - "batched": true, - "batchedRequest": { - "body": { - "FORM": {}, - "JSON": { - "data": [ - { - "action_source": "web", - "app_id": "429047995", - "custom_data": { - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ], - "currency": "USD", - "num_items": 3, - "opt_out_type": "LDP", - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "watch_video", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - }, - { - "action_source": "web", - "app_id": "429047995", - "custom_data": { - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ], - "currency": "USD", - "num_items": 3, - "opt_out_type": "LDP", - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "signup", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - }, - { - "action_source": "web", - "app_id": "429047995", - "custom_data": { - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "item_brand": "testBrand", - "id": "505bd76785ebb509fc183733", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ], - "currency": "USD", - "num_items": 3, - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "checkout", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {} - }, - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "files": {}, - "headers": { - "Authorization": "Bearer conversionToken123", - "Content-Type": "application/json" - }, - "method": "POST", - "params": {}, - "type": "REST", - "version": "1" - }, - "destination": { - "Config": { - "sendAsTestEvent": false, - "adAccountId": "accountId123", - "apiVersion": "newApi", - "appId": "429047995", - "conversionToken": "conversionToken123", - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "deduplicationKey": "messageId", - "enableDeduplication": true, - "enhancedMatch": true, - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ], - "sendingUnHashedData": true, - "tagId": "123456789" - }, - "Enabled": true, - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Transformations": [] - }, - "metadata": [ - { - "jobId": 8, - "userId": "u1" - }, - { - "jobId": 9, - "userId": "u1" - } - ], - "statusCode": 200 - }, - { - "batched": true, - "batchedRequest": { - "body": { - "FORM": {}, - "JSON": { - "data": [ - { - "action_source": "web", - "app_id": "429047995", - "custom_data": { - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ], - "currency": "USD", - "num_items": 3, - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "custom", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {} - }, - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "files": {}, - "headers": { - "Authorization": "Bearer conversionToken123", - "Content-Type": "application/json" - }, - "method": "POST", - "params": {}, - "type": "REST", - "version": "1" - }, - "destination": { - "Config": { - "sendAsTestEvent": false, - "adAccountId": "accountId123", - "apiVersion": "newApi", - "appId": "429047995", - "conversionToken": "conversionToken123", - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "deduplicationKey": "messageId", - "enableDeduplication": true, - "enhancedMatch": true, - "sendAsCustomEvent": true, - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ], - "sendingUnHashedData": true, - "tagId": "123456789" - }, - "Enabled": true, - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Transformations": [] - }, - "metadata": [ - { - "jobId": 10, - "userId": "u1" - } - ], - "statusCode": 200 - } - ] -] diff --git a/test/__tests__/data/pinterest_tag_router_error_input.json b/test/__tests__/data/pinterest_tag_router_error_input.json deleted file mode 100644 index ce188c73355..00000000000 --- a/test/__tests__/data/pinterest_tag_router_error_input.json +++ /dev/null @@ -1,124 +0,0 @@ -[ - { - "message": { - "type": "Identify", - "event": "User Signup", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 5, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "Watch Video" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } -] diff --git a/test/__tests__/data/pinterest_tag_router_error_output.json b/test/__tests__/data/pinterest_tag_router_error_output.json deleted file mode 100644 index 4cd4e6966cd..00000000000 --- a/test/__tests__/data/pinterest_tag_router_error_output.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - { - "metadata": [ - { - "jobId": 5, - "userId": "u1" - } - ], - "batched": false, - "statusCode": 400, - "error": "message type identify is not supported", - "statTags": { - "errorCategory": "dataValidation", - "errorType": "instrumentation" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "Watch Video" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } -] diff --git a/test/__tests__/data/pinterest_tag_router_input.json b/test/__tests__/data/pinterest_tag_router_input.json deleted file mode 100644 index c1639382d72..00000000000 --- a/test/__tests__/data/pinterest_tag_router_input.json +++ /dev/null @@ -1,1212 +0,0 @@ -[ - [ - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 1, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Order completed", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 2, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "product added", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "product_id": "123", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 3, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Product List Filtered", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 4, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "Identify", - "event": "User Signup", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 5, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "User Created", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 6, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "version": "1", - "statusCode": 200, - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "WatchVideo", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["bdfdee6414a89d72bfbf5ee90b1f85924467bae1e3980d83c2cd348dc31d5819"], - "fn": ["ee5db3fe0253b651aca3676692e0c59b25909304f5c51d223a02a215d104144b"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": { - "jobId": 7, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } - ], - [ - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 8, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Order completed", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 9, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Test", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "brand": "testBrand", - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "brand": "testBrand", - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "metadata": { - "jobId": 10, - "userId": "u1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } - ] -] diff --git a/test/__tests__/data/pinterest_tag_router_output.json b/test/__tests__/data/pinterest_tag_router_output.json deleted file mode 100644 index a54d3289786..00000000000 --- a/test/__tests__/data/pinterest_tag_router_output.json +++ /dev/null @@ -1,735 +0,0 @@ -[ - [ - { - "batchedRequest": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "data": [ - { - "event_name": "watch_video", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "signup", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "checkout", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "add_to_cart", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 2, - "content_ids": ["123"], - "contents": [ - { - "quantity": 2, - "item_price": "25" - } - ] - } - }, - { - "event_name": "search", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "signup", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "action_source": "web", - "event_name": "WatchVideo", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["bdfdee6414a89d72bfbf5ee90b1f85924467bae1e3980d83c2cd348dc31d5819"], - "fn": ["ee5db3fe0253b651aca3676692e0c59b25909304f5c51d223a02a215d104144b"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": [ - { - "jobId": 1, - "userId": "u1" - }, - { - "jobId": 2, - "userId": "u1" - }, - { - "jobId": 3, - "userId": "u1" - }, - { - "jobId": 4, - "userId": "u1" - }, - { - "jobId": 6, - "userId": "u1" - }, - { - "jobId": 7, - "userId": "u1" - } - ], - "batched": true, - "statusCode": 200, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "metadata": [ - { - "jobId": 5, - "userId": "u1" - } - ], - "statTags": { - "errorCategory": "dataValidation", - "errorType": "instrumentation" - }, - "batched": false, - "statusCode": 400, - "error": "message type identify is not supported", - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } - ], - [ - { - "batchedRequest": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "data": [ - { - "event_name": "watch_video", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "signup", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "opt_out_type": "LDP", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "checkout", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - }, - { - "event_name": "custom", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": [ - "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090" - ], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "id": "507f1f77bcf86cd799439011", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Monopoly: 3rd Edition", - "quantity": 1, - "item_price": "19" - }, - { - "id": "505bd76785ebb509fc183733", - "item_brand": "testBrand", - "item_category": "Games", - "item_name": "Uno Card Game", - "quantity": 2, - "item_price": "3" - } - ] - } - } - ] - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "metadata": [ - { - "jobId": 8, - "userId": "u1" - }, - { - "jobId": 9, - "userId": "u1" - }, - { - "jobId": 10, - "userId": "u1" - } - ], - "batched": true, - "statusCode": 200, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - }, - { - "from": "ABC Searched", - "to": "Signup" - }, - { - "from": "User Signup", - "to": "Signup" - }, - { - "from": "User Created", - "to": "Signup" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } - ] -] diff --git a/test/__tests__/data/pinterest_tag_step_input.json b/test/__tests__/data/pinterest_tag_step_input.json deleted file mode 100644 index 7b4e5071204..00000000000 --- a/test/__tests__/data/pinterest_tag_step_input.json +++ /dev/null @@ -1,2476 +0,0 @@ -[ - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "gender": "non-binary", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Order completed", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "product added", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "product_id": "123", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Product List Filtered", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "Product List Filtered", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "429047995", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "group", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "enhancedMatch": true, - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "ABC Searched", - "channel": "abc", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "numOfItems": 2, - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123", - "adTrackingEnabled": true - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "ip": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "adTrackingEnabled": false - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "requestIP": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": "Hashed phone", - "gender": "Hashed Gender", - "dob": "Hashed DB", - "lastname": "Hashed Lastname", - "firstName": "Hashed FirstName", - "address": { - "city": "Hashed City", - "state": "Hashed State", - "zip": "Hashed Zip", - "country": "Hashed country" - } - }, - "device": { - "adTrackingEnabled": false, - "advertisingId": "Hashed maids" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": false, - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "page", - "name": "ApplicationLoaded", - "category": "test category", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "requestIP": "127.0.0.0", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "phone": ["Hashed phone", "Hashed phone1"], - "gender": ["Hashed Gender", "Hashed Gender1"], - "dob": ["Hashed DB", "Hashed DB1"], - "lastname": ["Hashed Lastname", "Hashed Lastname1"], - "firstName": ["Hashed FirstName", "Hashed FirstName1"], - "address": { - "city": ["Hashed City", "Hashed City1"], - "state": ["Hashed State", "Hashed State1"], - "zip": ["Hashed Zip", "Hashed Zip1"], - "country": ["Hashed country", "Hashed country1"] - } - }, - "device": { - "adTrackingEnabled": false, - "advertisingId": "Hashed maids" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "path": "", - "referrer": "", - "search": "", - "title": "", - "url": "" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": false, - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "name": "Test Tool", - "type": "page", - "sentAt": "2023-02-01T00:00:00.379Z", - "userId": "", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "version": "2.22.3", - "namespace": "com.rudderlabs.javascript" - }, - "page": { - "url": "https://www.abc.com/s598907", - "path": "/test-path/s598907", - "title": "Test Tool + Reviews | Rudderstack", - "search": "", - "tab_url": "https://www.abc.com/s598907", - "referrer": "$direct", - "initial_referrer": "$direct", - "referring_domain": "", - "initial_referring_domain": "" - }, - "locale": "en-US", - "screen": { - "width": 1024, - "height": 1024, - "density": 1, - "innerWidth": 1024, - "innerHeight": 1024 - }, - "traits": {}, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "2.22.3" - }, - "campaign": {}, - "doNotSell": false, - "sessionId": 1675209600203, - "userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/109.0.5414.101 Safari/537.36", - "gaClientId": { - "integrations": { - "Google Ads": { - "gclid": "" - }, - "Google Analytics": { - "clientId": "1518934611.1234569600" - } - } - }, - "sessionStart": true - }, - "rudderId": "7291a10f-e7dd-49f9-94ce-0154f53897y6", - "messageId": "1c77a616-13a7-4a2e-a8e7-e1a0971897y6", - "timestamp": "2023-02-01T12:47:30.030Z", - "properties": { - "sku": "45790-32", - "url": "https://www.abc.com/23rty", - "name": "Test Tool", - "path": "/test-path/tool", - "email": "", - "title": "Test Tool + Reviews | Rudderstack", - "review": { - "reviewCount": 2, - "averageReview": 5, - "reviewContentID": ["238300132"] - }, - "search": "", - "tab_url": "https://www.abc/com", - "pageInfo": { - "pageId": "s592897", - "category": { - "pageType": "product", - "subCategory": "Dining & Kitchen Furniture", - "pageTemplate": "product detail grouper", - "primaryCategory": "Furniture" - }, - "brandType": "new brand" - }, - "referrer": "", - "subCategory": "Dining & Kitchen Furniture", - "primaryCategory": "Furniture", - "initial_referrer": "$direct", - "referring_domain": "", - "initial_referring_domain": "" - }, - "receivedAt": "2023-02-01T12:47:30.038Z", - "request_ip": "66.249.72.218", - "anonymousId": "a61c77a6-1613-474a-aee8-e7e1a0971047", - "integrations": { - "All": true - }, - "originalTimestamp": "2023-02-01T00:00:00.371Z" - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123478671210", - "sendingUnHashedData": false, - "enableDeduplication": false, - "eventsMapping": [ - { - "from": "Product Added", - "to": "AddToCart" - }, - { - "from": "Order Completed", - "to": "Checkout" - }, - { - "from": "Product Viewed", - "to": "PageVisit" - }, - { - "from": "Lead", - "to": "Lead" - }, - { - "from": "Signup", - "to": "Signup" - } - ], - "enhancedMatch": true - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "test", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "sku": "1234", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "sku": "1234", - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - } - ] - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "advertiserId": "123456", - "appId": "429047995", - "sendingUnHashedData": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "enhancedMatch": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Track call with v5 Api version and send external_id toggle enabled", - "message": { - "type": "track", - "event": "ABC Searched", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendExternalId": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Custom event with v5 Api version", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Custom event with v5 Api version, with unhashed User Data and the values are an array of strings", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": ["abc@gmail.com", "def@gmail.com"], - "phone": ["+1234589947", "+1234589948"], - "ge": ["male", "male"], - "db": ["19950715", "19970615"], - "lastname": ["Rudderlabs", "Xu"], - "firstName": ["Test", "Alex"], - "address": { - "city": ["Kolkata", "Mumbai"], - "state": ["WB", "MH"], - "zip": ["700114", "700115"], - "country": ["IN", "IN"] - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "price": 25, - "quantity": 2, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "optOutType": "LDP", - "products": [ - { - "sku": "45790-32", - "url": "https://www.example.com/product/path", - "name": "Monopoly: 3rd Edition", - "price": 19, - "category": "Games", - "quantity": 1, - "image_url": "https:///www.example.com/product/path.jpg", - "product_id": "507f1f77bcf86cd799439011" - }, - { - "sku": "46493-32", - "name": "Uno Card Game", - "price": 3, - "category": "Games", - "quantity": 2, - "product_id": "505bd76785ebb509fc183733" - } - ], - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Ad Account Id check in V5", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "description": "Conversion Token check in V5", - "message": { - "type": "track", - "event": "random", - "sentAt": "2020-08-14T05:30:30.118Z", - "channel": "web", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": true, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - }, - { - "message": { - "type": "track", - "event": "custom event", - "channel": "web", - "sentAt": "2020-08-14T05:30:30.118Z", - "context": { - "source": "test", - "userAgent": "chrome", - "traits": { - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "email": "abc@gmail.com", - "phone": "+1234589947", - "ge": "male", - "db": "19950715", - "lastname": "Rudderlabs", - "firstName": "Test", - "address": { - "city": "Kolkata", - "state": "WB", - "zip": "700114", - "country": "IN" - } - }, - "device": { - "advertisingId": "abc123" - }, - "library": { - "name": "rudder-sdk-ruby-sync", - "version": "1.0.6" - } - }, - "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "timestamp": "2020-08-14T05:30:30.118Z", - "properties": { - "tax": 2, - "total": 27.5, - "coupon": "hasbros", - "revenue": 48, - "currency": "USD", - "discount": 2.5, - "order_id": "50314b8e9bcf000000000000", - "requestIP": "123.0.0.0", - "shipping": 3, - "subtotal": 22.5, - "affiliation": "Google Store", - "checkout_id": "fksdjfsdjfisjf9sdfjsd9f" - }, - "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1", - "integrations": { - "All": true - } - }, - "destination": { - "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", - "Name": "PINTEREST_TAG", - "Config": { - "sendAsTestEvent": false, - "tagId": "123456789", - "apiVersion": "newApi", - "adAccountId": "accountId123", - "conversionToken": "conversionToken123", - "appId": "429047995", - "enhancedMatch": true, - "enableDeduplication": true, - "deduplicationKey": "messageId", - "sendingUnHashedData": true, - "sendAsCustomEvent": false, - "customProperties": [ - { - "properties": "presentclass" - }, - { - "properties": "presentgrade" - } - ], - "eventsMapping": [ - { - "from": "ABC Searched", - "to": "WatchVideo" - } - ] - }, - "Enabled": true, - "Transformations": [] - } - } -] diff --git a/test/__tests__/data/pinterest_tag_step_output.json b/test/__tests__/data/pinterest_tag_step_output.json deleted file mode 100644 index d364bf82dc5..00000000000 --- a/test/__tests__/data/pinterest_tag_step_output.json +++ /dev/null @@ -1,911 +0,0 @@ -[ - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "watch_video", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome", - "ge": ["1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9"] - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "checkout", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "add_to_cart", - "action_source": "web", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 2, - "content_ids": ["123"], - "contents": [ - { - "quantity": 2, - "item_price": "25" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Advertiser Id not found. Aborting" - }, - { - "statusCode": 400, - "error": "It is required at least one of em, hashed_maids or pair of client_ip_address and client_user_agent" - }, - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "watch_video", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "num_items": 2, - "order_id": "50314b8e9bcf000000000000", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Advertiser Id not found. Aborting" - }, - { - "statusCode": 400, - "error": "message type group is not supported" - }, - { - "statusCode": 400, - "error": "Action source must be one of app_android, app_ios, web, offline" - }, - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "action_source": "web", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "num_items": 2, - "order_id": "50314b8e9bcf000000000000", - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "page_visit", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "opt_out": false, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "opt_out": true, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "action_source": "web", - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "client_ip_address": "127.0.0.0", - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "action_source": "web", - "opt_out": true, - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "user_data": { - "ph": ["Hashed phone"], - "db": ["Hashed DB"], - "ln": ["Hashed Lastname"], - "fn": ["Hashed FirstName"], - "ct": ["Hashed City"], - "st": ["Hashed State"], - "zp": ["Hashed Zip"], - "country": ["Hashed country"], - "hashed_maids": ["Hashed maids"], - "ge": ["Hashed Gender"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_time": 1597383030, - "action_source": "web", - "opt_out": true, - "event_name": "view_category", - "app_id": "429047995", - "advertiser_id": "123456", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "user_data": { - "ph": ["Hashed phone", "Hashed phone1"], - "db": ["Hashed DB", "Hashed DB1"], - "ln": ["Hashed Lastname", "Hashed Lastname1"], - "fn": ["Hashed FirstName", "Hashed FirstName1"], - "ct": ["Hashed City", "Hashed City1"], - "st": ["Hashed State", "Hashed State1"], - "zp": ["Hashed Zip", "Hashed Zip1"], - "country": ["Hashed country", "Hashed country1"], - "hashed_maids": ["Hashed maids"], - "ge": ["Hashed Gender", "Hashed Gender1"], - "client_user_agent": "chrome" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "body": { - "JSON": { - "event_time": 1675255650, - "event_source_url": "https://www.abc.com/s598907", - "action_source": "web", - "app_name": "RudderLabs JavaScript SDK", - "app_version": "2.22.3", - "language": "en-US", - "event_id": "1c77a616-13a7-4a2e-a8e7-e1a0971897y6", - "advertiser_id": "123478671210", - "user_data": { - "client_ip_address": "66.249.72.218", - "client_user_agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/109.0.5414.101 Safari/537.36" - }, - "event_name": "page_visit" - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 0, - "content_ids": ["1234"], - "contents": [ - { - "quantity": 1, - "item_price": "undefined" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://ct.pinterest.com/events/v3", - "headers": { - "Content-Type": "application/json" - }, - "params": {}, - "body": { - "JSON": { - "event_name": "custom", - "event_time": 1597383030, - "action_source": "web", - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "advertiser_id": "123456", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "num_items": 1, - "content_ids": ["507f1f77bcf86cd799439011"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "body": { - "FORM": {}, - "JSON": { - "action_source": "web", - "advertiser_id": "123456", - "app_id": "429047995", - "custom_data": { - "contents": [{ "item_price": "undefined", "quantity": 1 }], - "currency": "USD", - "num_items": 0, - "order_id": "50314b8e9bcf000000000000", - "value": "27.5" - }, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "event_name": "custom event", - "event_time": 1597383030, - "user_data": { - "client_user_agent": "chrome", - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"] - } - }, - "JSON_ARRAY": {}, - "XML": {} - }, - "endpoint": "https://ct.pinterest.com/events/v3", - "files": {}, - "headers": { "Content-Type": "application/json" }, - "method": "POST", - "params": {}, - "type": "REST", - "version": "1" - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "watch_video", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome", - "external_id": ["3217d71a74c219d6e31e28267b313a7ceb6a2c032db1a091c9416b25b2ae2bc8"] - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": ["48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08"], - "ph": ["d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b"], - "ln": ["dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251"], - "fn": ["9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"], - "ct": ["6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85"], - "st": ["3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd"], - "zp": ["1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c"], - "country": ["582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf"], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - [ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://api.pinterest.com/v5/ad_accounts/accountId123/events", - "headers": { - "Content-Type": "application/json", - "Authorization": "Bearer conversionToken123" - }, - "params": {}, - "body": { - "JSON": { - "action_source": "web", - "event_name": "custom", - "event_time": 1597383030, - "event_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9", - "app_id": "429047995", - "user_data": { - "em": [ - "48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08", - "c392e50ebeca7bea4405e9c545023451ac56620031f81263f681269bde14218b" - ], - "ph": [ - "d164bbe036663cb5c96835e9ccc6501e9a521127ea62f6359744928ba932413b", - "22bdde2594851294f2a6f4c34af704e68b398b03129ea9ceb58f0ffe33f6db52" - ], - "ln": [ - "dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251", - "9c2f138690fca4890c3c4a6691610fbbbdf32091cc001f7355cfdf574baa52b9" - ], - "fn": [ - "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", - "4135aa9dc1b842a653dea846903ddb95bfb8c5a10c504a7fa16e10bc31d1fdf0" - ], - "ct": [ - "6689106ca7922c30b2fd2c175c85bc7fc2d52cc4941bdd7bb622c6cdc6284a85", - "d209bcc17778fd19fd2bc0c99a3868bf011da5162d3a75037a605768ebc276e2" - ], - "st": [ - "3b45022ab36728cdae12e709e945bba267c50ee8a91e6e4388539a8e03a3fdcd", - "1b0316ed1cfed044035c55363e02ccafab26d66b1c2746b94d17285f043324aa" - ], - "zp": [ - "1a4292e00780e18d00e76fde9850aee5344e939ba593333cd5e4b4aa2cd33b0c", - "4d6755aa1e85517191f06cc91448696c173e1195ae51f94a1670116ac7b5c47b" - ], - "country": [ - "582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf", - "582967534d0f909d196b97f9e6921342777aea87b46fa52df165389db1fb8ccf" - ], - "hashed_maids": ["6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"], - "client_user_agent": "chrome" - }, - "custom_data": { - "currency": "USD", - "value": "27.5", - "order_id": "50314b8e9bcf000000000000", - "opt_out_type": "LDP", - "num_items": 3, - "content_ids": ["507f1f77bcf86cd799439011", "505bd76785ebb509fc183733"], - "contents": [ - { - "quantity": 1, - "item_price": "19" - }, - { - "quantity": 2, - "item_price": "3" - } - ] - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } - ], - { - "statusCode": 400, - "error": "Ad Account ID not found. Aborting" - }, - { - "statusCode": 400, - "error": "Conversion Token not found. Aborting" - }, - { - "statusCode": 400, - "error": "custom event is not mapped in UI. Make sure to map the event in UI or enable the 'send as custom event' setting" - } -] diff --git a/test/__tests__/pinterestConversion-cdk.test.ts b/test/__tests__/pinterestConversion-cdk.test.ts deleted file mode 100644 index 2afde331d50..00000000000 --- a/test/__tests__/pinterestConversion-cdk.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { executeWorkflow, getWorkflowEngine, processCdkV2Workflow } from '../../src/cdk/v2/handler'; -import tags from '../../src/v0/util/tags'; -import logger from '../../src/logger'; - -const integration = 'pinterest_tag'; -const name = 'Pinterest Conversion API'; - -describe(`${name} Tests`, () => { - describe('Processor Tests', () => { - const inputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_input.json`), - { encoding: 'utf8' }, - ); - const outputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_output.json`), - { encoding: 'utf8' }, - ); - const inputData = JSON.parse(inputDataFile); - const expectedData = JSON.parse(outputDataFile); - inputData.forEach((input, index) => { - it(`${name} - payload: ${index}`, async () => { - const expected = expectedData[index]; - try { - const output = await processCdkV2Workflow( - integration, - input, - tags.FEATURES.PROCESSOR, - logger, - ); - expect(output).toEqual(expected); - } catch (error: any) { - expect(error.message).toEqual(expected.error); - } - }); - }); - }); - - describe('Processor Step Tests', () => { - const inputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_input.json`), - { encoding: 'utf8' }, - ); - const outputDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_output.json`), - { encoding: 'utf8' }, - ); - const inputData = JSON.parse(inputDataFile); - const expectedData = JSON.parse(outputDataFile); - inputData.forEach((input, index) => { - it(`${name} - payload: ${index}`, async () => { - const expected = expectedData[index]; - try { - const output = await processCdkV2Workflow( - integration, - input, - tags.FEATURES.PROCESSOR, - logger, - ); - expect(output).toEqual(expected); - } catch (error: any) { - expect(error.message).toEqual(expected.error); - } - }); - }); - }); - - describe('Router Tests', () => { - // Router Test Data - const inputRouterDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_input.json`), - { encoding: 'utf8' }, - ); - - const inputRouterErrorDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_error_input.json`), - { encoding: 'utf8' }, - ); - - const outputRouterBatchDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_batch_output.json`), - { encoding: 'utf8' }, - ); - const outputRouterDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_output.json`), - { encoding: 'utf8' }, - ); - const outputRouterErrorDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_router_error_output.json`), - { encoding: 'utf8' }, - ); - const inputRouterData = JSON.parse(inputRouterDataFile); - const inputRouterErrorData = JSON.parse(inputRouterErrorDataFile); - - const expectedRouterBatchData = JSON.parse(outputRouterBatchDataFile); - const expectedRouterData = JSON.parse(outputRouterDataFile); - const expectedRouterErrorData = JSON.parse(outputRouterErrorDataFile); - - it('Payload with error input', async () => { - const output = await processCdkV2Workflow( - integration, - inputRouterErrorData, - tags.FEATURES.ROUTER, - logger, - ); - expect(output).toEqual(expectedRouterErrorData); - }); - - describe('Default Batch size', () => { - inputRouterData.forEach((input, index) => { - it(`Payload: ${index}`, async () => { - const output = await processCdkV2Workflow( - integration, - input, - tags.FEATURES.ROUTER, - logger, - ); - expect(output).toEqual(expectedRouterData[index]); - }); - }); - }); - describe('Batch size 3', () => { - inputRouterData.forEach((input, index) => { - it(`Payload: ${index}`, async () => { - const workflowEngine = await getWorkflowEngine(integration, tags.FEATURES.ROUTER, { - MAX_BATCH_SIZE: 3, - }); - const output = await executeWorkflow(workflowEngine, input); - expect(output).toEqual(expectedRouterBatchData[index]); - }); - }); - }); - }); -}); From c37207764109c93022f346af12e6fb1e976f62fd Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 18 Oct 2024 09:36:18 +0000 Subject: [PATCH 060/147] chore(release): 1.82.2 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a81c5b5feeb..e4d972f67c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.82.2](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.1...v1.82.2) (2024-10-18) + + +### Bug Fixes + +* add missing fields to pinterest_tag mapping ([#3814](https://github.com/rudderlabs/rudder-transformer/issues/3814)) ([88c6175](https://github.com/rudderlabs/rudder-transformer/commit/88c6175391cf4575a57936aced898465ad78b55e)) + ### [1.82.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.0...v1.82.1) (2024-10-16) diff --git a/package-lock.json b/package-lock.json index a4295bd74c3..00b17114dd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.82.1", + "version": "1.82.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.82.1", + "version": "1.82.2", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 6b41457633a..e6a5259bb35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.82.1", + "version": "1.82.2", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From fcd8d997fe815d61d21ffff235b0799e69b7ded9 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:29:52 +0530 Subject: [PATCH 061/147] fix: not allowing empty string or null values for mandatory fields in zoho (#3800) --- src/cdk/v2/destinations/zoho/utils.js | 6 +++++- src/cdk/v2/destinations/zoho/utils.test.js | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/cdk/v2/destinations/zoho/utils.js b/src/cdk/v2/destinations/zoho/utils.js index 8b170d2b82b..4f5c4e86206 100644 --- a/src/cdk/v2/destinations/zoho/utils.js +++ b/src/cdk/v2/destinations/zoho/utils.js @@ -3,6 +3,7 @@ const { getHashFromArray, isDefinedAndNotNull, ConfigurationError, + isDefinedAndNotNullAndNotEmpty, } = require('@rudderstack/integrations-lib'); const get = require('get-value'); const { getDestinationExternalIDInfoForRetl, isHttpStatusSuccess } = require('../../../../v0/util'); @@ -31,7 +32,10 @@ const deduceModuleInfo = (inputs, Config) => { function validatePresenceOfMandatoryProperties(objectName, object) { if (zohoConfig.MODULE_MANDATORY_FIELD_CONFIG.hasOwnProperty(objectName)) { const requiredFields = zohoConfig.MODULE_MANDATORY_FIELD_CONFIG[objectName]; - const missingFields = requiredFields.filter((field) => !object.hasOwnProperty(field)) || []; + const missingFields = + requiredFields.filter( + (field) => !object.hasOwnProperty(field) || !isDefinedAndNotNullAndNotEmpty(object[field]), + ) || []; return { status: missingFields.length > 0, missingField: missingFields }; } // No mandatory check performed for custom objects diff --git a/src/cdk/v2/destinations/zoho/utils.test.js b/src/cdk/v2/destinations/zoho/utils.test.js index 332a4086958..5a11794ef57 100644 --- a/src/cdk/v2/destinations/zoho/utils.test.js +++ b/src/cdk/v2/destinations/zoho/utils.test.js @@ -130,6 +130,24 @@ describe('validatePresenceOfMandatoryProperties', () => { expect(() => validatePresenceOfMandatoryProperties(objectName, object)).not.toThrow(); }); + it('should return missing field if mandatory field contains empty string', () => { + const objectName = 'Leads'; + const object = { Last_Name: '' }; + + const result = validatePresenceOfMandatoryProperties(objectName, object); + + expect(result).toEqual({ missingField: ['Last_Name'], status: true }); + }); + + it('should return missing field if mandatory field contains empty null', () => { + const objectName = 'Leads'; + const object = { Last_Name: null }; + + const result = validatePresenceOfMandatoryProperties(objectName, object); + + expect(result).toEqual({ missingField: ['Last_Name'], status: true }); + }); + it('should not throw an error if the objectName is not in MODULE_MANDATORY_FIELD_CONFIG', () => { const objectName = 'CustomObject'; const object = { Some_Field: 'Some Value' }; From 427be71a91df8495f81b42d2b58aa490db439b23 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:55:04 +0530 Subject: [PATCH 062/147] fix: update order_id in checkout events, messageId in pixel events (#3794) * fix: update order_id in checkout events, messageId in pixel events * chore: add shopifyDetails support * chore: add shopifyDetails for shopify server side events from pixel * chore: set id property in the webhook event as messageId for pixel serverside event * chore: update tests --- src/v1/sources/shopify/pixelTransform.js | 8 +- src/v1/sources/shopify/pixelUtils.js | 2 +- src/v1/sources/shopify/pixelUtils.test.js | 3 + .../pixelTestScenarios/CheckoutEventsTests.ts | 291 ++++++- .../pixelTestScenarios/CheckoutStepsTests.ts | 708 +++++++++++++++++- .../pixelTestScenarios/ProductEventsTests.ts | 301 +++++++- 6 files changed, 1298 insertions(+), 15 deletions(-) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index 0ca64b41238..a19d431757b 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -23,7 +23,11 @@ const NO_OPERATION_SUCCESS = { function processPixelEvent(inputEvent) { // eslint-disable-next-line @typescript-eslint/naming-convention - const { name, query_parameters, clientId, data } = inputEvent; + const { name, query_parameters, clientId, data, id } = inputEvent; + const shopifyDetails = { ...inputEvent }; + delete shopifyDetails.context; + delete shopifyDetails.query_parameters; + delete shopifyDetails.pixelEventLabel; const { checkout } = data ?? {}; const { order } = checkout ?? {}; const { customer } = order ?? {}; @@ -77,6 +81,8 @@ function processPixelEvent(inputEvent) { version: '2.0.0', }); message.setProperty('context.topic', name); + message.setProperty('context.shopifyDetails', shopifyDetails); + message.messageId = id; message = removeUndefinedAndNullValues(message); return message; } diff --git a/src/v1/sources/shopify/pixelUtils.js b/src/v1/sources/shopify/pixelUtils.js index 92197a558b2..4c39e805496 100644 --- a/src/v1/sources/shopify/pixelUtils.js +++ b/src/v1/sources/shopify/pixelUtils.js @@ -138,7 +138,7 @@ const checkoutEventBuilder = (inputEvent) => { const properties = { products, - order_id: inputEvent.id, + order_id: inputEvent.data?.checkout?.order?.id, checkout_id: inputEvent?.data?.checkout?.token, total: inputEvent?.data?.checkout?.totalPrice?.amount, currency: inputEvent?.data?.checkout?.currencyCode, diff --git a/src/v1/sources/shopify/pixelUtils.test.js b/src/v1/sources/shopify/pixelUtils.test.js index cd544568cd1..ed648622281 100644 --- a/src/v1/sources/shopify/pixelUtils.test.js +++ b/src/v1/sources/shopify/pixelUtils.test.js @@ -171,6 +171,9 @@ describe('utilV2.js', () => { { id: 'product123', name: 'Product 123' }, { id: 'product456', name: 'Product 456' }, ], + order: { + id: 'order123', + }, token: 'checkout123', totalPrice: { amount: 200 }, currencyCode: 'USD', diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts index 1009fa2d040..3381223317c 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts @@ -207,6 +207,132 @@ export const pixelCheckoutEventsTestScenarios = [ version: '2.0.0', }, topic: 'checkout_started', + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_started', + timestamp: '2024-09-15T20:57:59.674Z', + type: 'standard', + }, }, integrations: { SHOPIFY: true, @@ -238,7 +364,7 @@ export const pixelCheckoutEventsTestScenarios = [ brand: 'Hydrogen Vendor', }, ], - order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + order_id: null, checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', total: 2759.8, currency: 'USD', @@ -249,6 +375,7 @@ export const pixelCheckoutEventsTestScenarios = [ tax: 0, }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', }, ], }, @@ -495,6 +622,165 @@ export const pixelCheckoutEventsTestScenarios = [ version: '2.0.0', }, topic: 'checkout_completed', + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_completed', + timestamp: '2024-09-15T20:57:59.674Z', + type: 'standard', + }, }, integrations: { SHOPIFY: true, @@ -548,7 +834,7 @@ export const pixelCheckoutEventsTestScenarios = [ brand: 'Multi-managed Vendor', }, ], - order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + order_id: null, checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', total: 2759.8, currency: 'USD', @@ -559,6 +845,7 @@ export const pixelCheckoutEventsTestScenarios = [ tax: 0, }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', }, ], }, diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts index 9d845c1dded..38f682ac6da 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts @@ -206,7 +206,185 @@ export const pixelCheckoutStepsScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'checkout_address_info_submitted' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', + name: 'checkout_address_info_submitted', + timestamp: '2024-09-15T21:45:50.523Z', + type: 'standard', + }, + topic: 'checkout_address_info_submitted', + }, integrations: { SHOPIFY: true, }, @@ -379,6 +557,7 @@ export const pixelCheckoutStepsScenarios = [ transactions: [], }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', }, ], }, @@ -577,7 +756,169 @@ export const pixelCheckoutStepsScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'checkout_contact_info_submitted' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', + name: 'checkout_contact_info_submitted', + timestamp: '2024-09-15T21:40:28.498Z', + type: 'standard', + }, + topic: 'checkout_contact_info_submitted', + }, integrations: { SHOPIFY: true, }, @@ -734,6 +1075,7 @@ export const pixelCheckoutStepsScenarios = [ transactions: [], }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', }, ], }, @@ -947,7 +1289,185 @@ export const pixelCheckoutStepsScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'checkout_shipping_info_submitted' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', + name: 'checkout_shipping_info_submitted', + timestamp: '2024-09-15T21:47:38.576Z', + type: 'standard', + }, + topic: 'checkout_shipping_info_submitted', + }, integrations: { SHOPIFY: true, }, @@ -1120,6 +1640,7 @@ export const pixelCheckoutStepsScenarios = [ transactions: [], }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', }, ], }, @@ -1333,7 +1854,185 @@ export const pixelCheckoutStepsScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'payment_info_submitted' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + checkout: { + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + id: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', + name: 'payment_info_submitted', + timestamp: '2024-09-15T21:49:13.092Z', + type: 'standard', + }, + topic: 'payment_info_submitted', + }, integrations: { SHOPIFY: true, }, @@ -1506,6 +2205,7 @@ export const pixelCheckoutStepsScenarios = [ transactions: [], }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', }, ], }, diff --git a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts index 0b8f8c3c1a3..b293bd46f95 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts @@ -41,7 +41,18 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'page_viewed' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: {}, + id: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', + name: 'page_viewed', + timestamp: '2024-09-15T17:24:30.373Z', + type: 'standard', + }, + topic: 'page_viewed', + }, integrations: { SHOPIFY: true, }, @@ -49,6 +60,7 @@ export const pixelEventsTestScenarios = [ type: 'page', properties: {}, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', }, ], }, @@ -118,7 +130,40 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'product_viewed' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + productVariant: { + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + }, + id: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', + name: 'product_viewed', + timestamp: '2024-09-15T17:34:54.889Z', + type: 'standard', + }, + topic: 'product_viewed', + }, integrations: { SHOPIFY: true, }, @@ -156,6 +201,7 @@ export const pixelEventsTestScenarios = [ name: 'The Collection Snowboard: Liquid', }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', }, ], }, @@ -247,7 +293,62 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'cart_viewed' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + cart: { + attributes: [], + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + }, + }, + id: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', + name: 'cart_viewed', + timestamp: '2024-09-15T18:25:30.125Z', + type: 'standard', + }, + topic: 'cart_viewed', + }, integrations: { SHOPIFY: true, }, @@ -300,6 +401,7 @@ export const pixelEventsTestScenarios = [ total: 1259.9, }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', }, ], }, @@ -417,7 +519,88 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'collection_viewed' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + collection: { + id: '', + productVariants: [ + { + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + price: { + amount: 10, + currencyCode: 'USD', + }, + product: { + id: '7234590605425', + title: 'Gift Card', + type: 'giftcard', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + vendor: 'Snowboard Vendor', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + }, + { + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + price: { + amount: 24.95, + currencyCode: 'USD', + }, + product: { + id: '7234590802033', + title: 'Selling Plans Ski Wax', + type: 'accessories', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + vendor: 'pixel-testing-rs', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + }, + { + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + price: { + amount: 2629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590703729', + title: 'The 3p Fulfilled Snowboard', + type: 'snowboard', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + vendor: 'pixel-testing-rs', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + ], + title: 'Products', + }, + }, + id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + name: 'collection_viewed', + timestamp: '2024-09-15T18:27:39.197Z', + type: 'standard', + }, + topic: 'collection_viewed', + }, integrations: { SHOPIFY: true, }, @@ -508,6 +691,7 @@ export const pixelEventsTestScenarios = [ ], }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', }, ], }, @@ -586,7 +770,49 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'product_added_to_cart' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + vendor: 'Hydrogen Vendor', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + id: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', + name: 'product_added_to_cart', + timestamp: '2024-09-15T18:34:42.625Z', + type: 'standard', + }, + topic: 'product_added_to_cart', + }, integrations: { SHOPIFY: true, }, @@ -636,6 +862,7 @@ export const pixelEventsTestScenarios = [ quantity: 1, }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', }, ], }, @@ -714,7 +941,49 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'product_removed_from_cart' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + vendor: 'Hydrogen Vendor', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + id: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', + name: 'product_removed_from_cart', + timestamp: '2024-09-15T20:56:00.125Z', + type: 'standard', + }, + topic: 'product_removed_from_cart', + }, integrations: { SHOPIFY: true, }, @@ -764,6 +1033,7 @@ export const pixelEventsTestScenarios = [ quantity: 1, }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', }, ], }, @@ -816,7 +1086,23 @@ export const pixelEventsTestScenarios = [ output: { batch: [ { - context: { ...responseDummyContext, topic: 'search_submitted' }, + context: { + ...responseDummyContext, + shopifyDetails: { + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + data: { + searchResult: { + productVariants: [], + query: 'skate', + }, + }, + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'search_submitted', + timestamp: '2024-09-15T22:37:35.869Z', + type: 'standard', + }, + topic: 'search_submitted', + }, integrations: { SHOPIFY: true, }, @@ -826,6 +1112,7 @@ export const pixelEventsTestScenarios = [ query: 'skate', }, anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + messageId: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', }, ], }, From 91f8ca76ad989af2606f915289cfcc0ada3fbaf0 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:32:36 +0530 Subject: [PATCH 063/147] chore: add network handler file for ga4 v2 in v0 implementation flow (#3822) * chore: add network handler file for ga4 v2 in v0 implementation flow * chore: add tests --- src/v0/destinations/ga4_v2/networkHandler.js | 1 + src/v1/destinations/ga4_v2/networkHandler.ts | 3 --- test/integrations/destinations/ga4_v2/dataDelivery/business.ts | 1 + test/integrations/destinations/ga4_v2/dataDelivery/data.ts | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/v0/destinations/ga4_v2/networkHandler.js delete mode 100644 src/v1/destinations/ga4_v2/networkHandler.ts create mode 100644 test/integrations/destinations/ga4_v2/dataDelivery/business.ts create mode 100644 test/integrations/destinations/ga4_v2/dataDelivery/data.ts diff --git a/src/v0/destinations/ga4_v2/networkHandler.js b/src/v0/destinations/ga4_v2/networkHandler.js new file mode 100644 index 00000000000..3e25b43b38b --- /dev/null +++ b/src/v0/destinations/ga4_v2/networkHandler.js @@ -0,0 +1 @@ +export { networkHandler } from '../ga4/networkHandler'; diff --git a/src/v1/destinations/ga4_v2/networkHandler.ts b/src/v1/destinations/ga4_v2/networkHandler.ts deleted file mode 100644 index aece0411c18..00000000000 --- a/src/v1/destinations/ga4_v2/networkHandler.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { networkHandler } from '../../../v0/destinations/ga4/networkHandler'; - -module.exports = { networkHandler }; diff --git a/test/integrations/destinations/ga4_v2/dataDelivery/business.ts b/test/integrations/destinations/ga4_v2/dataDelivery/business.ts new file mode 100644 index 00000000000..4cfa56f498c --- /dev/null +++ b/test/integrations/destinations/ga4_v2/dataDelivery/business.ts @@ -0,0 +1 @@ +export { testScenariosForV0API, testScenariosForV1API } from '../../ga4/dataDelivery/business'; diff --git a/test/integrations/destinations/ga4_v2/dataDelivery/data.ts b/test/integrations/destinations/ga4_v2/dataDelivery/data.ts new file mode 100644 index 00000000000..1790a67cdca --- /dev/null +++ b/test/integrations/destinations/ga4_v2/dataDelivery/data.ts @@ -0,0 +1 @@ +export { data } from '../../ga4/dataDelivery/data'; From 21b1039c26067b4896a15adf8b10a044e69cb495 Mon Sep 17 00:00:00 2001 From: Akash Chetty Date: Tue, 22 Oct 2024 11:19:01 +0530 Subject: [PATCH 064/147] feat: snowpipe streaming (#3740) --- .../snowpipe_streaming/transform.js | 1 + test/__tests__/warehouse.test.js | 239 +++++++++--------- 2 files changed, 125 insertions(+), 115 deletions(-) create mode 100644 src/v0/destinations/snowpipe_streaming/transform.js diff --git a/src/v0/destinations/snowpipe_streaming/transform.js b/src/v0/destinations/snowpipe_streaming/transform.js new file mode 100644 index 00000000000..3b0a6e1a931 --- /dev/null +++ b/src/v0/destinations/snowpipe_streaming/transform.js @@ -0,0 +1 @@ +module.exports = require('../snowflake/transform'); diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 6bde2e9eb22..7fdecbd7cff 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -29,6 +29,7 @@ const integrations = [ "postgres", "clickhouse", "snowflake", + "snowpipe_streaming", "mssql", "azure_synapse", "deltalake", @@ -36,6 +37,14 @@ const integrations = [ "s3_datalake", "gcs_datalake", ]; + +const integration = (index ) => { + const it = integrations[index]; + if (it === "snowflake" || it === "snowpipe_streaming") { + return "snowflake"; + } + return it; +} const transformers = integrations.map(integration => require(`../../src/${version}/destinations/${integration}/transform`) ); @@ -65,7 +74,7 @@ describe("event types", () => { const i = input("track"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("track", integrations[index])); + expect(received).toMatchObject(output("track", integration(index))); }); }); }); @@ -76,7 +85,7 @@ describe("event types", () => { // also verfies priority order between traits and context.traits transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("identify", integrations[index])); + expect(received).toMatchObject(output("identify", integration(index))); }); }); }); @@ -86,7 +95,7 @@ describe("event types", () => { const i = input("page"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integrations[index])); + expect(received).toMatchObject(output("page", integration(index))); }); }); it("should take name from properties if top-level name is missing", () => { @@ -95,7 +104,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integrations[index])); + expect(received).toMatchObject(output("page", integration(index))); }); }); }); @@ -105,7 +114,7 @@ describe("event types", () => { const i = input("screen"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integrations[index])); + expect(received).toMatchObject(output("screen", integration(index))); }); }); it("should take name from properties if top-level name is missing", () => { @@ -114,7 +123,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integrations[index])); + expect(received).toMatchObject(output("screen", integration(index))); }); }); }); @@ -124,7 +133,7 @@ describe("event types", () => { const i = input("alias"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("alias", integrations[index])); + expect(received).toMatchObject(output("alias", integration(index))); }); }); }); @@ -134,7 +143,7 @@ describe("event types", () => { const i = input("extract"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("extract", integrations[index])); + expect(received).toMatchObject(output("extract", integration(index))); }); }); }); @@ -153,7 +162,7 @@ describe("column & table names", () => { const received = transformer.process(i); const provider = - integrations[index] === "snowflake" ? "snowflake" : "default"; + (integration(index) === "snowflake" || integration(index) == "snowpipe_streaming") ? "snowflake" : "default"; expect(received[1].metadata.columns).toMatchObject( names.output.columns[provider] @@ -186,7 +195,7 @@ describe("column & table names", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); - if (integrations[index] === "postgres") { + if (integration(index) === "postgres") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1" @@ -210,7 +219,7 @@ describe("column & table names", () => { //KEY should be trimmed to 63 return; } - if (integrations[index] === "snowflake") { + if (integration(index) === "snowflake") { expect(received[1].metadata).toHaveProperty( "table", "A_1_A_2_A_3_A_4_A_5_B_1_B_2_B_3_B_4_B_5_C_1_C_2_C_3_C_4_C_5_D_1_D_2_D_3_D_4_D_5_E_1_E_2_E_3_E_4_E_5_F_1_F_2_F_3_F_4_F_5_G_1_G_2" @@ -233,7 +242,7 @@ describe("column & table names", () => { ); return; } - if (integrations[index] === "s3_datalake" || integrations[index] === "gcs_datalake" || integrations[index] === "azure_datalake") { + if (integration(index) === "s3_datalake" || integration(index) === "gcs_datalake" || integration(index) === "azure_datalake") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1_d_2_d_3_d_4_d_5_e_1_e_2_e_3_e_4_e_5_f_1_f_2_f_3_f_4_f_5_g_1_g_2_g_3_g_4_g_5" @@ -316,7 +325,7 @@ describe("conflict between rudder set props and user set props", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { let sampleRudderPropKey = "id"; - if (integrations[index] === "snowflake") { + if (integration(index) === "snowflake") { sampleRudderPropKey = "ID"; } @@ -354,7 +363,7 @@ describe("handle reserved words", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { const reserverdKeywordsMap = - reservedANSIKeywordsMap[integrations[index].toUpperCase()]; + reservedANSIKeywordsMap[integration(index).toUpperCase()]; i.message[propsKey] = Object.assign( i.message[propsKey] || {}, @@ -377,7 +386,7 @@ describe("handle reserved words", () => { } else { k = snakeCasedKey; } - if (integrations[index] === "snowflake") { + if (integration(index) === "snowflake") { expect(out.metadata.columns).toHaveProperty(k); } else { expect(out.metadata.columns).toHaveProperty(k.toLowerCase()); @@ -461,24 +470,24 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toEqual("new_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toEqual("new_ip"); } @@ -496,23 +505,23 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toEqual("requested_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ] ).toEqual("requested_ip"); } @@ -533,10 +542,10 @@ describe("remove rudder property if rudder property is null", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "context_ip") + integrationCasedString(integration(index), "context_ip") ); }); }); @@ -551,29 +560,29 @@ describe("remove any property if event is object ", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "channel") + integrationCasedString(integration(index), "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "channel") + integrationCasedString(integration(index), "channel") ); }); transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "event_text") + integrationCasedString(integration(index), "event_text") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "event_text") + integrationCasedString(integration(index), "event_text") ); }); i.message.channel = { channel: "android" }; transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "channel") + integrationCasedString(integration(index), "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "channel") + integrationCasedString(integration(index), "channel") ); }); }); @@ -589,13 +598,13 @@ describe("store full rudder event", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); const columnName = integrationCasedString( - integrations[index], + integration(index), "rudder_event" ); expect(received[0].metadata.columns).toHaveProperty(columnName); expect(received[0].metadata.columns[columnName]).toEqual( - fullEventColumnTypeByProvider[integrations[index]] + fullEventColumnTypeByProvider[integration(index)] ); expect(received[0].data[columnName]).toEqual(JSON.stringify(i.message)); @@ -635,7 +644,7 @@ describe("rudder reserved columns", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); checkProps.forEach(k => { - k = integrationCasedString(integrations[index], k); + k = integrationCasedString(integration(index), k); expect(received[0].metadata.columns).not.toHaveProperty(k); expect(received[0].data).not.toHaveProperty(k); if (received[1]) { @@ -657,12 +666,12 @@ describe("id column datatype for users table", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "user_id") + integrationCasedString(integration(index), "user_id") ] ).toEqual("int"); expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ] ).toEqual("int"); }); @@ -674,12 +683,12 @@ describe("id column datatype for users table", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "user_id") + integrationCasedString(integration(index), "user_id") ] ).toEqual("float"); expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ] ).toEqual("float"); }); @@ -698,22 +707,22 @@ describe("handle leading underscores in properties", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "_timestamp") + integrationCasedString(integration(index), "_timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "__timestamp") + integrationCasedString(integration(index), "__timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "__timestamp_new") + integrationCasedString(integration(index), "__timestamp_new") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integrations[index], "_timestamp") + integrationCasedString(integration(index), "_timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integrations[index], "__timestamp") + integrationCasedString(integration(index), "__timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integrations[index], "__timestamp_new") + integrationCasedString(integration(index), "__timestamp_new") ); }); }); @@ -727,22 +736,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect( - received[0].data[integrationCasedString(integrations[index], "id")] + received[0].data[integrationCasedString(integration(index), "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect( - received[1].data[integrationCasedString(integrations[index], "id")] + received[1].data[integrationCasedString(integration(index), "id")] ).toEqual(i.message.messageId); }); }); @@ -755,22 +764,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect( - received[0].data[integrationCasedString(integrations[index], "id")] + received[0].data[integrationCasedString(integration(index), "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect( - received[1].data[integrationCasedString(integrations[index], "id")] + received[1].data[integrationCasedString(integration(index), "id")] ).toEqual(i.message.messageId); }); }); @@ -783,17 +792,17 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect( - received[0].data[integrationCasedString(integrations[index], "id")] + received[0].data[integrationCasedString(integration(index), "id")] ).toEqual(i.message.messageId); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ] ).toEqual("string"); }); @@ -809,28 +818,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integrations[index], "id")] + received[1].data[integrationCasedString(integration(index), "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); }); }); @@ -845,28 +854,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integrations[index], "id")] + received[1].data[integrationCasedString(integration(index), "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integrations[index], "record_id") + integrationCasedString(integration(index), "record_id") ); }); }); @@ -906,10 +915,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -934,10 +943,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -947,7 +956,7 @@ describe("Handle no of columns in an event", () => { it("should throw an error if no of columns are more than 200", () => { const i = input("track"); transformers - .filter((transformer, index) => integrations[index] !== "s3_datalake" && integrations[index] !== "gcs_datalake" && integrations[index] !== "azure_datalake") + .filter((transformer, index) => integration(index) !== "s3_datalake" && integration(index) !== "gcs_datalake" && integration(index) !== "azure_datalake") .forEach((transformer, index) => { i.message.properties = largeNoOfColumnsevent; expect(() => transformer.process(i)).toThrow( @@ -975,13 +984,13 @@ describe("Add auto generated messageId for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integrations[index], "id") + integrationCasedString(integration(index), "id") ); expect( - received[0].data[integrationCasedString(integrations[index], "id")] + received[0].data[integrationCasedString(integration(index), "id")] ).toMatch(/auto-.*/); }); }); @@ -998,10 +1007,10 @@ describe("Add receivedAt for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integrations[index], "received_at") + integrationCasedString(integration(index), "received_at") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integrations[index], "received_at") + integrationCasedString(integration(index), "received_at") ); }); }); @@ -1014,12 +1023,12 @@ describe("Integration options", () => { const i = opInput("track"); transformers.forEach((transformer, index) => { const {jsonPaths} = i.destination.Config; - if (integrations[index] === "postgres") { + if (integration(index) === "postgres") { delete i.destination.Config.jsonPaths; } const received = transformer.process(i); i.destination.Config.jsonPaths = jsonPaths; - expect(received).toEqual(opOutput("track", integrations[index])); + expect(received).toEqual(opOutput("track", integration(index))); }); }); }); @@ -1029,7 +1038,7 @@ describe("Integration options", () => { const i = opInput("users"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toEqual(opOutput("users", integrations[index])); + expect(received).toEqual(opOutput("users", integration(index))); }); }); }); @@ -1084,18 +1093,18 @@ describe("Integration options", () => { for (const testCase of testCases) { transformers.forEach((transformer, index) => { - it(`new ${testCase.eventType} for ${integrations[index]}`, () => { + it(`new ${testCase.eventType} for ${integration(index)}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/new/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integrations[index])); + expect(received).toEqual(output(testCase.eventType, config, integration(index))); }) - it(`legacy ${testCase.eventType} for ${integrations[index]}`, () => { + it(`legacy ${testCase.eventType} for ${integration(index)}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/legacy/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integrations[index])); + expect(received).toEqual(output(testCase.eventType, config, integration(index))); }) }); } @@ -1285,10 +1294,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data[integrationCasedString(integrations[index], trait)]).toEqual(value); - expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); + expect(event.data[integrationCasedString(integration(index), trait)]).toEqual(value); + expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); }); }); }); @@ -1316,13 +1325,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); - expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); - expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); - expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v_2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); + expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); + expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); + expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); + expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v_2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); }); }); }); @@ -1364,10 +1373,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data).not.toHaveProperty(integrationCasedString(integrations[index], trait)); - expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integrations[index], trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); + expect(event.data).not.toHaveProperty(integrationCasedString(integration(index), trait)); + expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integration(index), trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); }); }); }); @@ -1393,13 +1402,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); - expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); - expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); - expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); + expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); + expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); + expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); + expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); }); }); }); @@ -1606,8 +1615,8 @@ describe("context traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/context_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); } }); } @@ -1699,8 +1708,8 @@ describe("group traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/group_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); } }); }); From 741f0c6d6714cf760ce98cc9354b61f7b5ce4684 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:34:43 +0530 Subject: [PATCH 065/147] feat: onboard tune destination (#3795) * feat: onboard tune destination * chore: test cases added * chore: file name updated * chore: import fix * chore: updated mappings * chore: updated transform.js * chore: updated test cases * chore: small fix * chore: router test cases added * chore: minor fix --------- Co-authored-by: Sai Sankeerth --- src/v0/destinations/tune/transform.js | 90 +++++++ .../destinations/tune/processor/data.ts | 3 + .../tune/processor/trackTestData.ts | 228 ++++++++++++++++++ .../destinations/tune/router/data.ts | 190 +++++++++++++++ 4 files changed, 511 insertions(+) create mode 100644 src/v0/destinations/tune/transform.js create mode 100644 test/integrations/destinations/tune/processor/data.ts create mode 100644 test/integrations/destinations/tune/processor/trackTestData.ts create mode 100644 test/integrations/destinations/tune/router/data.ts diff --git a/src/v0/destinations/tune/transform.js b/src/v0/destinations/tune/transform.js new file mode 100644 index 00000000000..97dad0e3d38 --- /dev/null +++ b/src/v0/destinations/tune/transform.js @@ -0,0 +1,90 @@ +const get = require('get-value'); +const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const { + defaultRequestConfig, + simpleProcessRouterDest, + getHashFromArray, + isDefinedAndNotNull, + isNotEmpty, +} = require('../../util'); + +const mapPropertiesWithNestedSupport = (msg, properties, mappings) => { + const mappedObj = {}; // Create a new object for parameters + Object.entries(mappings).forEach(([key, value]) => { + const keyStr = `${key}`; + const args = { object: properties, key: keyStr }; + if (args.key.split('.').length > 1) { + // Handle nested keys + args.object = msg; // This line modifies the object property of args + } + const data = get(args.object, args.key); + if (isDefinedAndNotNull(data) && isNotEmpty(data)) { + mappedObj[value] = data; // Map to the corresponding destination key + } + }); + return mappedObj; // Return the new params object +}; + +const responseBuilder = (message, { Config }) => { + const { tuneEvents } = Config; // Extract tuneEvents from config + const { properties, event: messageEvent } = message; // Destructure properties and event from message + + // Find the relevant tune event based on the message's event name + const tuneEvent = tuneEvents.find((event) => event.eventName === messageEvent); + + if (tuneEvent) { + const standardHashMap = getHashFromArray(tuneEvent.standardMapping, 'from', 'to', false); + const advSubIdHashMap = getHashFromArray(tuneEvent.advSubIdMapping, 'from', 'to', false); + const advUniqueIdHashMap = getHashFromArray(tuneEvent.advUniqueIdMapping, 'from', 'to', false); + + const params = { + ...mapPropertiesWithNestedSupport(message, properties, standardHashMap), + ...mapPropertiesWithNestedSupport(message, properties, advSubIdHashMap), + ...mapPropertiesWithNestedSupport(message, properties, advUniqueIdHashMap), + }; + + // Prepare the response + const response = defaultRequestConfig(); + response.params = params; // Set only the mapped params + response.endpoint = tuneEvent.url; // Use the user-defined URL + + return response; + } + + throw new InstrumentationError('No matching tune event found for the provided event.', 400); +}; + +const processEvent = (message, destination) => { + // Validate message type + if (!isDefinedAndNotNull(message.type) || typeof message.type !== 'string') { + throw new InstrumentationError( + 'Message Type is not present or is not a string. Aborting message.', + 400, + ); + } + const messageType = message.type.toLowerCase(); + + // Initialize response variable + let response; + + // Process 'track' messages using the responseBuilder + if (messageType === 'track') { + response = responseBuilder(message, destination); + } else { + throw new InstrumentationError('Message type not supported. Only "track" is allowed.', 400); + } + + return response; +}; + +const process = (event) => processEvent(event.message, event.destination); + +const processRouterDest = async (inputs, reqMetadata) => { + const respList = await simpleProcessRouterDest(inputs, process, reqMetadata); + return respList; +}; + +module.exports = { + process, + processRouterDest, +}; diff --git a/test/integrations/destinations/tune/processor/data.ts b/test/integrations/destinations/tune/processor/data.ts new file mode 100644 index 00000000000..aa818d9b838 --- /dev/null +++ b/test/integrations/destinations/tune/processor/data.ts @@ -0,0 +1,3 @@ +import { trackTestdata } from './trackTestData'; + +export const data = [...trackTestdata]; diff --git a/test/integrations/destinations/tune/processor/trackTestData.ts b/test/integrations/destinations/tune/processor/trackTestData.ts new file mode 100644 index 00000000000..c19ffdd84cb --- /dev/null +++ b/test/integrations/destinations/tune/processor/trackTestData.ts @@ -0,0 +1,228 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + overrideDestination, + transformResultBuilder, +} from '../../../testUtils'; + +const destination: Destination = { + ID: '123', + Name: 'tune', + DestinationDefinition: { + ID: '123', + Name: 'tune', + DisplayName: 'tune', + Config: {}, + }, + Config: { + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + tuneEvents: [ + { + url: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + eventName: 'Product added', + standardMapping: [ + { to: 'aff_id', from: 'affId' }, + { to: 'promo_code', from: 'promoCode' }, + { to: 'security_token', from: 'securityToken' }, + { to: 'status', from: 'status' }, + { to: 'transaction_id', from: 'mytransactionId' }, + ], + advSubIdMapping: [{ from: 'context.traits.ip', to: 'adv_sub2' }], + advUniqueIdMapping: [{ from: 'context.traits.customProperty1', to: 'adv_unique1' }], + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackTestdata: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'tune', + description: 'Track call with standard properties mapping', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product added', + properties: { + securityToken: '1123', + mytransactionId: 'test-123', + }, + context: { + traits: { + customProperty1: 'customValue', + firstName: 'David', + logins: 2, + ip: '0.0.0.0', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + event: 'Product added', + headers: {}, + params: { + security_token: '1123', + transaction_id: 'test-123', + adv_sub2: '0.0.0.0', + adv_unique1: 'customValue', + }, + userId: '', + JSON: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'Test 1', + name: 'tune', + description: 'Test case for handling a missing tune event for a given event name', + scenario: 'Business', + successCriteria: + 'The response should return a 400 status code with an appropriate error message indicating no matching tune event was found.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Purchase event', + properties: { + securityToken: '1123', + mytransactionId: 'test-123', + }, + context: { + traits: { + customProperty1: 'customValue', + firstName: 'David', + logins: 2, + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'No matching tune event found for the provided event.', + statTags: { + destType: 'TUNE', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + }, + { + id: 'Test 2', + name: 'tune', + description: 'Incorrect message type', + scenario: 'Business', + successCriteria: 'The response should return a 400 status code due to invalid message type.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'abc', + event: 'Product added', + properties: { + securityToken: '1123', + mytransactionId: 'test-123', + }, + context: { + traits: { + customProperty1: 'customValue', + firstName: 'David', + logins: 2, + }, + }, + anonymousId: 'david_bowie_anonId', + }, + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Message type not supported. Only "track" is allowed.', + statTags: { + destType: 'TUNE', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/tune/router/data.ts b/test/integrations/destinations/tune/router/data.ts new file mode 100644 index 00000000000..65bfee4ade5 --- /dev/null +++ b/test/integrations/destinations/tune/router/data.ts @@ -0,0 +1,190 @@ +import { Destination } from '../../../../../src/types'; +import { RouterTestData } from '../../../testTypes'; +import { generateMetadata } from '../../../testUtils'; + +const destination: Destination = { + ID: '123', + Name: 'tune', + DestinationDefinition: { + ID: '123', + Name: 'tune', + DisplayName: 'tune', + Config: {}, + }, + Config: { + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + tuneEvents: [ + { + url: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + eventName: 'Product added', + standardMapping: [ + { to: 'aff_id', from: 'affId' }, + { to: 'promo_code', from: 'promoCode' }, + { to: 'security_token', from: 'securityToken' }, + { to: 'status', from: 'status' }, + { to: 'transaction_id', from: 'mytransactionId' }, + ], + advSubIdMapping: [{ from: 'context.ip', to: 'adv_sub2' }], + advUniqueIdMapping: [{ from: 'context.traits.anonymousId', to: 'adv_unique1' }], + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const data: RouterTestData[] = [ + { + id: 'tune-router-test-1', + name: 'tune', + description: 'Basic Router Test for track call with standard properties mapping.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product added', + anonymousId: 'sampath', + channel: 'web', + context: { + app: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + ip: '0.0.0.0', + traits: { anonymousId: 'sampath', email: 'sampath@gmail.com' }, + }, + integrations: { All: true }, + properties: { + securityToken: '1123', + mytransactionId: 'test-123', + }, + }, + }, + ], + destType: 'tune', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + headers: {}, + params: { + security_token: '1123', + transaction_id: 'test-123', + adv_sub2: '0.0.0.0', + adv_unique1: 'sampath', + }, + body: { + JSON: {}, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: false, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'tune-router-test-2', + name: 'tune', + description: 'Basic Router Test with incorrect message type ', + scenario: 'Business', + successCriteria: + 'The response should return a 400 status code due to an invalid message type, with an appropriate error message indicating that the message type is not present or is not a string.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 123, + event: 'Product added', + anonymousId: 'sampath', + channel: 'web', + context: { + app: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + ip: '0.0.0.0', + traits: { anonymousId: 'sampath', email: 'sampath@gmail.com' }, + }, + integrations: { All: true }, + properties: { + securityToken: '1123', + mytransactionId: 'test-123', + }, + }, + }, + ], + destType: 'tune', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + error: 'Message Type is not present or is not a string. Aborting message.', + statTags: { + destType: 'TUNE', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: [generateMetadata(1)], + batched: false, + statusCode: 400, + destination, + }, + ], + }, + }, + }, + }, +]; From f781a84ade98649d68cebf4da13c2ceff8df2df2 Mon Sep 17 00:00:00 2001 From: ItsSudip Date: Wed, 23 Oct 2024 11:12:57 +0530 Subject: [PATCH 066/147] fix: add missing field for pinterest_tag single product events --- .../v2/destinations/pinterest_tag/procWorkflow.yaml | 6 +++++- test/apitests/data_scenarios/cdk_v2/failure.json | 8 ++++++++ test/apitests/data_scenarios/cdk_v2/success.json | 12 ++++++++++++ .../destination/proc/batch_input_multiplex.json | 12 ++++++++++++ .../destination/proc/multiplex_partial_failure.json | 8 ++++++++ .../destination/proc/multiplex_success.json | 8 ++++++++ .../destination/router/failure_test.json | 8 ++++++++ .../destinations/pinterest_tag/processor/data.ts | 13 ++++++++++--- .../destinations/pinterest_tag/router/data.ts | 4 +++- .../destinations/pinterest_tag/step/data.ts | 11 ++++++++--- 10 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml index 64d391c8882..5d97da5a9ed 100644 --- a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml @@ -167,7 +167,11 @@ steps: "content_ids": (props.product_id ?? props.sku ?? props.id)[], "contents": { "quantity": Number(props.quantity) || 1, - "item_price": String(props.price) + "item_price": String(props.price), + "item_name": String(props.name), + "id": props.product_id ?? props.sku, + "item_category": props.category, + "item_brand": props.brand }[] }; - name: combineAllEcomFields diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 1635a3f0dbf..154d24481dc 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -556,6 +556,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -679,6 +683,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index ced7433a282..88f430dd7c2 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -556,6 +556,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -634,6 +638,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -712,6 +720,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3ce7c150918..3deb7d4b8ba 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -388,6 +388,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -466,6 +470,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -544,6 +552,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index 0e467c26d0b..a2652855d56 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -388,6 +388,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -466,6 +470,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index 66b6c870a9e..ba4d5266f30 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -207,6 +207,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -285,6 +289,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 9e36da50cb8..197456f66af 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -754,6 +754,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -781,6 +785,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/integrations/destinations/pinterest_tag/processor/data.ts b/test/integrations/destinations/pinterest_tag/processor/data.ts index b856d247d71..1788d13d563 100644 --- a/test/integrations/destinations/pinterest_tag/processor/data.ts +++ b/test/integrations/destinations/pinterest_tag/processor/data.ts @@ -482,7 +482,9 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [ + { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, + ], }, }, JSON_ARRAY: {}, @@ -2405,7 +2407,9 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [{ quantity: 1, item_price: 'undefined' }], + contents: [ + { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, + ], }, }, JSON_ARRAY: {}, @@ -2666,7 +2670,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1 }], + contents: [{ item_price: 'undefined', quantity: 1, item_name: 'undefined' }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3497,6 +3501,7 @@ export const data = [ subtotal: 22.5, affiliation: 'Google Store', checkout_id: 'fksdjfsdjfisjf9sdfjsd9f', + category: 'Apparel', }, anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', integrations: { All: true }, @@ -3563,6 +3568,8 @@ export const data = [ { quantity: 1, item_price: 'undefined', + item_name: 'undefined', + item_category: 'Apparel', }, ], currency: 'USD', diff --git a/test/integrations/destinations/pinterest_tag/router/data.ts b/test/integrations/destinations/pinterest_tag/router/data.ts index c9ab29a45a9..28c82c4679c 100644 --- a/test/integrations/destinations/pinterest_tag/router/data.ts +++ b/test/integrations/destinations/pinterest_tag/router/data.ts @@ -815,7 +815,9 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [ + { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, + ], }, }, { diff --git a/test/integrations/destinations/pinterest_tag/step/data.ts b/test/integrations/destinations/pinterest_tag/step/data.ts index b607e3c9faf..8f0680a77c0 100644 --- a/test/integrations/destinations/pinterest_tag/step/data.ts +++ b/test/integrations/destinations/pinterest_tag/step/data.ts @@ -468,7 +468,9 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [ + { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, + ], }, }, JSON_ARRAY: {}, @@ -2420,7 +2422,9 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [{ quantity: 1, item_price: 'undefined' }], + contents: [ + { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, + ], }, }, JSON_ARRAY: {}, @@ -2685,7 +2689,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1 }], + contents: [{ item_name: 'undefined', item_price: 'undefined', quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3605,6 +3609,7 @@ export const data = [ num_items: 0, contents: [ { + item_name: 'undefined', quantity: 1, item_price: 'undefined', }, From f79dfe74b447b8ccd80287e143ff771688c510be Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Wed, 23 Oct 2024 12:39:17 +0530 Subject: [PATCH 067/147] feat: support for multiple zap urls (#3825) * feat: support for multiple zap urls * fix: update endpoint to array * fix: use forEach instead of map, remove unused dependency --------- Co-authored-by: Sai Sankeerth --- .../v2/destinations/zapier/procWorkflow.yaml | 20 +- src/cdk/v2/destinations/zapier/utils.js | 15 + .../destinations/zapier/processor/data.ts | 266 ++++++++++++++++++ 3 files changed, 288 insertions(+), 13 deletions(-) create mode 100644 src/cdk/v2/destinations/zapier/utils.js diff --git a/src/cdk/v2/destinations/zapier/procWorkflow.yaml b/src/cdk/v2/destinations/zapier/procWorkflow.yaml index c14c57378c4..d7a5429129a 100644 --- a/src/cdk/v2/destinations/zapier/procWorkflow.yaml +++ b/src/cdk/v2/destinations/zapier/procWorkflow.yaml @@ -1,10 +1,9 @@ bindings: - name: EventType path: ../../../../constants - - name: getHashFromArray + - name: getHashFromArrayWithDuplicate path: ../../../../v0/util/index - - name: defaultRequestConfig - path: ../../../../v0/util + - path: ./utils steps: - name: validateInput @@ -15,18 +14,18 @@ steps: - name: prepareContext template: | $.context.messageType = .message.type.toLowerCase(); - $.context.endpoint = .destination.Config.zapUrl; + $.context.endpoint = [.destination.Config.zapUrl]; - name: trackEndpoint condition: $.context.messageType === {{$.EventType.TRACK}} template: | - const trackEventsMap = $.getHashFromArray(.destination.Config.trackEventsToZap); + const trackEventsMap = $.getHashFromArrayWithDuplicate(.destination.Config.trackEventsToZap); const eventName = .message.event.toLowerCase(); (eventName && trackEventsMap[eventName]) ? ($.context.endpoint = trackEventsMap[eventName]) else: name: endpointForOthers template: | - const pageScreenEventsMap = $.getHashFromArray(.destination.Config.pageScreenEventsToZap); + const pageScreenEventsMap = $.getHashFromArrayWithDuplicate(.destination.Config.pageScreenEventsToZap); const pageName = .message.name.toLowerCase(); (pageName && pageScreenEventsMap[pageName]) ? ($.context.endpoint = pageScreenEventsMap[pageName]) @@ -37,10 +36,5 @@ steps: else: name: buildResponseForProcessTransformation template: | - const response = $.defaultRequestConfig(); - response.body.JSON = .message; - response.endpoint = $.context.endpoint; - response.headers = { - "content-type": "application/json" - }; - response + const responseList = $.buildResponseList(.message, $.context.endpoint) + responseList diff --git a/src/cdk/v2/destinations/zapier/utils.js b/src/cdk/v2/destinations/zapier/utils.js new file mode 100644 index 00000000000..43de6e58dd1 --- /dev/null +++ b/src/cdk/v2/destinations/zapier/utils.js @@ -0,0 +1,15 @@ +const { defaultRequestConfig } = require('../../../../v0/util'); + +const buildResponseList = (payload, endpointList) => { + const responseList = []; + endpointList.forEach((endpoint) => { + const response = defaultRequestConfig(); + response.body.JSON = payload; + response.endpoint = endpoint; + response.headers = { 'content-type': 'application/json' }; + responseList.push(response); + }); + return responseList; +}; + +module.exports = { buildResponseList }; diff --git a/test/integrations/destinations/zapier/processor/data.ts b/test/integrations/destinations/zapier/processor/data.ts index b938f68dc56..b4f5a2a8c57 100644 --- a/test/integrations/destinations/zapier/processor/data.ts +++ b/test/integrations/destinations/zapier/processor/data.ts @@ -643,6 +643,62 @@ export const data = [ response: { status: 200, body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'def.zap-hook', + headers: { + 'content-type': 'application/json', + }, + params: {}, + body: { + JSON: { + event: 'def', + userId: 'identified user id', + type: 'track', + anonymousId: 'anon-id-new', + context: { + traits: { + trait1: 'new-val', + }, + ip: '14.5.67.21', + library: { + name: 'http', + }, + }, + properties: { + abc: '123', + key: { + abc: 123, + }, + array: [ + { + abc: 123, + }, + { + def: 123, + }, + ], + }, + timestamp: '2020-02-02T00:23:09.544Z', + originalTimestamp: '2020-04-17T14:42:44.724Z', + sentAt: '2020-04-17T14:42:44.724Z', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, { output: { version: '1', @@ -703,4 +759,214 @@ export const data = [ }, }, }, + { + id: 'Test 5', + name: 'zapier', + description: 'Track call with Multiplexing', + scenario: 'Framework+Business', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + event: 'def', + userId: 'identified user id', + type: 'track', + anonymousId: 'anon-id-new', + timestamp: '2020-02-02T00:23:09.544Z', + originalTimestamp: '2020-04-17T14:42:44.724Z', + sentAt: '2020-04-17T14:42:44.724Z', + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + destination: { + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + zapUrl: 'abcd.zap-hook', + trackEventsToZap: [ + { + from: 'def', + to: ['def.zap-hook', 'ghi.zap-hook'], + }, + ], + pageScreenEventsToZap: [{}], + }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: ['def.zap-hook', 'ghi.zap-hook'], + headers: { + 'content-type': 'application/json', + }, + params: {}, + body: { + JSON: { + event: 'def', + userId: 'identified user id', + type: 'track', + anonymousId: 'anon-id-new', + timestamp: '2020-02-02T00:23:09.544Z', + originalTimestamp: '2020-04-17T14:42:44.724Z', + sentAt: '2020-04-17T14:42:44.724Z', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, + { + id: 'Test 6', + name: 'zapier', + description: 'Page call with Multiplexing', + scenario: 'Framework+Business', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + name: 'abc_page_test', + userId: 'identified user id', + type: 'page', + anonymousId: 'anon-id-new', + properties: { + abc: '123', + key: { + abc: 123, + }, + array: [ + { + abc: 123, + }, + { + def: 123, + }, + ], + }, + timestamp: '2020-02-02T00:23:09.544Z', + originalTimestamp: '2020-04-17T14:42:44.724Z', + sentAt: '2020-04-17T14:42:44.724Z', + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + destination: { + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + zapUrl: 'abcd.zap-hook', + trackEventsToZap: [{}], + pageScreenEventsToZap: [ + { + from: 'abc_page_test', + to: ['page.zap-hook', 'ghi.zap-hook'], + }, + ], + }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: ['page.zap-hook', 'ghi.zap-hook'], + headers: { + 'content-type': 'application/json', + }, + params: {}, + body: { + JSON: { + name: 'abc_page_test', + userId: 'identified user id', + type: 'page', + anonymousId: 'anon-id-new', + properties: { + abc: '123', + key: { + abc: 123, + }, + array: [ + { + abc: 123, + }, + { + def: 123, + }, + ], + }, + timestamp: '2020-02-02T00:23:09.544Z', + originalTimestamp: '2020-04-17T14:42:44.724Z', + sentAt: '2020-04-17T14:42:44.724Z', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, ]; From 8f18e1aca70ab68e3f157a4632d63ae7cec0e87b Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:24:11 +0530 Subject: [PATCH 068/147] fix: str replace is not a function error (#3799) * fix: str.replace is not a function * fix: resolving comments --- .../transform.js | 22 +- src/v0/util/index.js | 6 +- src/v0/util/index.test.js | 16 + .../router/data.ts | 307 ++++++++++++++++++ 4 files changed, 345 insertions(+), 6 deletions(-) diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 55d0c16c8cc..007f16d7f8e 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -1,8 +1,9 @@ /* eslint-disable no-param-reassign */ const get = require('get-value'); -const { cloneDeep } = require('lodash'); +const { cloneDeep, isNumber } = require('lodash'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); +const isString = require('lodash/isString'); const { constructPayload, defaultRequestConfig, @@ -35,7 +36,18 @@ const updateMappingJson = (mapping) => { const responseBuilder = async (metadata, message, { Config }, payload) => { const response = defaultRequestConfig(); const { event } = message; - const filteredCustomerId = removeHyphens(Config.customerId); + const { subAccount } = Config; + let { customerId, loginCustomerId } = Config; + if (isNumber(customerId)) { + customerId = customerId.toString(); + } + if (isNumber(loginCustomerId)) { + loginCustomerId = loginCustomerId.toString(); + } + if (!isString(customerId) || !isString(loginCustomerId)) { + throw new InstrumentationError('customerId and loginCustomerId should be a string or number'); + } + const filteredCustomerId = removeHyphens(customerId); response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}:uploadConversionAdjustments`; response.body.JSON = payload; const accessToken = getAccessToken(metadata, 'access_token'); @@ -45,9 +57,9 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { 'developer-token': getValueFromMessage(metadata, 'secret.developer_token'), }; response.params = { event, customerId: filteredCustomerId }; - if (Config.subAccount) - if (Config.loginCustomerId) { - const filteredLoginCustomerId = removeHyphens(Config.loginCustomerId); + if (subAccount) + if (loginCustomerId) { + const filteredLoginCustomerId = removeHyphens(loginCustomerId); response.headers['login-customer-id'] = filteredLoginCustomerId; } else throw new ConfigurationError(`LoginCustomerId is required as subAccount is true.`); diff --git a/src/v0/util/index.js b/src/v0/util/index.js index ca81262f88e..f034ab802b2 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -26,6 +26,7 @@ const { } = require('@rudderstack/integrations-lib'); const { JsonTemplateEngine, PathType } = require('@rudderstack/json-template-engine'); +const isString = require('lodash/isString'); const logger = require('../../logger'); const stats = require('../../util/stats'); const { DestCanonicalNames, DestHandlerMap } = require('../../constants/destinationCanonicalNames'); @@ -1622,7 +1623,7 @@ function isHttpStatusRetryable(status) { function generateUUID() { return crypto.randomUUID({ disableEntropyCache: true, - }); /* using disableEntropyCache as true to not cache the generated uuids. + }); /* using disableEntropyCache as true to not cache the generated uuids. For more Info https://nodejs.org/api/crypto.html#cryptorandomuuidoptions:~:text=options%20%3CObject%3E-,disableEntropyCache,-%3Cboolean%3E%20By */ } @@ -1646,6 +1647,9 @@ function isAppleFamily(platform) { } function removeHyphens(str) { + if (!isString(str)) { + return str; + } return str.replace(/-/g, ''); } diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 6bf689eca72..eaf8b79d54e 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -10,6 +10,7 @@ const { validateEventAndLowerCaseConversion, groupRouterTransformEvents, isAxiosError, + removeHyphens, } = require('./index'); const exp = require('constants'); @@ -968,3 +969,18 @@ describe('isAxiosError', () => { expect(isAxiosError(error)).toBe(false); }); }); + +describe('removeHyphens', () => { + const data = [ + { input: 'hello-w--orld', expected: 'helloworld' }, + { input: '', expected: '' }, + { input: null, expected: null }, + { input: undefined, expected: undefined }, + { input: 12345, expected: 12345 }, + ]; + it('should remove hyphens from string else return the input as it is', () => { + data.forEach(({ input, expected }) => { + expect(removeHyphens(input)).toBe(expected); + }); + }); +}); diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 1d77b5d7743..89ce06818b4 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -225,6 +225,194 @@ const events = [ sentAt: '2019-10-14T11:15:53.296Z', }, }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 4, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '{{event.context.customerID || "" }}', + subAccount: true, + loginCustomerId: '{{event.context.subaccountID || "" }}', + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: 1234567890, + subaccountID: 11, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 5, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '{{event.context.customerID || "" }}', + subAccount: true, + loginCustomerId: '{{event.context.subaccountID || "" }}', + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: {}, + subaccountID: 11, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, ]; const invalidRtTfCases = [ @@ -500,6 +688,125 @@ export const data = [ module: 'destination', }, }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '11', + }, + params: { event: 'Page View', customerId: '1234567890' }, + body: { + JSON: { + partialFailure: true, + conversionAdjustments: [ + { + gclidDateTimePair: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + }, + restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, + orderId: '10000', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + userIdentifiers: [ + { + hashedPhoneNumber: + '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', + }, + { + addressInfo: { + hashedFirstName: + 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', + hashedLastName: + '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', + state: 'UK', + city: 'London', + hashedStreetAddress: + '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + }, + }, + ], + adjustmentType: 'ENHANCEMENT', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 4, + userId: 'u1', + }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: 1234567890, + subAccount: true, + loginCustomerId: 11, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, + { + batched: false, + statusCode: 400, + error: 'customerId and loginCustomerId should be a string or number', + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 5, + userId: 'u1', + }, + ], + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: {}, + subAccount: true, + loginCustomerId: 11, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, ], }, }, From 3a091810bff12ae893c16b514c07d17e6374062a Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:40:46 +0530 Subject: [PATCH 069/147] feat: add support for identity stitching for shopify pixel flow (#3818) --- src/util/prometheus.js | 18 +++ src/v0/sources/shopify/util.js | 4 +- src/v1/sources/shopify/config.js | 13 ++ src/v1/sources/shopify/pixelTransform.js | 69 ++++++++++- .../pixelTransform.redisCartToken.test.js | 116 ++++++++++++++++++ 5 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/v1/sources/shopify/pixelTransform.redisCartToken.test.js diff --git a/src/util/prometheus.js b/src/util/prometheus.js index 27747faf4b3..c8dd55068be 100644 --- a/src/util/prometheus.js +++ b/src/util/prometheus.js @@ -439,6 +439,24 @@ class Prometheus { type: 'counter', labelNames: ['writeKey', 'source', 'shopifyTopic'], }, + { + name: 'shopify_pixel_cart_token_not_found', + help: 'shopify_pixel_cart_token_not_found', + type: 'counter', + labelNames: ['event', 'writeKey'], + }, + { + name: 'shopify_pixel_cart_token_set', + help: 'shopify_pixel_cart_token_set', + type: 'counter', + labelNames: ['event', 'writeKey'], + }, + { + name: 'shopify_pixel_cart_token_redis_error', + help: 'shopify_pixel_cart_token_redis_error', + type: 'counter', + labelNames: ['event', 'writeKey'], + }, { name: 'outgoing_request_count', help: 'Outgoing HTTP requests count', diff --git a/src/v0/sources/shopify/util.js b/src/v0/sources/shopify/util.js index 6d13d13bdf7..981832363e4 100644 --- a/src/v0/sources/shopify/util.js +++ b/src/v0/sources/shopify/util.js @@ -124,11 +124,11 @@ const extractEmailFromPayload = (event) => { }; const getCartToken = (message) => { - const { event, properties } = message; + const { event, properties, context } = message; if (event === SHOPIFY_TRACK_MAP.carts_update) { return properties?.id || properties?.token; } - return properties?.cart_token || null; + return properties?.cart_token || context?.cart_token || null; }; /** diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 5a3ce99b40c..57e7e168a18 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -1,6 +1,8 @@ const path = require('path'); const fs = require('fs'); +const commonCartTokenLocation = 'context.document.location.pathname'; + const PIXEL_EVENT_TOPICS = { CART_VIEWED: 'cart_viewed', PRODUCT_ADDED_TO_CART: 'product_added_to_cart', @@ -61,6 +63,16 @@ const checkoutStartedCompletedEventMappingJSON = JSON.parse( ), ); +const pixelEventToCartTokenLocationMapping = { + cart_viewed: 'properties.cart_id', + checkout_address_info_submitted: commonCartTokenLocation, + checkout_contact_info_submitted: commonCartTokenLocation, + checkout_shipping_info_submitted: commonCartTokenLocation, + payment_info_submitted: commonCartTokenLocation, + checkout_started: commonCartTokenLocation, + checkout_completed: commonCartTokenLocation, +}; + const INTEGERATION = 'SHOPIFY'; module.exports = { @@ -73,4 +85,5 @@ module.exports = { productViewedEventMappingJSON, productToCartEventMappingJSON, checkoutStartedCompletedEventMappingJSON, + pixelEventToCartTokenLocationMapping, }; diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index a19d431757b..e308f626b48 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -1,6 +1,11 @@ +/* eslint-disable no-param-reassign */ +// eslint-disable-next-line @typescript-eslint/naming-convention +const _ = require('lodash'); +const { isDefinedNotNullNotEmpty } = require('@rudderstack/integrations-lib'); const stats = require('../../../util/stats'); const logger = require('../../../logger'); const { removeUndefinedAndNullValues } = require('../../../v0/util'); +const { RedisDB } = require('../../../util/redis/redisConnector'); const { pageViewedEventBuilder, cartViewedEventBuilder, @@ -11,7 +16,11 @@ const { checkoutStepEventBuilder, searchEventBuilder, } = require('./pixelUtils'); -const { INTEGERATION, PIXEL_EVENT_TOPICS } = require('./config'); +const { + INTEGERATION, + PIXEL_EVENT_TOPICS, + pixelEventToCartTokenLocationMapping, +} = require('./config'); const NO_OPERATION_SUCCESS = { outputToSource: { @@ -21,6 +30,59 @@ const NO_OPERATION_SUCCESS = { statusCode: 200, }; +/** + * Parses and extracts cart token value from the input event + * @param {Object} inputEvent + * @returns {String} cartToken + */ +function extractCartToken(inputEvent) { + const cartTokenLocation = pixelEventToCartTokenLocationMapping[inputEvent.name]; + if (!cartTokenLocation) { + stats.increment('shopify_pixel_cart_token_not_found', { + event: inputEvent.name, + writeKey: inputEvent.query_parameters.writeKey, + }); + return undefined; + } + // the unparsedCartToken is a string like '/checkout/cn/1234' + const unparsedCartToken = _.get(inputEvent, cartTokenLocation); + if (typeof unparsedCartToken !== 'string') { + logger.error(`Cart token is not a string`); + stats.increment('shopify_pixel_cart_token_not_found', { + event: inputEvent.name, + writeKey: inputEvent.query_parameters.writeKey, + }); + return undefined; + } + const cartTokenParts = unparsedCartToken.split('/'); + const cartToken = cartTokenParts[3]; + return cartToken; +} + +/** + * Handles storing cart token and anonymousId (clientId) in Redis + * @param {Object} inputEvent + * @param {String} clientId + */ +const handleCartTokenRedisOperations = async (inputEvent, clientId) => { + const cartToken = extractCartToken(inputEvent); + try { + if (isDefinedNotNullNotEmpty(clientId) && isDefinedNotNullNotEmpty(cartToken)) { + await RedisDB.setVal(cartToken, ['anonymousId', clientId]); + stats.increment('shopify_pixel_cart_token_set', { + event: inputEvent.name, + writeKey: inputEvent.query_parameters.writeKey, + }); + } + } catch (error) { + logger.error(`Error handling Redis operations for event: ${inputEvent.name}`, error); + stats.increment('shopify_pixel_cart_token_redis_error', { + event: inputEvent.name, + writeKey: inputEvent.query_parameters.writeKey, + }); + } +}; + function processPixelEvent(inputEvent) { // eslint-disable-next-line @typescript-eslint/naming-convention const { name, query_parameters, clientId, data, id } = inputEvent; @@ -37,6 +99,7 @@ function processPixelEvent(inputEvent) { message = pageViewedEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.CART_VIEWED: + handleCartTokenRedisOperations(inputEvent, clientId); message = cartViewedEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: @@ -52,6 +115,7 @@ function processPixelEvent(inputEvent) { case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: if (customer.id) message.userId = customer.id || ''; + handleCartTokenRedisOperations(inputEvent, clientId); message = checkoutEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: @@ -59,6 +123,7 @@ function processPixelEvent(inputEvent) { case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: if (customer.id) message.userId = customer.id || ''; + handleCartTokenRedisOperations(inputEvent, clientId); message = checkoutStepEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: @@ -94,4 +159,6 @@ const processEventFromPixel = async (event) => { module.exports = { processEventFromPixel, + handleCartTokenRedisOperations, + extractCartToken, }; diff --git a/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js b/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js new file mode 100644 index 00000000000..8f54efc3735 --- /dev/null +++ b/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js @@ -0,0 +1,116 @@ +const { extractCartToken, handleCartTokenRedisOperations } = require('./pixelTransform'); +const { RedisDB } = require('../../../util/redis/redisConnector'); +const stats = require('../../../util/stats'); +const logger = require('../../../logger'); +const { pixelEventToCartTokenLocationMapping } = require('./config'); + +jest.mock('../../../util/redis/redisConnector', () => ({ + RedisDB: { + setVal: jest.fn(), + }, +})); + +jest.mock('../../../util/stats', () => ({ + increment: jest.fn(), +})); + +jest.mock('../../../logger', () => ({ + info: jest.fn(), + error: jest.fn(), +})); + +jest.mock('./config', () => ({ + pixelEventToCartTokenLocationMapping: { cart_viewed: 'properties.cart_id' }, +})); + +describe('extractCartToken', () => { + it('should return undefined if cart token location is not found', () => { + const inputEvent = { name: 'unknownEvent', query_parameters: { writeKey: 'testWriteKey' } }; + + const result = extractCartToken(inputEvent); + + expect(result).toBeUndefined(); + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_not_found', { + event: 'unknownEvent', + writeKey: 'testWriteKey', + }); + }); + + it('should return undefined if cart token is not a string', () => { + const inputEvent = { + name: 'cart_viewed', + properties: { cart_id: 12345 }, + query_parameters: { writeKey: 'testWriteKey' }, + }; + + const result = extractCartToken(inputEvent); + + expect(result).toBeUndefined(); + expect(logger.error).toHaveBeenCalledWith('Cart token is not a string'); + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_not_found', { + event: 'cart_viewed', + writeKey: 'testWriteKey', + }); + }); + + it('should return the cart token if it is a valid string', () => { + const inputEvent = { + name: 'cart_viewed', + properties: { cart_id: '/checkout/cn/1234' }, + query_parameters: { writeKey: 'testWriteKey' }, + }; + + const result = extractCartToken(inputEvent); + + expect(result).toBe('1234'); + }); +}); + +describe('handleCartTokenRedisOperations', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should handle undefined or null cart token gracefully', async () => { + const inputEvent = { + name: 'unknownEvent', + query_parameters: { + writeKey: 'testWriteKey', + }, + }; + const clientId = 'testClientId'; + + await handleCartTokenRedisOperations(inputEvent, clientId); + + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_not_found', { + event: 'unknownEvent', + writeKey: 'testWriteKey', + }); + }); + + it('should log error and increment stats when exception occurs', async () => { + const inputEvent = { + name: 'cart_viewed', + properties: { + cart_id: '/checkout/cn/1234', + }, + query_parameters: { + writeKey: 'testWriteKey', + }, + }; + const clientId = 'testClientId'; + const error = new Error('Redis error'); + RedisDB.setVal.mockRejectedValue(error); + + await handleCartTokenRedisOperations(inputEvent, clientId); + + expect(logger.error).toHaveBeenCalledWith( + 'Error handling Redis operations for event: cart_viewed', + error, + ); + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_redis_error', { + event: 'cart_viewed', + writeKey: 'testWriteKey', + }); + }); +}); From dc5d3cf0a625478a98667e2feca40d52e57a6cdb Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 25 Oct 2024 10:06:09 +0000 Subject: [PATCH 070/147] chore(release): 1.83.0 --- CHANGELOG.md | 21 +++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d972f67c3..bcfd6f2835b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.83.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.2...v1.83.0) (2024-10-25) + + +### Features + +* add support for identity stitching for shopify pixel flow ([#3818](https://github.com/rudderlabs/rudder-transformer/issues/3818)) ([3a09181](https://github.com/rudderlabs/rudder-transformer/commit/3a091810bff12ae893c16b514c07d17e6374062a)) +* onboard tune destination ([#3795](https://github.com/rudderlabs/rudder-transformer/issues/3795)) ([741f0c6](https://github.com/rudderlabs/rudder-transformer/commit/741f0c6d6714cf760ce98cc9354b61f7b5ce4684)) +* snowpipe streaming ([#3740](https://github.com/rudderlabs/rudder-transformer/issues/3740)) ([21b1039](https://github.com/rudderlabs/rudder-transformer/commit/21b1039c26067b4896a15adf8b10a044e69cb495)) +* support for multiple zap urls ([#3825](https://github.com/rudderlabs/rudder-transformer/issues/3825)) ([f79dfe7](https://github.com/rudderlabs/rudder-transformer/commit/f79dfe74b447b8ccd80287e143ff771688c510be)) + + +### Bug Fixes + +* add missing field for pinterest_tag single product events ([f781a84](https://github.com/rudderlabs/rudder-transformer/commit/f781a84ade98649d68cebf4da13c2ceff8df2df2)) +* add missing field for pinterest_tag single product events ([#3826](https://github.com/rudderlabs/rudder-transformer/issues/3826)) ([4a63277](https://github.com/rudderlabs/rudder-transformer/commit/4a63277efd0b4357d8321618640d1a0ba2a47d71)) +* heap userId extraction ([#3801](https://github.com/rudderlabs/rudder-transformer/issues/3801)) ([e578413](https://github.com/rudderlabs/rudder-transformer/commit/e57841396ad666d716e195fbd4e9b74a63bf5191)) +* not allowing empty string or null values for mandatory fields in zoho ([#3800](https://github.com/rudderlabs/rudder-transformer/issues/3800)) ([fcd8d99](https://github.com/rudderlabs/rudder-transformer/commit/fcd8d997fe815d61d21ffff235b0799e69b7ded9)) +* populate source destination info env set properly ([#3806](https://github.com/rudderlabs/rudder-transformer/issues/3806)) ([d730daf](https://github.com/rudderlabs/rudder-transformer/commit/d730dafbbd2de30b67c35db8ca05396a98a8d2e0)) +* str replace is not a function error ([#3799](https://github.com/rudderlabs/rudder-transformer/issues/3799)) ([8f18e1a](https://github.com/rudderlabs/rudder-transformer/commit/8f18e1aca70ab68e3f157a4632d63ae7cec0e87b)) +* update order_id in checkout events, messageId in pixel events ([#3794](https://github.com/rudderlabs/rudder-transformer/issues/3794)) ([427be71](https://github.com/rudderlabs/rudder-transformer/commit/427be71a91df8495f81b42d2b58aa490db439b23)) + ### [1.82.2](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.1...v1.82.2) (2024-10-18) diff --git a/package-lock.json b/package-lock.json index 77cc67cc720..ccf7ed2c2ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.82.2", + "version": "1.83.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.82.2", + "version": "1.83.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index f87249e77c8..79571462d3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.82.2", + "version": "1.83.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From e9c5a755e6ff2d46aafcc3c6117871c42d750ace Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:14:39 +0530 Subject: [PATCH 071/147] chore: allow only mapped in properties, update event name (#3830) * chore: allow only mapped in properties, update event name * chore: remove redundant checks * chore: add jsdoc descriptions * chore: address comments --- src/v1/sources/shopify/config.js | 2 +- src/v1/sources/shopify/pixelUtils.js | 58 +- src/v1/sources/shopify/pixelUtils.test.js | 636 ++++++++++++++++-- .../pixelTestScenarios/CheckoutEventsTests.ts | 29 +- .../pixelTestScenarios/ProductEventsTests.ts | 150 ----- 5 files changed, 631 insertions(+), 244 deletions(-) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 57e7e168a18..5d88353d60c 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -27,7 +27,7 @@ const PIXEL_EVENT_MAPPING = { product_viewed: 'Product Viewed', collection_viewed: 'Collection Viewed', checkout_started: 'Checkout Started', - checkout_completed: 'Checkout Completed', + checkout_completed: 'Order Completed', checkout_address_info_submitted: 'Checkout Address Info Submitted', checkout_contact_info_submitted: 'Checkout Contact Info Submitted', checkout_shipping_info_submitted: 'Checkout Shipping Info Submitted', diff --git a/src/v1/sources/shopify/pixelUtils.js b/src/v1/sources/shopify/pixelUtils.js index 4c39e805496..9abef5c2f85 100644 --- a/src/v1/sources/shopify/pixelUtils.js +++ b/src/v1/sources/shopify/pixelUtils.js @@ -30,10 +30,14 @@ function setNestedValue(object, path, value) { }, object); } -function mapObjectKeys(sourceObject, keyMappings) { - if (!Array.isArray(keyMappings)) { - throw new TypeError('keyMappings should be an array'); - } +/* + * Creates a copy of the source object with the keys mapped to the destination keys + * Keys that are not present in the mapping will be copied as is + * @param {Object} sourceObject + * @param {Array} keyMappings + * @returns {Object} resultObject + */ +function mapContextObjectKeys(sourceObject, keyMappings) { const resultObject = { ...sourceObject }; // eslint-disable-next-line @typescript-eslint/no-shadow @@ -46,10 +50,31 @@ function mapObjectKeys(sourceObject, keyMappings) { }, resultObject); } +/* + * Maps the keys of the source object to the destination object + * Only the keys that are present in the mapping will be copied + * @param {Object} sourceObject + * @param {Array} keyMappings + * @returns {Object} trackProperties + */ +function mapObjectKeys(sourceObject, keyMappings) { + const trackProperties = {}; + + keyMappings.forEach(({ sourceKeys, destKeys }) => { + const value = getNestedValue(sourceObject, sourceKeys); + if (value !== undefined) { + setNestedValue(trackProperties, destKeys, value); + } + }); + + return trackProperties; +} + const createMessage = (eventType, eventName, properties, context) => { const message = new Message(INTEGERATION); message.setEventType(eventType); - message.setEventName(eventName); + if (eventType === EventType.TRACK) message.setEventName(eventName); + else message.name = eventName; message.properties = properties; message.context = context; return message; @@ -57,13 +82,8 @@ const createMessage = (eventType, eventName, properties, context) => { const pageViewedEventBuilder = (inputEvent) => { const { data, context } = inputEvent; - const pageEventContextValues = mapObjectKeys(context, contextualFieldMappingJSON); - const message = new Message(INTEGERATION); - message.name = 'Page View'; - message.setEventType(EventType.PAGE); - message.properties = { ...data }; - message.context = { ...pageEventContextValues }; - return message; + const pageEventContextValues = mapContextObjectKeys(context, contextualFieldMappingJSON); + return createMessage(EventType.PAGE, 'Page View', { ...data }, pageEventContextValues); }; const cartViewedEventBuilder = (inputEvent) => { @@ -83,7 +103,7 @@ const cartViewedEventBuilder = (inputEvent) => { cart_id: inputEvent.data.cart.id, total, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage(EventType.TRACK, 'Cart Viewed', properties, contextualPayload); }; @@ -102,7 +122,7 @@ const productListViewedEventBuilder = (inputEvent) => { products, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage(EventType.TRACK, 'Product List Viewed', properties, contextualPayload); }; @@ -110,7 +130,7 @@ const productViewedEventBuilder = (inputEvent) => { const properties = { ...mapObjectKeys(inputEvent.data, productViewedEventMappingJSON), }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage(EventType.TRACK, 'Product Viewed', properties, contextualPayload); }; @@ -118,7 +138,7 @@ const productToCartEventBuilder = (inputEvent) => { const properties = { ...mapObjectKeys(inputEvent.data, productToCartEventMappingJSON), }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage( EventType.TRACK, PIXEL_EVENT_MAPPING[inputEvent.name], @@ -148,7 +168,7 @@ const checkoutEventBuilder = (inputEvent) => { value: inputEvent?.data?.checkout?.totalPrice?.amount, tax: inputEvent?.data?.checkout?.totalTax?.amount, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage( EventType.TRACK, PIXEL_EVENT_MAPPING[inputEvent.name], @@ -158,7 +178,7 @@ const checkoutEventBuilder = (inputEvent) => { }; const checkoutStepEventBuilder = (inputEvent) => { - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); const properties = { ...inputEvent.data.checkout, }; @@ -174,7 +194,7 @@ const searchEventBuilder = (inputEvent) => { const properties = { query: inputEvent.data.searchResult.query, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const contextualPayload = mapContextObjectKeys(inputEvent.context, contextualFieldMappingJSON); return createMessage( EventType.TRACK, PIXEL_EVENT_MAPPING[inputEvent.name], diff --git a/src/v1/sources/shopify/pixelUtils.test.js b/src/v1/sources/shopify/pixelUtils.test.js index ed648622281..4bff8eada4c 100644 --- a/src/v1/sources/shopify/pixelUtils.test.js +++ b/src/v1/sources/shopify/pixelUtils.test.js @@ -82,21 +82,6 @@ describe('utilV2.js', () => { price: 629.95, quantity: 2, variant: 'The Multi-managed Snowboard', - merchandise: { - id: '41327143157873', - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - title: 'The Multi-managed Snowboard', - }, - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - cost: { - totalAmount: { amount: 1259.9, currencyCode: 'USD' }, - }, }, ], cart_id: '123', @@ -112,8 +97,27 @@ describe('utilV2.js', () => { data: { collection: { productVariants: [ - { id: 'product123', name: 'Product 123' }, - { id: 'product456', name: 'Product 456' }, + { + price: { + amount: 10, + currencyCode: 'USD', + }, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + }, ], }, }, @@ -127,8 +131,17 @@ describe('utilV2.js', () => { cart_id: 'client123', list_id: 'list123', products: [ - { id: 'product123', name: 'Product 123' }, - { id: 'product456', name: 'Product 456' }, + { + brand: 'Snowboard Vendor', + category: 'giftcard', + image_url: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + name: '$10', + price: 10, + product_id: '7234590605425', + sku: '', + url: '/products/gift-card', + variant: 'Gift Card', + }, ], }); expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); @@ -138,12 +151,43 @@ describe('utilV2.js', () => { describe('productViewedEventBuilder', () => { it('should build a product viewed event message', () => { const inputEvent = { - data: { id: 'product123', name: 'Product 123' }, + data: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + }, context: { userAgent: 'Mozilla/5.0' }, }; const message = productViewedEventBuilder(inputEvent); expect(message).toBeInstanceOf(Message); - expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.properties).toEqual({ + brand: 'Hydrogen Vendor', + category: 'snowboard', + currency: 'USD', + name: 'The Collection Snowboard: Liquid', + price: 749.95, + product_id: '7234590834801', + url: '/products/the-collection-snowboard-liquid', + variant: 'The Collection Snowboard: Liquid', + }); expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); }); }); @@ -151,13 +195,56 @@ describe('utilV2.js', () => { describe('productToCartEventBuilder', () => { it('should build a product to cart event message', () => { const inputEvent = { - data: { id: 'product123', name: 'Product 123' }, + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, context: { userAgent: 'Mozilla/5.0' }, name: 'add_to_cart', }; const message = productToCartEventBuilder(inputEvent); expect(message).toBeInstanceOf(Message); - expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.properties).toEqual({ + brand: 'Hydrogen Vendor', + category: 'snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + name: null, + price: 749.95, + product_id: '7234590834801', + quantity: 1, + sku: '', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + variant: 'The Collection Snowboard: Liquid', + }); expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); }); }); @@ -167,20 +254,128 @@ describe('utilV2.js', () => { const inputEvent = { data: { checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', lineItems: [ - { id: 'product123', name: 'Product 123' }, - { id: 'product456', name: 'Product 456' }, + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, order: { - id: 'order123', + id: null, + customer: { + id: null, + isFirstOrder: null, + }, }, - token: 'checkout123', - totalPrice: { amount: 200 }, - currencyCode: 'USD', - discountsAmount: { amount: 10 }, - shippingLine: { price: { amount: 5 } }, - subtotalPrice: { amount: 185 }, - totalTax: { amount: 15 }, + delivery: { + selectedDeliveryOptions: [], + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], }, }, id: 'order123', @@ -191,18 +386,42 @@ describe('utilV2.js', () => { expect(message).toBeInstanceOf(Message); expect(message.properties).toEqual({ products: [ - { id: 'product123', name: 'Product 123' }, - { id: 'product456', name: 'Product 456' }, + { + brand: 'Hydrogen Vendor', + category: 'snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + name: 'The Collection Snowboard: Liquid', + price: 749.95, + product_id: '7234590834801', + quantity: 2, + sku: null, + url: '/products/the-collection-snowboard-liquid', + variant: 'The Collection Snowboard: Liquid', + }, + { + brand: 'Multi-managed Vendor', + category: 'snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + name: 'The Multi-managed Snowboard', + price: 629.95, + product_id: '7234590736497', + quantity: 2, + sku: 'sku-managed-1', + url: '/products/the-multi-managed-snowboard', + variant: 'The Multi-managed Snowboard', + }, ], - order_id: 'order123', - checkout_id: 'checkout123', - total: 200, + order_id: null, + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, currency: 'USD', - discount: 10, - shipping: 5, - revenue: 185, - value: 200, - tax: 15, + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, }); expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); }); @@ -213,8 +432,169 @@ describe('utilV2.js', () => { const inputEvent = { data: { checkout: { - step: 1, - action: 'shipping_info_submitted', + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], }, }, context: { userAgent: 'Mozilla/5.0' }, @@ -222,7 +602,171 @@ describe('utilV2.js', () => { }; const message = checkoutStepEventBuilder(inputEvent); expect(message).toBeInstanceOf(Message); - expect(message.properties).toEqual({ step: 1, action: 'shipping_info_submitted' }); + expect(message.properties).toEqual({ + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + currencyCode: 'USD', + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + lineItems: [ + { + discountAllocations: [], + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + id: '41327143321713', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + vendor: 'Hydrogen Vendor', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + }, + { + discountAllocations: [], + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + id: '41327143157873', + properties: [], + quantity: 2, + sellingPlanAllocation: null, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + vendor: 'Multi-managed Vendor', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + handle: 'us', + id: 'gid://shopify/Market/23505895537', + }, + }, + order: { + customer: { + id: null, + isFirstOrder: null, + }, + id: null, + }, + phone: '', + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + transactions: [], + }); expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); }); }); diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts index 3381223317c..ff1ea39ed13 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts @@ -342,17 +342,8 @@ export const pixelCheckoutEventsTestScenarios = [ properties: { products: [ { - discountAllocations: [], - id: '41327143321713', quantity: 2, - title: 'The Collection Snowboard: Liquid', variant: 'The Collection Snowboard: Liquid', - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], name: 'The Collection Snowboard: Liquid', image_url: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', @@ -786,21 +777,12 @@ export const pixelCheckoutEventsTestScenarios = [ SHOPIFY: true, }, type: 'track', - event: 'Checkout Completed', + event: 'Order Completed', properties: { products: [ { - discountAllocations: [], - id: '41327143321713', quantity: 2, - title: 'The Collection Snowboard: Liquid', variant: 'The Collection Snowboard: Liquid', - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], name: 'The Collection Snowboard: Liquid', image_url: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', @@ -812,17 +794,8 @@ export const pixelCheckoutEventsTestScenarios = [ brand: 'Hydrogen Vendor', }, { - discountAllocations: [], - id: '41327143157873', quantity: 2, - title: 'The Multi-managed Snowboard', variant: 'The Multi-managed Snowboard', - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], name: 'The Multi-managed Snowboard', image_url: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', diff --git a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts index b293bd46f95..46bd4f96151 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts @@ -170,27 +170,6 @@ export const pixelEventsTestScenarios = [ type: 'track', event: 'Product Viewed', properties: { - productVariant: { - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - id: '7234590834801', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - type: 'snowboard', - }, - id: '41327143321713', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - sku: '', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, product_id: '7234590834801', variant: 'The Collection Snowboard: Liquid', brand: 'Hydrogen Vendor', @@ -357,33 +336,6 @@ export const pixelEventsTestScenarios = [ properties: { products: [ { - cost: { - totalAmount: { - amount: 1259.9, - currencyCode: 'USD', - }, - }, - merchandise: { - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - id: '7234590736497', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - type: 'snowboard', - }, - id: '41327143157873', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', - }, - sku: 'sku-managed-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, quantity: 2, product_id: '7234590736497', variant: 'The Multi-managed Snowboard', @@ -612,21 +564,7 @@ export const pixelEventsTestScenarios = [ products: [ { price: 10, - product: { - title: 'Gift Card', - vendor: 'Snowboard Vendor', - id: '7234590605425', - untranslatedTitle: 'Gift Card', - url: '/products/gift-card', - type: 'giftcard', - }, - id: '41327142895729', - image: { - src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', - }, sku: '', - title: '$10', - untranslatedTitle: '$10', image_url: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', product_id: '7234590605425', @@ -638,21 +576,7 @@ export const pixelEventsTestScenarios = [ }, { price: 24.95, - product: { - title: 'Selling Plans Ski Wax', - vendor: 'pixel-testing-rs', - id: '7234590802033', - untranslatedTitle: 'Selling Plans Ski Wax', - url: '/products/selling-plans-ski-wax', - type: 'accessories', - }, - id: '41327143223409', - image: { - src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', - }, sku: '', - title: 'Selling Plans Ski Wax', - untranslatedTitle: 'Selling Plans Ski Wax', image_url: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', product_id: '7234590802033', @@ -664,21 +588,7 @@ export const pixelEventsTestScenarios = [ }, { price: 2629.95, - product: { - title: 'The 3p Fulfilled Snowboard', - vendor: 'pixel-testing-rs', - id: '7234590703729', - untranslatedTitle: 'The 3p Fulfilled Snowboard', - url: '/products/the-3p-fulfilled-snowboard', - type: 'snowboard', - }, - id: '41327143125105', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', - }, sku: 'sku-hosted-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', image_url: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', product_id: '7234590703729', @@ -819,36 +729,6 @@ export const pixelEventsTestScenarios = [ type: 'track', event: 'Product Added', properties: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, image_url: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', price: 749.95, @@ -990,36 +870,6 @@ export const pixelEventsTestScenarios = [ type: 'track', event: 'Product Removed', properties: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, image_url: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', price: 749.95, From a0eb8e90d8dff3ae44800abfb23d59ed3dedc6fc Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:52:18 +0530 Subject: [PATCH 072/147] fix: endpoint fix for tune destination (#3833) * feat: endpoint fix for tune destination * chore: minor fix --- src/v0/destinations/tune/transform.js | 8 ++++++-- .../destinations/tune/processor/trackTestData.ts | 4 ++-- test/integrations/destinations/tune/router/data.ts | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/v0/destinations/tune/transform.js b/src/v0/destinations/tune/transform.js index 97dad0e3d38..8103b4d2dcf 100644 --- a/src/v0/destinations/tune/transform.js +++ b/src/v0/destinations/tune/transform.js @@ -8,6 +8,8 @@ const { isNotEmpty, } = require('../../util'); +const getTuneEndpoint = (subdomain) => `https://${subdomain}.go2cloud.org/aff_l`; + const mapPropertiesWithNestedSupport = (msg, properties, mappings) => { const mappedObj = {}; // Create a new object for parameters Object.entries(mappings).forEach(([key, value]) => { @@ -26,7 +28,7 @@ const mapPropertiesWithNestedSupport = (msg, properties, mappings) => { }; const responseBuilder = (message, { Config }) => { - const { tuneEvents } = Config; // Extract tuneEvents from config + const { tuneEvents, subdomain } = Config; // Extract tuneEvents from config const { properties, event: messageEvent } = message; // Destructure properties and event from message // Find the relevant tune event based on the message's event name @@ -43,10 +45,12 @@ const responseBuilder = (message, { Config }) => { ...mapPropertiesWithNestedSupport(message, properties, advUniqueIdHashMap), }; + const endpoint = getTuneEndpoint(subdomain); + // Prepare the response const response = defaultRequestConfig(); response.params = params; // Set only the mapped params - response.endpoint = tuneEvent.url; // Use the user-defined URL + response.endpoint = endpoint; return response; } diff --git a/test/integrations/destinations/tune/processor/trackTestData.ts b/test/integrations/destinations/tune/processor/trackTestData.ts index c19ffdd84cb..63178d0e339 100644 --- a/test/integrations/destinations/tune/processor/trackTestData.ts +++ b/test/integrations/destinations/tune/processor/trackTestData.ts @@ -20,12 +20,12 @@ const destination: Destination = { connectionMode: { web: 'cloud', }, + subdomain: 'demo', consentManagement: {}, oneTrustCookieCategories: {}, ketchConsentPurposes: {}, tuneEvents: [ { - url: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', eventName: 'Product added', standardMapping: [ { to: 'aff_id', from: 'affId' }, @@ -89,7 +89,7 @@ export const trackTestdata: ProcessorTestData[] = [ { output: transformResultBuilder({ method: 'POST', - endpoint: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + endpoint: 'https://demo.go2cloud.org/aff_l', event: 'Product added', headers: {}, params: { diff --git a/test/integrations/destinations/tune/router/data.ts b/test/integrations/destinations/tune/router/data.ts index 65bfee4ade5..f21714d0580 100644 --- a/test/integrations/destinations/tune/router/data.ts +++ b/test/integrations/destinations/tune/router/data.ts @@ -15,12 +15,12 @@ const destination: Destination = { connectionMode: { web: 'cloud', }, + subdomain: 'demo', consentManagement: {}, oneTrustCookieCategories: {}, ketchConsentPurposes: {}, tuneEvents: [ { - url: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', eventName: 'Product added', standardMapping: [ { to: 'aff_id', from: 'affId' }, @@ -92,7 +92,7 @@ export const data: RouterTestData[] = [ version: '1', type: 'REST', method: 'POST', - endpoint: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029', + endpoint: 'https://demo.go2cloud.org/aff_l', headers: {}, params: { security_token: '1123', From 386b8c2c13d1b10d4267e1b62c312b49ba7e480d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:52:38 +0530 Subject: [PATCH 073/147] chore(deps): bump docker/setup-buildx-action from 3.6.1 to 3.7.1 (#3787) --- .github/workflows/build-push-docker-image.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index acc06496c27..c73469907c5 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -98,7 +98,7 @@ jobs: fetch-depth: 1 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Login to DockerHub uses: docker/login-action@v3.3.0 @@ -151,7 +151,7 @@ jobs: fetch-depth: 1 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Login to DockerHub uses: docker/login-action@v3.3.0 @@ -199,7 +199,7 @@ jobs: steps: - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.6.1 + uses: docker/setup-buildx-action@v3.7.1 - name: Login to DockerHub uses: docker/login-action@v3.3.0 From 34a2dfac095639321bd495ca5850fec60128bce0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:53:51 +0530 Subject: [PATCH 074/147] chore(deps): bump codecov/codecov-action from 4.0.1 to 4.6.0 (#3788) --- .github/workflows/dt-test-and-report-code-coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 86963b62703..33b9d881d97 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -58,14 +58,14 @@ jobs: npm run lint:fix - name: Upload Coverage Reports to Codecov - uses: codecov/codecov-action@v4.0.1 + uses: codecov/codecov-action@v4.6.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: directory: ./reports/coverage - name: Upload TS Coverage Reports to Codecov - uses: codecov/codecov-action@v4.0.1 + uses: codecov/codecov-action@v4.6.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: From ba694a5b38c2382981a4fc4e81b29c9672574534 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:55:17 +0530 Subject: [PATCH 075/147] chore(deps): bump docker/build-push-action from 6.7.0 to 6.9.0 (#3789) --- .github/workflows/build-push-docker-image.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index c73469907c5..c7e59dce86a 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -107,7 +107,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} - name: Build Docker Image - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 with: context: . file: ${{ inputs.dockerfile }} @@ -124,7 +124,7 @@ jobs: docker run ${{ inputs.build_tag }} npm run test:ts:ci - name: Build and Push Multi-platform Images - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 with: context: . file: ${{ inputs.dockerfile }} @@ -160,7 +160,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} - name: Build Docker Image - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 with: context: . file: ${{ inputs.dockerfile }} @@ -177,7 +177,7 @@ jobs: docker run ${{ inputs.build_tag }} npm run test:ts:ci - name: Build and Push Multi-platform Images - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.9.0 with: context: . file: ${{ inputs.dockerfile }} From d7be16508ba6b2d3ec004f70394ded8e9769eadb Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Fri, 1 Nov 2024 22:08:58 +0530 Subject: [PATCH 076/147] Revert "fix: str replace is not a function error (#3799)" (#3839) This reverts commit 8f18e1aca70ab68e3f157a4632d63ae7cec0e87b. --- .../transform.js | 22 +- src/v0/util/index.js | 6 +- src/v0/util/index.test.js | 16 - .../router/data.ts | 307 ------------------ 4 files changed, 6 insertions(+), 345 deletions(-) diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 007f16d7f8e..55d0c16c8cc 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -1,9 +1,8 @@ /* eslint-disable no-param-reassign */ const get = require('get-value'); -const { cloneDeep, isNumber } = require('lodash'); +const { cloneDeep } = require('lodash'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); -const isString = require('lodash/isString'); const { constructPayload, defaultRequestConfig, @@ -36,18 +35,7 @@ const updateMappingJson = (mapping) => { const responseBuilder = async (metadata, message, { Config }, payload) => { const response = defaultRequestConfig(); const { event } = message; - const { subAccount } = Config; - let { customerId, loginCustomerId } = Config; - if (isNumber(customerId)) { - customerId = customerId.toString(); - } - if (isNumber(loginCustomerId)) { - loginCustomerId = loginCustomerId.toString(); - } - if (!isString(customerId) || !isString(loginCustomerId)) { - throw new InstrumentationError('customerId and loginCustomerId should be a string or number'); - } - const filteredCustomerId = removeHyphens(customerId); + const filteredCustomerId = removeHyphens(Config.customerId); response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}:uploadConversionAdjustments`; response.body.JSON = payload; const accessToken = getAccessToken(metadata, 'access_token'); @@ -57,9 +45,9 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { 'developer-token': getValueFromMessage(metadata, 'secret.developer_token'), }; response.params = { event, customerId: filteredCustomerId }; - if (subAccount) - if (loginCustomerId) { - const filteredLoginCustomerId = removeHyphens(loginCustomerId); + if (Config.subAccount) + if (Config.loginCustomerId) { + const filteredLoginCustomerId = removeHyphens(Config.loginCustomerId); response.headers['login-customer-id'] = filteredLoginCustomerId; } else throw new ConfigurationError(`LoginCustomerId is required as subAccount is true.`); diff --git a/src/v0/util/index.js b/src/v0/util/index.js index f034ab802b2..ca81262f88e 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -26,7 +26,6 @@ const { } = require('@rudderstack/integrations-lib'); const { JsonTemplateEngine, PathType } = require('@rudderstack/json-template-engine'); -const isString = require('lodash/isString'); const logger = require('../../logger'); const stats = require('../../util/stats'); const { DestCanonicalNames, DestHandlerMap } = require('../../constants/destinationCanonicalNames'); @@ -1623,7 +1622,7 @@ function isHttpStatusRetryable(status) { function generateUUID() { return crypto.randomUUID({ disableEntropyCache: true, - }); /* using disableEntropyCache as true to not cache the generated uuids. + }); /* using disableEntropyCache as true to not cache the generated uuids. For more Info https://nodejs.org/api/crypto.html#cryptorandomuuidoptions:~:text=options%20%3CObject%3E-,disableEntropyCache,-%3Cboolean%3E%20By */ } @@ -1647,9 +1646,6 @@ function isAppleFamily(platform) { } function removeHyphens(str) { - if (!isString(str)) { - return str; - } return str.replace(/-/g, ''); } diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index eaf8b79d54e..6bf689eca72 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -10,7 +10,6 @@ const { validateEventAndLowerCaseConversion, groupRouterTransformEvents, isAxiosError, - removeHyphens, } = require('./index'); const exp = require('constants'); @@ -969,18 +968,3 @@ describe('isAxiosError', () => { expect(isAxiosError(error)).toBe(false); }); }); - -describe('removeHyphens', () => { - const data = [ - { input: 'hello-w--orld', expected: 'helloworld' }, - { input: '', expected: '' }, - { input: null, expected: null }, - { input: undefined, expected: undefined }, - { input: 12345, expected: 12345 }, - ]; - it('should remove hyphens from string else return the input as it is', () => { - data.forEach(({ input, expected }) => { - expect(removeHyphens(input)).toBe(expected); - }); - }); -}); diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 89ce06818b4..1d77b5d7743 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -225,194 +225,6 @@ const events = [ sentAt: '2019-10-14T11:15:53.296Z', }, }, - { - metadata: { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 4, - userId: 'u1', - }, - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: '{{event.context.customerID || "" }}', - subAccount: true, - loginCustomerId: '{{event.context.subaccountID || "" }}', - listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], - authStatus: 'active', - }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { - phone: '912382193', - firstName: 'John', - lastName: 'Gomes', - city: 'London', - state: 'UK', - streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, - customerID: 1234567890, - subaccountID: 11, - }, - event: 'Page View', - type: 'track', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - adjustedValue: '10', - currency: 'INR', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - partialFailure: true, - campaignId: '1', - templateId: '0', - order_id: 10000, - total: 1000, - products: [ - { - product_id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - price: '19', - position: '1', - category: 'cars', - url: 'https://www.example.com/product/path', - image_url: 'https://www.example.com/product/path.jpg', - quantity: '2', - }, - { - product_id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - price: '192', - quantity: 22, - position: '12', - category: 'Cars2', - url: 'https://www.example.com/product/path2', - image_url: 'https://www.example.com/product/path.jpg2', - }, - ], - }, - integrations: { All: true }, - name: 'ApplicationLoaded', - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, - { - metadata: { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 5, - userId: 'u1', - }, - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: '{{event.context.customerID || "" }}', - subAccount: true, - loginCustomerId: '{{event.context.subaccountID || "" }}', - listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], - authStatus: 'active', - }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { - phone: '912382193', - firstName: 'John', - lastName: 'Gomes', - city: 'London', - state: 'UK', - streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, - customerID: {}, - subaccountID: 11, - }, - event: 'Page View', - type: 'track', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - adjustedValue: '10', - currency: 'INR', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - partialFailure: true, - campaignId: '1', - templateId: '0', - order_id: 10000, - total: 1000, - products: [ - { - product_id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - price: '19', - position: '1', - category: 'cars', - url: 'https://www.example.com/product/path', - image_url: 'https://www.example.com/product/path.jpg', - quantity: '2', - }, - { - product_id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - price: '192', - quantity: 22, - position: '12', - category: 'Cars2', - url: 'https://www.example.com/product/path2', - image_url: 'https://www.example.com/product/path.jpg2', - }, - ], - }, - integrations: { All: true }, - name: 'ApplicationLoaded', - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, ]; const invalidRtTfCases = [ @@ -688,125 +500,6 @@ export const data = [ module: 'destination', }, }, - { - batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - 'login-customer-id': '11', - }, - params: { event: 'Page View', customerId: '1234567890' }, - body: { - JSON: { - partialFailure: true, - conversionAdjustments: [ - { - gclidDateTimePair: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - }, - restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, - orderId: '10000', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - userIdentifiers: [ - { - hashedPhoneNumber: - '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', - }, - { - addressInfo: { - hashedFirstName: - 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', - hashedLastName: - '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - state: 'UK', - city: 'London', - hashedStreetAddress: - '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', - }, - }, - ], - adjustmentType: 'ENHANCEMENT', - }, - ], - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - }, - metadata: [ - { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 4, - userId: 'u1', - }, - ], - batched: false, - statusCode: 200, - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: 1234567890, - subAccount: true, - loginCustomerId: 11, - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, - }, - }, - { - batched: false, - statusCode: 400, - error: 'customerId and loginCustomerId should be a string or number', - statTags: { - destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'router', - implementation: 'native', - module: 'destination', - }, - metadata: [ - { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 5, - userId: 'u1', - }, - ], - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: {}, - subAccount: true, - loginCustomerId: 11, - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, - }, - }, ], }, }, From 2083ca020ad751fcb75fd50e682e5e7c69d3961a Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 1 Nov 2024 16:41:18 +0000 Subject: [PATCH 077/147] chore(release): 1.83.1 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcfd6f2835b..2f648c78f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.83.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.0...v1.83.1) (2024-11-01) + ## [1.83.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.2...v1.83.0) (2024-10-25) diff --git a/package-lock.json b/package-lock.json index ccf7ed2c2ae..37196f8f57c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.1", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 79571462d3a..5edc30592b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.1", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From b5003d16aef9ab51d05ab5885bd402e59dfaf8e1 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Mon, 4 Nov 2024 20:19:06 +0530 Subject: [PATCH 078/147] chore: new flags incorporate env variables via features.ts file --- src/controllers/misc.ts | 2 +- src/features.json | 105 ------------------------- src/features.ts | 116 ++++++++++++++++++++++++++++ src/services/__tests__/misc.test.ts | 40 ++++++++++ src/services/misc.ts | 8 +- test/apitests/service.api.test.ts | 6 +- 6 files changed, 162 insertions(+), 115 deletions(-) delete mode 100644 src/features.json create mode 100644 src/features.ts diff --git a/src/controllers/misc.ts b/src/controllers/misc.ts index e2efdab5db7..7f8ec52825d 100644 --- a/src/controllers/misc.ts +++ b/src/controllers/misc.ts @@ -21,7 +21,7 @@ export class MiscController { } public static features(ctx: Context) { - ctx.body = MiscService.getFetaures(); + ctx.body = MiscService.getFeatures(); ctx.status = 200; return ctx; } diff --git a/src/features.json b/src/features.json deleted file mode 100644 index 63862eefed4..00000000000 --- a/src/features.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "routerTransform": { - "ACTIVE_CAMPAIGN": true, - "ALGOLIA": true, - "CANDU": true, - "DELIGHTED": true, - "DRIP": true, - "FB_CUSTOM_AUDIENCE": true, - "GA": true, - "GAINSIGHT": true, - "GAINSIGHT_PX": true, - "GOOGLESHEETS": true, - "GOOGLE_ADWORDS_ENHANCED_CONVERSIONS": true, - "GOOGLE_ADWORDS_REMARKETING_LISTS": true, - "GOOGLE_ADWORDS_OFFLINE_CONVERSIONS": true, - "HS": true, - "ITERABLE": true, - "KLAVIYO": true, - "KUSTOMER": true, - "MAILCHIMP": true, - "MAILMODO": true, - "MARKETO": true, - "OMETRIA": true, - "PARDOT": true, - "PINTEREST_TAG": true, - "PROFITWELL": true, - "SALESFORCE": true, - "SALESFORCE_OAUTH": true, - "SALESFORCE_OAUTH_SANDBOX": true, - "SFMC": true, - "SNAPCHAT_CONVERSION": true, - "TIKTOK_ADS": true, - "TRENGO": true, - "YAHOO_DSP": true, - "CANNY": true, - "LAMBDA": true, - "WOOTRIC": true, - "GOOGLE_CLOUD_FUNCTION": true, - "BQSTREAM": true, - "CLICKUP": true, - "FRESHMARKETER": true, - "FRESHSALES": true, - "MONDAY": true, - "CUSTIFY": true, - "USER": true, - "REFINER": true, - "FACEBOOK_OFFLINE_CONVERSIONS": true, - "MAILJET": true, - "SNAPCHAT_CUSTOM_AUDIENCE": true, - "MARKETO_STATIC_LIST": true, - "CAMPAIGN_MANAGER": true, - "SENDGRID": true, - "SENDINBLUE": true, - "ZENDESK": true, - "MP": true, - "TIKTOK_ADS_OFFLINE_EVENTS": true, - "CRITEO_AUDIENCE": true, - "CUSTOMERIO": true, - "BRAZE": true, - "OPTIMIZELY_FULLSTACK": true, - "TWITTER_ADS": true, - "CLEVERTAP": true, - "ORTTO": true, - "GLADLY": true, - "ONE_SIGNAL": true, - "TIKTOK_AUDIENCE": true, - "REDDIT": true, - "THE_TRADE_DESK": true, - "INTERCOM": true, - "NINETAILED": true, - "KOALA": true, - "LINKEDIN_ADS": true, - "BLOOMREACH": true, - "MOVABLE_INK": true, - "EMARSYS": true, - "KODDI": true, - "WUNDERKIND": true, - "CLICKSEND": true, - "ZOHO": true, - "CORDIAL": true, - "X_AUDIENCE": true, - "BLOOMREACH_CATALOG": true, - "SMARTLY": true, - "HTTP": true, - "AMAZON_AUDIENCE": true, - "INTERCOM_V2": true - }, - "regulations": [ - "BRAZE", - "AM", - "INTERCOM", - "CLEVERTAP", - "AF", - "MP", - "GA", - "ITERABLE", - "ENGAGE", - "CUSTIFY", - "SENDGRID", - "SPRIG", - "EMARSYS" - ], - "supportSourceTransformV1": true, - "supportTransformerProxyV1": true -} diff --git a/src/features.ts b/src/features.ts new file mode 100644 index 00000000000..9f60d444836 --- /dev/null +++ b/src/features.ts @@ -0,0 +1,116 @@ +interface FeaturesConfig { + routerTransform: Record; + regulations: string[]; + supportSourceTransformV1: boolean; + supportTransformerProxyV1: boolean; + upgradedToSourceTransformV2?: boolean; +} + +const defaultFeaturesConfig: FeaturesConfig = { + routerTransform: { + ACTIVE_CAMPAIGN: true, + ALGOLIA: true, + CANDU: true, + DELIGHTED: true, + DRIP: true, + FB_CUSTOM_AUDIENCE: true, + GA: true, + GAINSIGHT: true, + GAINSIGHT_PX: true, + GOOGLESHEETS: true, + GOOGLE_ADWORDS_ENHANCED_CONVERSIONS: true, + GOOGLE_ADWORDS_REMARKETING_LISTS: true, + GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: true, + HS: true, + ITERABLE: true, + KLAVIYO: true, + KUSTOMER: true, + MAILCHIMP: true, + MAILMODO: true, + MARKETO: true, + OMETRIA: true, + PARDOT: true, + PINTEREST_TAG: true, + PROFITWELL: true, + SALESFORCE: true, + SALESFORCE_OAUTH: true, + SALESFORCE_OAUTH_SANDBOX: true, + SFMC: true, + SNAPCHAT_CONVERSION: true, + TIKTOK_ADS: true, + TRENGO: true, + YAHOO_DSP: true, + CANNY: true, + LAMBDA: true, + WOOTRIC: true, + GOOGLE_CLOUD_FUNCTION: true, + BQSTREAM: true, + CLICKUP: true, + FRESHMARKETER: true, + FRESHSALES: true, + MONDAY: true, + CUSTIFY: true, + USER: true, + REFINER: true, + FACEBOOK_OFFLINE_CONVERSIONS: true, + MAILJET: true, + SNAPCHAT_CUSTOM_AUDIENCE: true, + MARKETO_STATIC_LIST: true, + CAMPAIGN_MANAGER: true, + SENDGRID: true, + SENDINBLUE: true, + ZENDESK: true, + MP: true, + TIKTOK_ADS_OFFLINE_EVENTS: true, + CRITEO_AUDIENCE: true, + CUSTOMERIO: true, + BRAZE: true, + OPTIMIZELY_FULLSTACK: true, + TWITTER_ADS: true, + CLEVERTAP: true, + ORTTO: true, + GLADLY: true, + ONE_SIGNAL: true, + TIKTOK_AUDIENCE: true, + REDDIT: true, + THE_TRADE_DESK: true, + INTERCOM: true, + NINETAILED: true, + KOALA: true, + LINKEDIN_ADS: true, + BLOOMREACH: true, + MOVABLE_INK: true, + EMARSYS: true, + KODDI: true, + WUNDERKIND: true, + CLICKSEND: true, + ZOHO: true, + CORDIAL: true, + X_AUDIENCE: true, + BLOOMREACH_CATALOG: true, + SMARTLY: true, + HTTP: true, + AMAZON_AUDIENCE: true, + INTERCOM_V2: true, + }, + regulations: [ + 'BRAZE', + 'AM', + 'INTERCOM', + 'CLEVERTAP', + 'AF', + 'MP', + 'GA', + 'ITERABLE', + 'ENGAGE', + 'CUSTIFY', + 'SENDGRID', + 'SPRIG', + 'EMARSYS', + ], + supportSourceTransformV1: true, + supportTransformerProxyV1: true, + upgradedToSourceTransformV2: process.env.UPGRADED_TO_SOURCE_TRANSFORM_V2 === 'true' || false, // redundant but required to show that the default is false +}; + +export default defaultFeaturesConfig; diff --git a/src/services/__tests__/misc.test.ts b/src/services/__tests__/misc.test.ts index 5dcd948b34e..f4befd4a042 100644 --- a/src/services/__tests__/misc.test.ts +++ b/src/services/__tests__/misc.test.ts @@ -1,4 +1,5 @@ import { DestHandlerMap } from '../../constants/destinationCanonicalNames'; +import defaultFeaturesConfig from '../../features'; import { MiscService } from '../misc'; describe('Misc tests', () => { @@ -24,3 +25,42 @@ describe('Misc tests', () => { ); }); }); + +describe('Misc | getFeatures', () => { + const originalEnv = process.env; + + beforeEach(() => { + // Reset environment variables and module cache before each test + process.env = { ...originalEnv }; + jest.resetModules(); + }); + + afterAll(() => { + // Restore the original environment variables after all tests + process.env = originalEnv; + }); + + function getMiscService() { + // Re-import config and featuresService after environment variables are set + const { MiscService: miscService } = require('../misc'); + return miscService; + } + + it('should return the default configuration as a JSON string', () => { + const miscService = getMiscService(); + const expectedConfig = JSON.stringify(defaultFeaturesConfig); + const result = miscService.getFeatures(); + expect(result).toBe(expectedConfig); + }); + + it('should return configuration with upgradedToSourceTransformV2 overridden by environment variable', () => { + process.env.UPGRADED_TO_SOURCE_TRANSFORM_V2 = 'true'; + const expectedConfig = { + ...defaultFeaturesConfig, + upgradedToSourceTransformV2: true, + }; + const miscService = getMiscService(); + const result = miscService.getFeatures(); + expect(result).toBe(JSON.stringify(expectedConfig)); + }); +}); diff --git a/src/services/misc.ts b/src/services/misc.ts index 09051edeec3..334b54ba17b 100644 --- a/src/services/misc.ts +++ b/src/services/misc.ts @@ -1,10 +1,9 @@ /* eslint-disable global-require, import/no-dynamic-require */ -import fs from 'fs'; import { Context } from 'koa'; -import path from 'path'; import { DestHandlerMap } from '../constants/destinationCanonicalNames'; import { getCPUProfile, getHeapProfile } from '../middleware'; import { Metadata } from '../types'; +import defaultFeaturesConfig from '../features'; export class MiscService { public static getDestHandler(dest: string, version: string) { @@ -62,9 +61,8 @@ export class MiscService { return process.env.npm_package_version || 'Version Info not found'; } - public static getFetaures() { - const obj = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../features.json'), 'utf8')); - return JSON.stringify(obj); + public static getFeatures() { + return JSON.stringify(defaultFeaturesConfig); } public static async getCPUProfile(seconds: number) { diff --git a/test/apitests/service.api.test.ts b/test/apitests/service.api.test.ts index 2a0db6978e0..9c1d96e7fe5 100644 --- a/test/apitests/service.api.test.ts +++ b/test/apitests/service.api.test.ts @@ -8,6 +8,7 @@ import request from 'supertest'; import networkHandlerFactory from '../../src/adapters/networkHandlerFactory'; import { FetchHandler } from '../../src/helpers/fetchHandlers'; import { applicationRoutes } from '../../src/routes'; +import defaultFeaturesConfig from '../../src/features'; let server: any; const OLD_ENV = process.env; @@ -43,12 +44,9 @@ const getDataFromPath = (pathInput) => { describe('features tests', () => { test('successful features response', async () => { - const expectedData = JSON.parse( - fs.readFileSync(path.resolve(__dirname, '../../src/features.json'), 'utf8'), - ); const response = await request(server).get('/features'); expect(response.status).toEqual(200); - expect(JSON.parse(response.text)).toEqual(expectedData); + expect(JSON.parse(response.text)).toEqual(defaultFeaturesConfig); }); test('features regulations should be array', async () => { From e5c5b0a28070ff5ca89a274c3998b96780139149 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:42:34 +0530 Subject: [PATCH 079/147] fix: update gaec destination with config validation (#3847) * fix: str.replace is not a function * fix: resolving comments * fix: update google adwords enhanced conversion config check * chore: refactor code * chore: fix lint errors * chore: address comments --------- Co-authored-by: Manish Kumar --- .../transform.js | 32 +- src/v0/util/index.js | 6 +- src/v0/util/index.test.js | 17 + .../processor/data.ts | 2 +- .../router/data.ts | 510 ++++++++++++++++++ 5 files changed, 558 insertions(+), 9 deletions(-) diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 55d0c16c8cc..a939b02cbb7 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -1,8 +1,9 @@ /* eslint-disable no-param-reassign */ const get = require('get-value'); -const { cloneDeep } = require('lodash'); +const { cloneDeep, isNumber } = require('lodash'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); +const isString = require('lodash/isString'); const { constructPayload, defaultRequestConfig, @@ -35,7 +36,16 @@ const updateMappingJson = (mapping) => { const responseBuilder = async (metadata, message, { Config }, payload) => { const response = defaultRequestConfig(); const { event } = message; - const filteredCustomerId = removeHyphens(Config.customerId); + const { subAccount } = Config; + let { customerId, loginCustomerId } = Config; + if (isNumber(customerId)) { + customerId = customerId.toString(); + } + if (!isString(customerId)) { + throw new InstrumentationError('customerId should be a string or number'); + } + const filteredCustomerId = removeHyphens(customerId); + response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}:uploadConversionAdjustments`; response.body.JSON = payload; const accessToken = getAccessToken(metadata, 'access_token'); @@ -45,11 +55,19 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { 'developer-token': getValueFromMessage(metadata, 'secret.developer_token'), }; response.params = { event, customerId: filteredCustomerId }; - if (Config.subAccount) - if (Config.loginCustomerId) { - const filteredLoginCustomerId = removeHyphens(Config.loginCustomerId); - response.headers['login-customer-id'] = filteredLoginCustomerId; - } else throw new ConfigurationError(`LoginCustomerId is required as subAccount is true.`); + if (subAccount) { + if (!loginCustomerId) { + throw new ConfigurationError(`loginCustomerId is required as subAccount is true.`); + } + if (isNumber(loginCustomerId)) { + loginCustomerId = loginCustomerId.toString(); + } + if (loginCustomerId && !isString(loginCustomerId)) { + throw new InstrumentationError('loginCustomerId should be a string or number'); + } + const filteredLoginCustomerId = removeHyphens(loginCustomerId); + response.headers['login-customer-id'] = filteredLoginCustomerId; + } return response; }; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index ca81262f88e..f034ab802b2 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -26,6 +26,7 @@ const { } = require('@rudderstack/integrations-lib'); const { JsonTemplateEngine, PathType } = require('@rudderstack/json-template-engine'); +const isString = require('lodash/isString'); const logger = require('../../logger'); const stats = require('../../util/stats'); const { DestCanonicalNames, DestHandlerMap } = require('../../constants/destinationCanonicalNames'); @@ -1622,7 +1623,7 @@ function isHttpStatusRetryable(status) { function generateUUID() { return crypto.randomUUID({ disableEntropyCache: true, - }); /* using disableEntropyCache as true to not cache the generated uuids. + }); /* using disableEntropyCache as true to not cache the generated uuids. For more Info https://nodejs.org/api/crypto.html#cryptorandomuuidoptions:~:text=options%20%3CObject%3E-,disableEntropyCache,-%3Cboolean%3E%20By */ } @@ -1646,6 +1647,9 @@ function isAppleFamily(platform) { } function removeHyphens(str) { + if (!isString(str)) { + return str; + } return str.replace(/-/g, ''); } diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 6bf689eca72..0b05b6f2d69 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -10,6 +10,7 @@ const { validateEventAndLowerCaseConversion, groupRouterTransformEvents, isAxiosError, + removeHyphens, } = require('./index'); const exp = require('constants'); @@ -968,3 +969,19 @@ describe('isAxiosError', () => { expect(isAxiosError(error)).toBe(false); }); }); + +describe('removeHyphens', () => { + const data = [ + { input: 'hello-w--orld', expected: 'helloworld' }, + { input: '', expected: '' }, + { input: null, expected: null }, + { input: undefined, expected: undefined }, + { input: 12345, expected: 12345 }, + { input: '123-12-241', expected: '12312241' }, + ]; + it('should remove hyphens from string else return the input as it is', () => { + data.forEach(({ input, expected }) => { + expect(removeHyphens(input)).toBe(expected); + }); + }); +}); diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts index 40d8370fcb7..1d20e887e98 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts @@ -814,7 +814,7 @@ export const data = [ }, }, statusCode: 400, - error: 'LoginCustomerId is required as subAccount is true.', + error: 'loginCustomerId is required as subAccount is true.', statTags: { errorCategory: 'dataValidation', errorType: 'configuration', diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 1d77b5d7743..bf1bfcf5b93 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -225,6 +225,323 @@ const events = [ sentAt: '2019-10-14T11:15:53.296Z', }, }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 4, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '{{event.context.customerID || "" }}', + subAccount: true, + loginCustomerId: '{{event.context.subaccountID || "" }}', + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: 1234567890, + subaccountID: 11, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 5, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '{{event.context.customerID || "" }}', + subAccount: true, + loginCustomerId: '{{event.context.subaccountID || "" }}', + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: {}, + subaccountID: 11, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 6, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '1234567890', + subAccount: true, + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: {}, + subaccountID: 11, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 7, + userId: 'u1', + }, + destination: { + Config: { + customerId: '1234567890', + subAccount: true, + loginCustomerId: { id: '1234567890' }, + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + event: 'Page View', + type: 'track', + userId: '12345', + context: { + traits: { + email: 'user@testmail.com', + }, + }, + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + order_id: 10000, + total: 1000, + }, + }, + }, ]; const invalidRtTfCases = [ @@ -500,6 +817,199 @@ export const data = [ module: 'destination', }, }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '11', + }, + params: { event: 'Page View', customerId: '1234567890' }, + body: { + JSON: { + partialFailure: true, + conversionAdjustments: [ + { + gclidDateTimePair: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + }, + restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, + orderId: '10000', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + userIdentifiers: [ + { + hashedPhoneNumber: + '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', + }, + { + addressInfo: { + hashedFirstName: + 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', + hashedLastName: + '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', + state: 'UK', + city: 'London', + hashedStreetAddress: + '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + }, + }, + ], + adjustmentType: 'ENHANCEMENT', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 4, + userId: 'u1', + }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: 1234567890, + subAccount: true, + loginCustomerId: 11, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, + { + batched: false, + statusCode: 400, + error: 'customerId should be a string or number', + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 5, + userId: 'u1', + }, + ], + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: {}, + subAccount: true, + loginCustomerId: 11, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, + { + batched: false, + statusCode: 400, + error: 'loginCustomerId is required as subAccount is true.', + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'router', + implementation: 'native', + module: 'destination', + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 6, + userId: 'u1', + }, + ], + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + customerId: '1234567890', + subAccount: true, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, + { + batched: false, + statusCode: 400, + error: 'loginCustomerId should be a string or number', + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 7, + userId: 'u1', + }, + ], + destination: { + Config: { + loginCustomerId: { + id: '1234567890', + }, + customerId: '1234567890', + subAccount: true, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, ], }, }, From f4100a3527db82108f08960bfb97870079394f16 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:42:56 +0530 Subject: [PATCH 080/147] Revert "fix: add missing field for pinterest_tag single product events" (#3851) This reverts commit f781a84ade98649d68cebf4da13c2ceff8df2df2. --- .../v2/destinations/pinterest_tag/procWorkflow.yaml | 6 +----- test/apitests/data_scenarios/cdk_v2/failure.json | 8 -------- test/apitests/data_scenarios/cdk_v2/success.json | 12 ------------ .../destination/proc/batch_input_multiplex.json | 12 ------------ .../destination/proc/multiplex_partial_failure.json | 8 -------- .../destination/proc/multiplex_success.json | 8 -------- .../destination/router/failure_test.json | 8 -------- .../destinations/pinterest_tag/processor/data.ts | 13 +++---------- .../destinations/pinterest_tag/router/data.ts | 4 +--- .../destinations/pinterest_tag/step/data.ts | 11 +++-------- 10 files changed, 8 insertions(+), 82 deletions(-) diff --git a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml index 5d97da5a9ed..64d391c8882 100644 --- a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml @@ -167,11 +167,7 @@ steps: "content_ids": (props.product_id ?? props.sku ?? props.id)[], "contents": { "quantity": Number(props.quantity) || 1, - "item_price": String(props.price), - "item_name": String(props.name), - "id": props.product_id ?? props.sku, - "item_category": props.category, - "item_brand": props.brand + "item_price": String(props.price) }[] }; - name: combineAllEcomFields diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 154d24481dc..1635a3f0dbf 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -556,10 +556,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -683,10 +679,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index 88f430dd7c2..ced7433a282 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -556,10 +556,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -638,10 +634,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -720,10 +712,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3deb7d4b8ba..3ce7c150918 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -388,10 +388,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -470,10 +466,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -552,10 +544,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index a2652855d56..0e467c26d0b 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -388,10 +388,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -470,10 +466,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index ba4d5266f30..66b6c870a9e 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -207,10 +207,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -289,10 +285,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 197456f66af..9e36da50cb8 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -754,10 +754,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -785,10 +781,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/integrations/destinations/pinterest_tag/processor/data.ts b/test/integrations/destinations/pinterest_tag/processor/data.ts index 1788d13d563..b856d247d71 100644 --- a/test/integrations/destinations/pinterest_tag/processor/data.ts +++ b/test/integrations/destinations/pinterest_tag/processor/data.ts @@ -482,9 +482,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2407,9 +2405,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [ - { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, - ], + contents: [{ quantity: 1, item_price: 'undefined' }], }, }, JSON_ARRAY: {}, @@ -2670,7 +2666,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1, item_name: 'undefined' }], + contents: [{ item_price: 'undefined', quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3501,7 +3497,6 @@ export const data = [ subtotal: 22.5, affiliation: 'Google Store', checkout_id: 'fksdjfsdjfisjf9sdfjsd9f', - category: 'Apparel', }, anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', integrations: { All: true }, @@ -3568,8 +3563,6 @@ export const data = [ { quantity: 1, item_price: 'undefined', - item_name: 'undefined', - item_category: 'Apparel', }, ], currency: 'USD', diff --git a/test/integrations/destinations/pinterest_tag/router/data.ts b/test/integrations/destinations/pinterest_tag/router/data.ts index 28c82c4679c..c9ab29a45a9 100644 --- a/test/integrations/destinations/pinterest_tag/router/data.ts +++ b/test/integrations/destinations/pinterest_tag/router/data.ts @@ -815,9 +815,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, { diff --git a/test/integrations/destinations/pinterest_tag/step/data.ts b/test/integrations/destinations/pinterest_tag/step/data.ts index 8f0680a77c0..b607e3c9faf 100644 --- a/test/integrations/destinations/pinterest_tag/step/data.ts +++ b/test/integrations/destinations/pinterest_tag/step/data.ts @@ -468,9 +468,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2422,9 +2420,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [ - { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, - ], + contents: [{ quantity: 1, item_price: 'undefined' }], }, }, JSON_ARRAY: {}, @@ -2689,7 +2685,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_name: 'undefined', item_price: 'undefined', quantity: 1 }], + contents: [{ item_price: 'undefined', quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3609,7 +3605,6 @@ export const data = [ num_items: 0, contents: [ { - item_name: 'undefined', quantity: 1, item_price: 'undefined', }, From 60468fb65c105c1fa81f6818c52bdf1c7c2de6b7 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 5 Nov 2024 09:19:30 +0000 Subject: [PATCH 081/147] chore(release): 1.83.2 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f648c78f9e..8c7591edec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.83.2](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.1...v1.83.2) (2024-11-05) + + +### Bug Fixes + +* update gaec destination with config validation ([#3847](https://github.com/rudderlabs/rudder-transformer/issues/3847)) ([e5c5b0a](https://github.com/rudderlabs/rudder-transformer/commit/e5c5b0a28070ff5ca89a274c3998b96780139149)) + ### [1.83.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.0...v1.83.1) (2024-11-01) ## [1.83.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.2...v1.83.0) (2024-10-25) diff --git a/package-lock.json b/package-lock.json index 37196f8f57c..0e33a864ca0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.83.1", + "version": "1.83.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.83.1", + "version": "1.83.2", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 5edc30592b8..9b0165feb42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.83.1", + "version": "1.83.2", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 7a264590b61d3d31d5559c8ac53fd572b40cddec Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Wed, 6 Nov 2024 10:19:47 +0530 Subject: [PATCH 082/147] feat: gaec migration (#3855) --- .../transform.js | 32 ++- .../processor/data.ts | 190 ++++++++++++++++++ .../router/data.ts | 165 +++++++++++++++ 3 files changed, 384 insertions(+), 3 deletions(-) diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 007f16d7f8e..13a294ea959 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -2,7 +2,11 @@ const get = require('get-value'); const { cloneDeep, isNumber } = require('lodash'); -const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); +const { + InstrumentationError, + ConfigurationError, + isDefinedAndNotNull, +} = require('@rudderstack/integrations-lib'); const isString = require('lodash/isString'); const { constructPayload, @@ -11,6 +15,7 @@ const { removeHyphens, simpleProcessRouterDest, getAccessToken, + isDefined, } = require('../../util'); const { trackMapping, BASE_ENDPOINT } = require('./config'); @@ -38,6 +43,16 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { const { event } = message; const { subAccount } = Config; let { customerId, loginCustomerId } = Config; + const { configData } = Config; + + if (isDefinedAndNotNull(configData)) { + const configDetails = JSON.parse(configData); + customerId = configDetails.customerId; + if (isDefined(configDetails.loginCustomerId)) { + loginCustomerId = configDetails.loginCustomerId; + } + } + if (isNumber(customerId)) { customerId = customerId.toString(); } @@ -63,6 +78,11 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { response.headers['login-customer-id'] = filteredLoginCustomerId; } else throw new ConfigurationError(`LoginCustomerId is required as subAccount is true.`); + if (loginCustomerId) { + const filteredLoginCustomerId = removeHyphens(loginCustomerId); + response.headers['login-customer-id'] = filteredLoginCustomerId; + } + return response; }; @@ -71,8 +91,14 @@ const processTrackEvent = async (metadata, message, destination) => { const { Config } = destination; const { event } = message; const { listOfConversions } = Config; - if (listOfConversions.some((i) => i.conversions === event)) { - flag = 1; + if (listOfConversions && listOfConversions.length > 0) { + if (typeof listOfConversions[0] === 'string') { + if (listOfConversions.includes(event)) { + flag = 1; + } + } else if (listOfConversions.some((i) => i.conversions === event)) { + flag = 1; + } } if (event === undefined || event === '' || flag === 0) { throw new ConfigurationError( diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts index 40d8370fcb7..87fad8b9a54 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts @@ -1720,4 +1720,194 @@ export const data = [ }, }, }, + { + name: 'google_adwords_enhanced_conversions', + description: 'Success test with configDetails', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + listOfConversions: ['Page View', 'Product Added'], + authStatus: 'active', + configData: '{"customerId": "1234567890", "loginCustomerId": ""}', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + countryCode: 'us', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { + All: true, + }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + }, + params: { + event: 'Page View', + customerId: '1234567890', + }, + body: { + JSON: { + conversionAdjustments: [ + { + gclidDateTimePair: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + }, + restatementValue: { + adjustedValue: 10, + currencyCode: 'INR', + }, + orderId: '10000', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + userIdentifiers: [ + { + hashedPhoneNumber: + '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', + }, + { + addressInfo: { + hashedFirstName: + 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', + hashedLastName: + '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', + state: 'UK', + city: 'London', + countryCode: 'us', + hashedStreetAddress: + '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + }, + }, + ], + adjustmentType: 'ENHANCEMENT', + }, + ], + partialFailure: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + }, + statusCode: 200, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 89ce06818b4..33cb4a832fc 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -413,6 +413,91 @@ const events = [ sentAt: '2019-10-14T11:15:53.296Z', }, }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 6, + userId: 'u1', + }, + destination: { + Config: { + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + phone: '912382193', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'UK', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + }, + event: 'Page View', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + userId: '12345', + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + adjustedValue: '10', + currency: 'INR', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + partialFailure: true, + campaignId: '1', + templateId: '0', + order_id: 10000, + total: 1000, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + integrations: { All: true }, + name: 'ApplicationLoaded', + }, + }, ]; const invalidRtTfCases = [ @@ -807,6 +892,86 @@ export const data = [ }, }, }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '65656565', + }, + params: { event: 'Page View', customerId: '1234567890' }, + body: { + JSON: { + partialFailure: true, + conversionAdjustments: [ + { + gclidDateTimePair: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + }, + restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, + orderId: '10000', + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + userIdentifiers: [ + { + hashedPhoneNumber: + '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', + }, + { + addressInfo: { + hashedFirstName: + 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', + hashedLastName: + '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', + state: 'UK', + city: 'London', + hashedStreetAddress: + '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + }, + }, + ], + adjustmentType: 'ENHANCEMENT', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 6, + userId: 'u1', + }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, ], }, }, From 04c069486bdd3c101906fa6c621e983090fcab25 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Thu, 17 Oct 2024 18:25:20 +0530 Subject: [PATCH 083/147] feat: sources v2 spec support along with adapters --- src/controllers/__tests__/source.test.ts | 111 +++++++++++- src/controllers/util/index.test.ts | 163 ++++++++++++++++-- src/controllers/util/index.ts | 62 ++++++- src/interfaces/SourceService.ts | 8 +- src/middlewares/routeActivation.ts | 15 ++ .../__tests__/nativeIntegration.test.ts | 20 ++- src/services/source/nativeIntegration.ts | 18 +- src/types/index.ts | 22 +++ test/apitests/service.api.test.ts | 7 + 9 files changed, 390 insertions(+), 36 deletions(-) diff --git a/src/controllers/__tests__/source.test.ts b/src/controllers/__tests__/source.test.ts index 565f39d559f..72bee83282e 100644 --- a/src/controllers/__tests__/source.test.ts +++ b/src/controllers/__tests__/source.test.ts @@ -6,6 +6,7 @@ import { applicationRoutes } from '../../routes'; import { NativeIntegrationSourceService } from '../../services/source/nativeIntegration'; import { ServiceSelector } from '../../helpers/serviceSelector'; import { ControllerUtility } from '../util/index'; +import { SourceInputConversionResult } from '../../types'; let server: any; const OLD_ENV = process.env; @@ -38,6 +39,19 @@ const getData = () => { return [{ event: { a: 'b1' } }, { event: { a: 'b2' } }]; }; +const getV2Data = () => { + return [ + { request: { body: '{"a": "b"}' }, source: { id: 1 } }, + { request: { body: '{"a": "b"}' }, source: { id: 1 } }, + ]; +}; + +const getConvertedData = () => { + return getData().map((eventInstance) => { + return { output: eventInstance } as SourceInputConversionResult; + }); +}; + describe('Source controller tests', () => { describe('V0 Source transform tests', () => { test('successful source transform', async () => { @@ -49,7 +63,7 @@ describe('Source controller tests', () => { mockSourceService.sourceTransformRoutine = jest .fn() .mockImplementation((i, s, v, requestMetadata) => { - expect(i).toEqual(getData()); + expect(i).toEqual(getConvertedData()); expect(s).toEqual(sourceType); expect(v).toEqual(version); return testOutput; @@ -66,7 +80,7 @@ describe('Source controller tests', () => { expect(s).toEqual(sourceType); expect(v).toEqual(version); expect(e).toEqual(getData()); - return { implementationVersion: version, input: e }; + return { implementationVersion: version, input: getConvertedData() }; }); const response = await request(server) @@ -139,7 +153,7 @@ describe('Source controller tests', () => { mockSourceService.sourceTransformRoutine = jest .fn() .mockImplementation((i, s, v, requestMetadata) => { - expect(i).toEqual(getData()); + expect(i).toEqual(getConvertedData()); expect(s).toEqual(sourceType); expect(v).toEqual(version); return testOutput; @@ -156,7 +170,7 @@ describe('Source controller tests', () => { expect(s).toEqual(sourceType); expect(v).toEqual(version); expect(e).toEqual(getData()); - return { implementationVersion: version, input: e }; + return { implementationVersion: version, input: getConvertedData() }; }); const response = await request(server) @@ -217,4 +231,93 @@ describe('Source controller tests', () => { expect(adaptInputToVersionSpy).toHaveBeenCalledTimes(1); }); }); + + describe('V2 Source transform tests', () => { + test('successful source transform', async () => { + const sourceType = '__rudder_test__'; + const version = 'v2'; + const testOutput = [{ event: { a: 'b' }, source: { id: 'id' } }]; + + const mockSourceService = new NativeIntegrationSourceService(); + mockSourceService.sourceTransformRoutine = jest + .fn() + .mockImplementation((i, s, v, requestMetadata) => { + expect(i).toEqual(getConvertedData()); + expect(s).toEqual(sourceType); + expect(v).toEqual(version); + return testOutput; + }); + const getNativeSourceServiceSpy = jest + .spyOn(ServiceSelector, 'getNativeSourceService') + .mockImplementation(() => { + return mockSourceService; + }); + + const adaptInputToVersionSpy = jest + .spyOn(ControllerUtility, 'adaptInputToVersion') + .mockImplementation((s, v, e) => { + expect(s).toEqual(sourceType); + expect(v).toEqual(version); + expect(e).toEqual(getV2Data()); + return { implementationVersion: version, input: getConvertedData() }; + }); + + const response = await request(server) + .post('/v2/sources/__rudder_test__') + .set('Accept', 'application/json') + .send(getV2Data()); + + expect(response.status).toEqual(200); + expect(response.body).toEqual(testOutput); + + expect(response.header['apiversion']).toEqual('2'); + + expect(getNativeSourceServiceSpy).toHaveBeenCalledTimes(1); + expect(adaptInputToVersionSpy).toHaveBeenCalledTimes(1); + expect(mockSourceService.sourceTransformRoutine).toHaveBeenCalledTimes(1); + }); + + test('failing source transform', async () => { + const sourceType = '__rudder_test__'; + const version = 'v2'; + const mockSourceService = new NativeIntegrationSourceService(); + const getNativeSourceServiceSpy = jest + .spyOn(ServiceSelector, 'getNativeSourceService') + .mockImplementation(() => { + return mockSourceService; + }); + + const adaptInputToVersionSpy = jest + .spyOn(ControllerUtility, 'adaptInputToVersion') + .mockImplementation((s, v, e) => { + expect(s).toEqual(sourceType); + expect(v).toEqual(version); + expect(e).toEqual(getV2Data()); + throw new Error('test error'); + }); + + const response = await request(server) + .post('/v2/sources/__rudder_test__') + .set('Accept', 'application/json') + .send(getV2Data()); + + const expectedResp = [ + { + error: 'test error', + statTags: { + errorCategory: 'transformation', + }, + statusCode: 500, + }, + ]; + + expect(response.status).toEqual(200); + expect(response.body).toEqual(expectedResp); + + expect(response.header['apiversion']).toEqual('2'); + + expect(getNativeSourceServiceSpy).toHaveBeenCalledTimes(1); + expect(adaptInputToVersionSpy).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/src/controllers/util/index.test.ts b/src/controllers/util/index.test.ts index 60659208461..6ab2336b71d 100644 --- a/src/controllers/util/index.test.ts +++ b/src/controllers/util/index.test.ts @@ -19,9 +19,9 @@ describe('adaptInputToVersion', () => { const expected = { implementationVersion: undefined, input: [ - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, ], }; @@ -40,9 +40,9 @@ describe('adaptInputToVersion', () => { const expected = { implementationVersion: 'v0', input: [ - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, ], }; @@ -71,16 +71,22 @@ describe('adaptInputToVersion', () => { implementationVersion: 'v1', input: [ { - event: { key1: 'val1', key2: 'val2' }, - source: { id: 'source_id', config: { configField1: 'configVal1' } }, + output: { + event: { key1: 'val1', key2: 'val2' }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, }, { - event: { key1: 'val1', key2: 'val2' }, - source: { id: 'source_id', config: { configField1: 'configVal1' } }, + output: { + event: { key1: 'val1', key2: 'val2' }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, }, { - event: { key1: 'val1', key2: 'val2' }, - source: { id: 'source_id', config: { configField1: 'configVal1' } }, + output: { + event: { key1: 'val1', key2: 'val2' }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, }, ], }; @@ -100,9 +106,9 @@ describe('adaptInputToVersion', () => { const expected = { implementationVersion: 'v1', input: [ - { event: { key1: 'val1', key2: 'val2' }, source: undefined }, - { event: { key1: 'val1', key2: 'val2' }, source: undefined }, - { event: { key1: 'val1', key2: 'val2' }, source: undefined }, + { output: { event: { key1: 'val1', key2: 'val2' }, source: undefined } }, + { output: { event: { key1: 'val1', key2: 'val2' }, source: undefined } }, + { output: { event: { key1: 'val1', key2: 'val2' }, source: undefined } }, ], }; @@ -131,9 +137,130 @@ describe('adaptInputToVersion', () => { const expected = { implementationVersion: 'v0', input: [ - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, - { key1: 'val1', key2: 'val2' }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, + { output: { key1: 'val1', key2: 'val2' } }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); + + it('should convert input from v2 to v0 format when the request version is v2 and the implementation version is v0', () => { + const sourceType = 'pipedream'; + const requestVersion = 'v2'; + + const input = [ + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + const expected = { + implementationVersion: 'v0', + input: [ + { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, + { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, + { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); + + it('should convert input from v2 to v1 format when the request version is v2 and the implementation version is v1', () => { + const sourceType = 'webhook'; + const requestVersion = 'v2'; + + const input = [ + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + const expected = { + implementationVersion: 'v1', + input: [ + { + output: { + event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, + { + output: { + event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, + { + output: { + event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, ], }; diff --git a/src/controllers/util/index.ts b/src/controllers/util/index.ts index c5bf7ab3580..b562381ed67 100644 --- a/src/controllers/util/index.ts +++ b/src/controllers/util/index.ts @@ -10,6 +10,8 @@ import { RouterTransformationRequestData, RudderMessage, SourceInput, + SourceInputConversionResult, + SourceInputV2, } from '../../types'; import { getValueFromMessage } from '../../v0/util'; import genericFieldMap from '../../v0/util/data/GenericFieldMapping.json'; @@ -45,28 +47,72 @@ export class ControllerUtility { return this.sourceVersionMap; } - private static convertSourceInputv1Tov0(sourceEvents: SourceInput[]): NonNullable[] { - return sourceEvents.map((sourceEvent) => sourceEvent.event); + private static convertSourceInputv1Tov0( + sourceEvents: SourceInput[], + ): SourceInputConversionResult>[] { + return sourceEvents.map((sourceEvent) => ({ + output: sourceEvent.event as NonNullable, + })); } - private static convertSourceInputv0Tov1(sourceEvents: unknown[]): SourceInput[] { - return sourceEvents.map( - (sourceEvent) => ({ event: sourceEvent, source: undefined }) as SourceInput, - ); + private static convertSourceInputv0Tov1( + sourceEvents: unknown[], + ): SourceInputConversionResult[] { + return sourceEvents.map((sourceEvent) => ({ + output: { event: sourceEvent, source: undefined } as SourceInput, + })); + } + + private static convertSourceInputv2Tov0( + sourceEvents: SourceInputV2[], + ): SourceInputConversionResult>[] { + return sourceEvents.map((sourceEvent) => { + try { + const v0Event = JSON.parse(sourceEvent.request.body); + v0Event.query_parameters = sourceEvent.request.query_parameters; + return { output: v0Event }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v2 to v0 spec'); + return { output: {} as NonNullable, conversionError }; + } + }); + } + + private static convertSourceInputv2Tov1( + sourceEvents: SourceInputV2[], + ): SourceInputConversionResult[] { + return sourceEvents.map((sourceEvent) => { + try { + const v1Event = { event: JSON.parse(sourceEvent.request.body), source: sourceEvent.source }; + v1Event.event.query_parameters = sourceEvent.request.query_parameters; + return { output: v1Event }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v2 to v1 spec'); + return { output: {} as SourceInput, conversionError }; + } + }); } public static adaptInputToVersion( sourceType: string, requestVersion: string, input: NonNullable[], - ): { implementationVersion: string; input: NonNullable[] } { + ): { implementationVersion: string; input: SourceInputConversionResult>[] } { const sourceToVersionMap = this.getSourceVersionsMap(); const implementationVersion = sourceToVersionMap.get(sourceType); - let updatedInput: NonNullable[] = input; + let updatedInput: SourceInputConversionResult>[] = input.map((event) => ({ + output: event, + })); if (requestVersion === 'v0' && implementationVersion === 'v1') { updatedInput = this.convertSourceInputv0Tov1(input); } else if (requestVersion === 'v1' && implementationVersion === 'v0') { updatedInput = this.convertSourceInputv1Tov0(input as SourceInput[]); + } else if (requestVersion === 'v2' && implementationVersion === 'v0') { + updatedInput = this.convertSourceInputv2Tov0(input as SourceInputV2[]); + } else if (requestVersion === 'v2' && implementationVersion === 'v1') { + updatedInput = this.convertSourceInputv2Tov1(input as SourceInputV2[]); } return { implementationVersion, input: updatedInput }; } diff --git a/src/interfaces/SourceService.ts b/src/interfaces/SourceService.ts index c7de8cfe8bc..32a7125e7a0 100644 --- a/src/interfaces/SourceService.ts +++ b/src/interfaces/SourceService.ts @@ -1,10 +1,14 @@ -import { MetaTransferObject, SourceTransformationResponse } from '../types/index'; +import { + MetaTransferObject, + SourceInputConversionResult, + SourceTransformationResponse, +} from '../types/index'; export interface SourceService { getTags(): MetaTransferObject; sourceTransformRoutine( - sourceEvents: NonNullable[], + sourceEvents: SourceInputConversionResult>[], sourceType: string, version: string, requestMetadata: NonNullable, diff --git a/src/middlewares/routeActivation.ts b/src/middlewares/routeActivation.ts index ffb1e15e80b..126749b0830 100644 --- a/src/middlewares/routeActivation.ts +++ b/src/middlewares/routeActivation.ts @@ -106,4 +106,19 @@ export class RouteActivationMiddleware { RouteActivationMiddleware.shouldActivateRoute(destination, deliveryFilterList), ); } + + // This middleware will be used by source endpoint when we completely deprecate v0, v1 versions. + public static isVersionAllowed(ctx: Context, next: Next) { + const { version } = ctx.params; + if (version === 'v0' || version === 'v1') { + ctx.status = 500; + ctx.body = + '/v0, /v1 versioned endpoints are deprecated. Use /v2 version endpoint. This is probably caused because of source transformation call from an outdated rudder-server version. Please upgrade rudder-server to a minimum of 1.xx.xx version.'; + } else if (version === 'v2') { + next(); + } else { + ctx.status = 404; + ctx.body = 'Path not found. Verify the version of your api call.'; + } + } } diff --git a/src/services/source/__tests__/nativeIntegration.test.ts b/src/services/source/__tests__/nativeIntegration.test.ts index 2ef8129cdc4..51bb37f5f13 100644 --- a/src/services/source/__tests__/nativeIntegration.test.ts +++ b/src/services/source/__tests__/nativeIntegration.test.ts @@ -44,7 +44,15 @@ describe('NativeIntegration Source Service', () => { }); const service = new NativeIntegrationSourceService(); - const resp = await service.sourceTransformRoutine(events, sourceType, version, requestMetadata); + const adapterConvertedEvents = events.map((eventInstance) => { + return { output: eventInstance }; + }); + const resp = await service.sourceTransformRoutine( + adapterConvertedEvents, + sourceType, + version, + requestMetadata, + ); expect(resp).toEqual(tresponse); @@ -81,7 +89,15 @@ describe('NativeIntegration Source Service', () => { jest.spyOn(stats, 'increment').mockImplementation(() => {}); const service = new NativeIntegrationSourceService(); - const resp = await service.sourceTransformRoutine(events, sourceType, version, requestMetadata); + const adapterConvertedEvents = events.map((eventInstance) => { + return { output: eventInstance }; + }); + const resp = await service.sourceTransformRoutine( + adapterConvertedEvents, + sourceType, + version, + requestMetadata, + ); expect(resp).toEqual(tresponse); diff --git a/src/services/source/nativeIntegration.ts b/src/services/source/nativeIntegration.ts index 5c89de7b924..58a6a19649d 100644 --- a/src/services/source/nativeIntegration.ts +++ b/src/services/source/nativeIntegration.ts @@ -4,6 +4,7 @@ import { ErrorDetailer, MetaTransferObject, RudderMessage, + SourceInputConversionResult, SourceTransformationEvent, SourceTransformationResponse, } from '../../types/index'; @@ -28,7 +29,7 @@ export class NativeIntegrationSourceService implements SourceService { } public async sourceTransformRoutine( - sourceEvents: NonNullable[], + sourceEvents: SourceInputConversionResult>[], sourceType: string, version: string, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -39,7 +40,20 @@ export class NativeIntegrationSourceService implements SourceService { const respList: SourceTransformationResponse[] = await Promise.all( sourceEvents.map(async (sourceEvent) => { try { - const newSourceEvent = sourceEvent; + if (sourceEvent.conversionError) { + stats.increment('source_transform_errors', { + source: sourceType, + version, + }); + logger.debug(`Error during source Transform: ${sourceEvent.conversionError}`, { + ...logger.getLogMetadata(metaTO.errorDetails), + }); + return SourcePostTransformationService.handleFailureEventsSource( + sourceEvent.conversionError, + metaTO, + ); + } + const newSourceEvent = sourceEvent.output; const { headers } = newSourceEvent; delete newSourceEvent.headers; const respEvents: RudderMessage | RudderMessage[] | SourceTransformationResponse = diff --git a/src/types/index.ts b/src/types/index.ts index 45ec7445c3f..0bc2cbc33b4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -355,6 +355,26 @@ type SourceInput = { event: NonNullable[]; source?: Source; }; + +type SourceRequestV2 = { + method: string; + url: string; + proto: string; + body: string; + headers: NonNullable; + query_parameters: NonNullable; +}; + +type SourceInputV2 = { + request: SourceRequestV2; + source?: Source; +}; + +type SourceInputConversionResult = { + output: T; + conversionError?: Error; +}; + export { ComparatorInput, DeliveryJobState, @@ -382,7 +402,9 @@ export { UserDeletionRequest, UserDeletionResponse, SourceInput, + SourceInputV2, Source, + SourceInputConversionResult, UserTransformationLibrary, UserTransformationResponse, UserTransformationServiceResponse, diff --git a/test/apitests/service.api.test.ts b/test/apitests/service.api.test.ts index 9c1d96e7fe5..2ad1f323ace 100644 --- a/test/apitests/service.api.test.ts +++ b/test/apitests/service.api.test.ts @@ -78,6 +78,13 @@ describe('features tests', () => { const supportTransformerProxyV1 = JSON.parse(response.text).supportTransformerProxyV1; expect(typeof supportTransformerProxyV1).toBe('boolean'); }); + + test('features upgradedToSourceTransformV2 to be boolean', async () => { + const response = await request(server).get('/features'); + expect(response.status).toEqual(200); + const upgradedToSourceTransformV2 = JSON.parse(response.text).upgradedToSourceTransformV2; + expect(typeof upgradedToSourceTransformV2).toBe('boolean'); + }); }); describe('Api tests with a mock source/destination', () => { From 778b028cb0ba0f9a3b5feefbc11bfb72901fe01b Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Thu, 17 Oct 2024 18:48:48 +0530 Subject: [PATCH 084/147] chore: unwanted file .python-version removed, updated .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 09c536ebb80..624a40d7515 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,7 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test +.vscode # yarn v2 .yarn/cache @@ -133,7 +134,7 @@ dist # Others **/.DS_Store .dccache - +.python-version .idea # component test report From de8faba7ed4f908f69485aa2776c71e806fbcc44 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Mon, 21 Oct 2024 13:38:24 +0530 Subject: [PATCH 085/147] chore: lint check github workflow issue for non js files fixed --- .github/workflows/verify.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 115cad42488..e8b1920b871 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -32,11 +32,18 @@ jobs: uses: Ana06/get-changed-files@v1.2 with: token: ${{ secrets.GITHUB_TOKEN }} + + - name: Filter JS/TS Files + run: | + echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' > changed_files.txt + if [ ! -s changed_files.txt ]; then + echo "No JS/TS files to format or lint." + exit 0 + fi - name: Run format Checks run: | - npx prettier ${{steps.files.outputs.added_modified}} --write - + npx prettier --write $(cat changed_files.txt) - run: git diff --exit-code - name: Formatting Error message From 3f8e75d984258bb88b9458ccfbc101ddcbb98c05 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Fri, 25 Oct 2024 11:46:47 +0530 Subject: [PATCH 086/147] chore: refactoring version conversion adapter to readable format --- .github/workflows/verify.yml | 3 +- src/controllers/source.ts | 1 + .../util/conversionStrategies/abstractions.ts | 5 ++ .../conversionStrategies/strategyDefault.ts | 15 +++++ .../conversionStrategies/strategyV0ToV1.ts | 11 +++ .../conversionStrategies/strategyV1ToV0.ts | 10 +++ .../conversionStrategies/strategyV1ToV2.ts | 37 ++++++++++ .../conversionStrategies/strategyV2ToV0.ts | 18 +++++ .../conversionStrategies/strategyV2ToV1.ts | 18 +++++ src/controllers/util/index.ts | 67 +++++++++++++++---- src/controllers/util/versionConversion.ts | 65 ++++++++++++++++++ src/types/index.ts | 1 + 12 files changed, 236 insertions(+), 15 deletions(-) create mode 100644 src/controllers/util/conversionStrategies/abstractions.ts create mode 100644 src/controllers/util/conversionStrategies/strategyDefault.ts create mode 100644 src/controllers/util/conversionStrategies/strategyV0ToV1.ts create mode 100644 src/controllers/util/conversionStrategies/strategyV1ToV0.ts create mode 100644 src/controllers/util/conversionStrategies/strategyV1ToV2.ts create mode 100644 src/controllers/util/conversionStrategies/strategyV2ToV0.ts create mode 100644 src/controllers/util/conversionStrategies/strategyV2ToV1.ts create mode 100644 src/controllers/util/versionConversion.ts diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index e8b1920b871..4fca34673a4 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -32,7 +32,7 @@ jobs: uses: Ana06/get-changed-files@v1.2 with: token: ${{ secrets.GITHUB_TOKEN }} - + - name: Filter JS/TS Files run: | echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' > changed_files.txt @@ -45,7 +45,6 @@ jobs: run: | npx prettier --write $(cat changed_files.txt) - run: git diff --exit-code - - name: Formatting Error message if: ${{ failure() }} run: | diff --git a/src/controllers/source.ts b/src/controllers/source.ts index 230636f1936..8b6d2d70f84 100644 --- a/src/controllers/source.ts +++ b/src/controllers/source.ts @@ -12,6 +12,7 @@ export class SourceController { const events = ctx.request.body as object[]; const { version, source }: { version: string; source: string } = ctx.params; const integrationService = ServiceSelector.getNativeSourceService(); + try { const { implementationVersion, input } = ControllerUtility.adaptInputToVersion( source, diff --git a/src/controllers/util/conversionStrategies/abstractions.ts b/src/controllers/util/conversionStrategies/abstractions.ts new file mode 100644 index 00000000000..f25bc374a24 --- /dev/null +++ b/src/controllers/util/conversionStrategies/abstractions.ts @@ -0,0 +1,5 @@ +import { SourceInputConversionResult } from '../../../types'; + +export abstract class VersionConversionStrategy { + abstract convert(sourceEvents: I[]): SourceInputConversionResult[]; +} diff --git a/src/controllers/util/conversionStrategies/strategyDefault.ts b/src/controllers/util/conversionStrategies/strategyDefault.ts new file mode 100644 index 00000000000..44b9fbf312c --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyDefault.ts @@ -0,0 +1,15 @@ +import { SourceInputConversionResult } from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyDefault extends VersionConversionStrategy< + NonNullable, + NonNullable +> { + convert( + sourceEvents: NonNullable[], + ): SourceInputConversionResult>[] { + return sourceEvents.map((sourceEvent) => ({ + output: sourceEvent, + })); + } +} diff --git a/src/controllers/util/conversionStrategies/strategyV0ToV1.ts b/src/controllers/util/conversionStrategies/strategyV0ToV1.ts new file mode 100644 index 00000000000..28f170c4ddf --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyV0ToV1.ts @@ -0,0 +1,11 @@ +import { SourceInput, SourceInputConversionResult } from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyV0ToV1 extends VersionConversionStrategy, SourceInput> { + convert(sourceEvents: NonNullable[]): SourceInputConversionResult[] { + // This should be deprecated along with v0-webhook-rudder-server deprecation + return sourceEvents.map((sourceEvent) => ({ + output: { event: sourceEvent, source: undefined } as SourceInput, + })); + } +} diff --git a/src/controllers/util/conversionStrategies/strategyV1ToV0.ts b/src/controllers/util/conversionStrategies/strategyV1ToV0.ts new file mode 100644 index 00000000000..d0894099a55 --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyV1ToV0.ts @@ -0,0 +1,10 @@ +import { SourceInput, SourceInputConversionResult } from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyV1ToV0 extends VersionConversionStrategy> { + convert(sourceEvents: SourceInput[]): SourceInputConversionResult>[] { + return sourceEvents.map((sourceEvent) => ({ + output: sourceEvent.event as NonNullable, + })); + } +} diff --git a/src/controllers/util/conversionStrategies/strategyV1ToV2.ts b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts new file mode 100644 index 00000000000..0db03cc8113 --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts @@ -0,0 +1,37 @@ +import { + SourceInput, + SourceInputConversionResult, + SourceInputV2, + SourceRequestV2, +} from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyV1ToV2 extends VersionConversionStrategy { + convert(sourceEvents: SourceInput[]): SourceInputConversionResult[] { + // Currently this is not being used + // Hold off on testing this until atleast one v2 source has been implemented + return sourceEvents.map((sourceEvent) => { + try { + const sourceRequest: SourceRequestV2 = { + method: '', + url: '', + proto: '', + headers: {}, + query_parameters: {}, + body: JSON.stringify(sourceEvent.event), + }; + const sourceInputV2: SourceInputV2 = { + request: sourceRequest, + source: sourceEvent.source, + }; + return { + output: sourceInputV2, + }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v1 to v2 spec'); + return { output: {} as SourceInputV2, conversionError }; + } + }); + } +} diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV0.ts b/src/controllers/util/conversionStrategies/strategyV2ToV0.ts new file mode 100644 index 00000000000..031039e5386 --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyV2ToV0.ts @@ -0,0 +1,18 @@ +import { SourceInputConversionResult, SourceInputV2 } from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyV2ToV0 extends VersionConversionStrategy> { + convert(sourceEvents: SourceInputV2[]): SourceInputConversionResult>[] { + return sourceEvents.map((sourceEvent) => { + try { + const v0Event = JSON.parse(sourceEvent.request.body); + v0Event.query_parameters = sourceEvent.request.query_parameters; + return { output: v0Event }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v2 to v0 spec'); + return { output: {} as NonNullable, conversionError }; + } + }); + } +} diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts new file mode 100644 index 00000000000..7ddafd782ee --- /dev/null +++ b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts @@ -0,0 +1,18 @@ +import { SourceInput, SourceInputConversionResult, SourceInputV2 } from '../../../types'; +import { VersionConversionStrategy } from './abstractions'; + +export class StrategyV2ToV1 extends VersionConversionStrategy { + convert(sourceEvents: SourceInputV2[]): SourceInputConversionResult[] { + return sourceEvents.map((sourceEvent) => { + try { + const v1Event = { event: JSON.parse(sourceEvent.request.body), source: sourceEvent.source }; + v1Event.event.query_parameters = sourceEvent.request.query_parameters; + return { output: v1Event }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v2 to v1 spec'); + return { output: {} as SourceInput, conversionError }; + } + }); + } +} diff --git a/src/controllers/util/index.ts b/src/controllers/util/index.ts index b562381ed67..b6fa909d27e 100644 --- a/src/controllers/util/index.ts +++ b/src/controllers/util/index.ts @@ -12,10 +12,12 @@ import { SourceInput, SourceInputConversionResult, SourceInputV2, + SourceRequestV2, } from '../../types'; import { getValueFromMessage } from '../../v0/util'; import genericFieldMap from '../../v0/util/data/GenericFieldMapping.json'; import { EventType, MappedToDestinationKey } from '../../constants'; +import { versionConversionFactory } from './versionConversion'; export class ControllerUtility { private static sourceVersionMap: Map = new Map(); @@ -55,6 +57,36 @@ export class ControllerUtility { })); } + private static convertSourceInputv1Tov2( + sourceEvents: SourceInput[], + ): SourceInputConversionResult[] { + // Currently this is not being used + // Hold off on testing this until atleast one v2 source has been implemented + return sourceEvents.map((sourceEvent) => { + try { + const sourceRequest: SourceRequestV2 = { + method: '', + url: '', + proto: '', + headers: {}, + query_parameters: {}, + body: JSON.stringify(sourceEvent.event), + }; + const sourceInputV2: SourceInputV2 = { + request: sourceRequest, + source: sourceEvent.source, + }; + return { + output: sourceInputV2, + }; + } catch (err) { + const conversionError = + err instanceof Error ? err : new Error('error converting v1 to v2 spec'); + return { output: {} as SourceInputV2, conversionError }; + } + }); + } + private static convertSourceInputv0Tov1( sourceEvents: unknown[], ): SourceInputConversionResult[] { @@ -102,19 +134,28 @@ export class ControllerUtility { ): { implementationVersion: string; input: SourceInputConversionResult>[] } { const sourceToVersionMap = this.getSourceVersionsMap(); const implementationVersion = sourceToVersionMap.get(sourceType); - let updatedInput: SourceInputConversionResult>[] = input.map((event) => ({ - output: event, - })); - if (requestVersion === 'v0' && implementationVersion === 'v1') { - updatedInput = this.convertSourceInputv0Tov1(input); - } else if (requestVersion === 'v1' && implementationVersion === 'v0') { - updatedInput = this.convertSourceInputv1Tov0(input as SourceInput[]); - } else if (requestVersion === 'v2' && implementationVersion === 'v0') { - updatedInput = this.convertSourceInputv2Tov0(input as SourceInputV2[]); - } else if (requestVersion === 'v2' && implementationVersion === 'v1') { - updatedInput = this.convertSourceInputv2Tov1(input as SourceInputV2[]); - } - return { implementationVersion, input: updatedInput }; + + const conversionStrategy = versionConversionFactory.getStrategy( + requestVersion, + implementationVersion, + ); + return { implementationVersion, input: conversionStrategy.convert(input) }; + + // let updatedInput: SourceInputConversionResult>[] = input.map((event) => ({ + // output: event, + // })); + // if (requestVersion === 'v0' && implementationVersion === 'v1') { + // updatedInput = this.convertSourceInputv0Tov1(input); + // } else if (requestVersion === 'v1' && implementationVersion === 'v0') { + // updatedInput = this.convertSourceInputv1Tov0(input as SourceInput[]); + // } else if (requestVersion === 'v1' && implementationVersion === 'v2') { + // updatedInput = this.convertSourceInputv1Tov2(input as SourceInput[]); + // } else if (requestVersion === 'v2' && implementationVersion === 'v0') { + // updatedInput = this.convertSourceInputv2Tov0(input as SourceInputV2[]); + // } else if (requestVersion === 'v2' && implementationVersion === 'v1') { + // updatedInput = this.convertSourceInputv2Tov1(input as SourceInputV2[]); + // } + // return { implementationVersion, input: updatedInput }; } private static getCompatibleStatusCode(status: number): number { diff --git a/src/controllers/util/versionConversion.ts b/src/controllers/util/versionConversion.ts new file mode 100644 index 00000000000..3058531f572 --- /dev/null +++ b/src/controllers/util/versionConversion.ts @@ -0,0 +1,65 @@ +import { VersionConversionStrategy } from './conversionStrategies/abstractions'; +import { StrategyDefault } from './conversionStrategies/strategyDefault'; +import { StrategyV0ToV1 } from './conversionStrategies/strategyV0ToV1'; +import { StrategyV1ToV0 } from './conversionStrategies/strategyV1ToV0'; +import { StrategyV1ToV2 } from './conversionStrategies/strategyV1ToV2'; +import { StrategyV2ToV0 } from './conversionStrategies/strategyV2ToV0'; +import { StrategyV2ToV1 } from './conversionStrategies/strategyV2ToV1'; + +export class VersionConversionFactory { + private strategyCache: Map> = new Map(); + + private getCase(requestVersion: string, implementationVersion: string) { + return `${String(requestVersion)}-to-${String(implementationVersion)}`; + } + + public getStrategy( + requestVersion: string, + implementationVersion: string, + ): VersionConversionStrategy { + const versionCase = this.getCase(requestVersion, implementationVersion); + + if (this.strategyCache.has(versionCase)) { + const cachedStrategy = this.strategyCache.get(versionCase); + if (cachedStrategy) { + return cachedStrategy; + } + } + + let strategy: VersionConversionStrategy; + + switch (versionCase) { + case 'v0-to-v1': + strategy = new StrategyV0ToV1(); + break; + + case 'v1-to-v0': + strategy = new StrategyV1ToV0(); + break; + + case 'v1-to-v2': + strategy = new StrategyV1ToV2(); + break; + + case 'v2-to-v0': + strategy = new StrategyV2ToV0(); + break; + + case 'v2-to-v1': + strategy = new StrategyV2ToV1(); + break; + + default: + strategy = new StrategyDefault(); + break; + } + + if (strategy) { + this.strategyCache[versionCase] = strategy; + } + + return strategy; + } +} + +export const versionConversionFactory = new VersionConversionFactory(); diff --git a/src/types/index.ts b/src/types/index.ts index 0bc2cbc33b4..54ff3a994ea 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -403,6 +403,7 @@ export { UserDeletionResponse, SourceInput, SourceInputV2, + SourceRequestV2, Source, SourceInputConversionResult, UserTransformationLibrary, From 5705f2e28a5c8e123a4018b2c6815f4143b4df67 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Mon, 28 Oct 2024 21:16:06 +0530 Subject: [PATCH 087/147] chore: stricter types, extra test cases for v2 --- .gitignore | 2 +- .../conversionStrategies/strategyV1ToV2.ts | 23 ++-- .../conversionStrategies/strategyV2ToV1.ts | 4 +- src/controllers/util/index.test.ts | 124 ++++++++++++++++++ src/controllers/util/index.ts | 97 -------------- src/middlewares/routeActivation.ts | 15 --- src/types/index.ts | 15 ++- 7 files changed, 151 insertions(+), 129 deletions(-) diff --git a/.gitignore b/.gitignore index 624a40d7515..84421f49d9b 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,4 @@ dist # component test report test_reports/ -temp/ +temp/ \ No newline at end of file diff --git a/src/controllers/util/conversionStrategies/strategyV1ToV2.ts b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts index 0db03cc8113..b4f04ef8589 100644 --- a/src/controllers/util/conversionStrategies/strategyV1ToV2.ts +++ b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts @@ -8,21 +8,26 @@ import { VersionConversionStrategy } from './abstractions'; export class StrategyV1ToV2 extends VersionConversionStrategy { convert(sourceEvents: SourceInput[]): SourceInputConversionResult[] { - // Currently this is not being used - // Hold off on testing this until atleast one v2 source has been implemented return sourceEvents.map((sourceEvent) => { try { + const sourceEventParam = { ...sourceEvent }; + + let queryParameters: Record | undefined; + if (sourceEventParam.event && sourceEventParam.event.query_parameters) { + queryParameters = sourceEventParam.event.query_parameters; + delete sourceEventParam.event.query_parameters; + } + const sourceRequest: SourceRequestV2 = { - method: '', - url: '', - proto: '', - headers: {}, - query_parameters: {}, - body: JSON.stringify(sourceEvent.event), + body: JSON.stringify(sourceEventParam.event), }; + if (queryParameters) { + sourceRequest.query_parameters = queryParameters; + } + const sourceInputV2: SourceInputV2 = { request: sourceRequest, - source: sourceEvent.source, + source: sourceEventParam.source, }; return { output: sourceInputV2, diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts index 7ddafd782ee..0872d549f0f 100644 --- a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts +++ b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts @@ -6,7 +6,9 @@ export class StrategyV2ToV1 extends VersionConversionStrategy { try { const v1Event = { event: JSON.parse(sourceEvent.request.body), source: sourceEvent.source }; - v1Event.event.query_parameters = sourceEvent.request.query_parameters; + if (sourceEvent.request) { + v1Event.event.query_parameters = sourceEvent.request.query_parameters; + } return { output: v1Event }; } catch (err) { const conversionError = diff --git a/src/controllers/util/index.test.ts b/src/controllers/util/index.test.ts index 6ab2336b71d..138572a8eac 100644 --- a/src/controllers/util/index.test.ts +++ b/src/controllers/util/index.test.ts @@ -201,6 +201,38 @@ describe('adaptInputToVersion', () => { expect(result).toEqual(expected); }); + it('should fail trying to convert input from v2 to v0 format when the request version is v2 and the implementation version is v0', () => { + const sourceType = 'pipedream'; + const requestVersion = 'v2'; + + const input = [ + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + const expected = { + implementationVersion: 'v0', + input: [ + { + output: {}, + conversionError: new SyntaxError('Unexpected end of JSON input'), + }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); + it('should convert input from v2 to v1 format when the request version is v2 and the implementation version is v1', () => { const sourceType = 'webhook'; const requestVersion = 'v2'; @@ -269,6 +301,38 @@ describe('adaptInputToVersion', () => { expect(result).toEqual(expected); }); + it('should fail trying to convert input from v2 to v1 format when the request version is v2 and the implementation version is v1', () => { + const sourceType = 'webhook'; + const requestVersion = 'v2'; + + const input = [ + { + request: { + method: 'POST', + url: 'http://example.com', + proto: 'HTTP/2', + headers: { headerkey: ['headervalue'] }, + body: '{"key": "value"', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + const expected = { + implementationVersion: 'v1', + input: [ + { + output: {}, + conversionError: new SyntaxError('Unexpected end of JSON input'), + }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); + // Should return an empty array when the input is an empty array it('should return an empty array when the input is an empty array', () => { const sourceType = 'pipedream'; @@ -280,6 +344,66 @@ describe('adaptInputToVersion', () => { expect(result).toEqual(expected); }); + + it('should convert input from v1 to v2 format when the request version is v1 and the implementation version is v2', () => { + const sourceType = 'someSourceType'; + const requestVersion = 'v1'; + + // Mock return value for getSourceVersionsMap + jest + .spyOn(ControllerUtility as any, 'getSourceVersionsMap') + .mockReturnValue(new Map([['someSourceType', 'v2']])); + + const input = [ + { + event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + event: { key: 'value' }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + event: {}, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + + const expected = { + implementationVersion: 'v2', + input: [ + { + output: { + request: { + body: '{"key":"value"}', + query_parameters: { paramkey: ['paramvalue'] }, + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, + { + output: { + request: { + body: '{"key":"value"}', + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, + { + output: { + request: { + body: '{}', + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); }); type timestampTestCases = { diff --git a/src/controllers/util/index.ts b/src/controllers/util/index.ts index b6fa909d27e..ab2a0f5dc3a 100644 --- a/src/controllers/util/index.ts +++ b/src/controllers/util/index.ts @@ -9,10 +9,7 @@ import { ProcessorTransformationRequest, RouterTransformationRequestData, RudderMessage, - SourceInput, SourceInputConversionResult, - SourceInputV2, - SourceRequestV2, } from '../../types'; import { getValueFromMessage } from '../../v0/util'; import genericFieldMap from '../../v0/util/data/GenericFieldMapping.json'; @@ -49,84 +46,6 @@ export class ControllerUtility { return this.sourceVersionMap; } - private static convertSourceInputv1Tov0( - sourceEvents: SourceInput[], - ): SourceInputConversionResult>[] { - return sourceEvents.map((sourceEvent) => ({ - output: sourceEvent.event as NonNullable, - })); - } - - private static convertSourceInputv1Tov2( - sourceEvents: SourceInput[], - ): SourceInputConversionResult[] { - // Currently this is not being used - // Hold off on testing this until atleast one v2 source has been implemented - return sourceEvents.map((sourceEvent) => { - try { - const sourceRequest: SourceRequestV2 = { - method: '', - url: '', - proto: '', - headers: {}, - query_parameters: {}, - body: JSON.stringify(sourceEvent.event), - }; - const sourceInputV2: SourceInputV2 = { - request: sourceRequest, - source: sourceEvent.source, - }; - return { - output: sourceInputV2, - }; - } catch (err) { - const conversionError = - err instanceof Error ? err : new Error('error converting v1 to v2 spec'); - return { output: {} as SourceInputV2, conversionError }; - } - }); - } - - private static convertSourceInputv0Tov1( - sourceEvents: unknown[], - ): SourceInputConversionResult[] { - return sourceEvents.map((sourceEvent) => ({ - output: { event: sourceEvent, source: undefined } as SourceInput, - })); - } - - private static convertSourceInputv2Tov0( - sourceEvents: SourceInputV2[], - ): SourceInputConversionResult>[] { - return sourceEvents.map((sourceEvent) => { - try { - const v0Event = JSON.parse(sourceEvent.request.body); - v0Event.query_parameters = sourceEvent.request.query_parameters; - return { output: v0Event }; - } catch (err) { - const conversionError = - err instanceof Error ? err : new Error('error converting v2 to v0 spec'); - return { output: {} as NonNullable, conversionError }; - } - }); - } - - private static convertSourceInputv2Tov1( - sourceEvents: SourceInputV2[], - ): SourceInputConversionResult[] { - return sourceEvents.map((sourceEvent) => { - try { - const v1Event = { event: JSON.parse(sourceEvent.request.body), source: sourceEvent.source }; - v1Event.event.query_parameters = sourceEvent.request.query_parameters; - return { output: v1Event }; - } catch (err) { - const conversionError = - err instanceof Error ? err : new Error('error converting v2 to v1 spec'); - return { output: {} as SourceInput, conversionError }; - } - }); - } - public static adaptInputToVersion( sourceType: string, requestVersion: string, @@ -140,22 +59,6 @@ export class ControllerUtility { implementationVersion, ); return { implementationVersion, input: conversionStrategy.convert(input) }; - - // let updatedInput: SourceInputConversionResult>[] = input.map((event) => ({ - // output: event, - // })); - // if (requestVersion === 'v0' && implementationVersion === 'v1') { - // updatedInput = this.convertSourceInputv0Tov1(input); - // } else if (requestVersion === 'v1' && implementationVersion === 'v0') { - // updatedInput = this.convertSourceInputv1Tov0(input as SourceInput[]); - // } else if (requestVersion === 'v1' && implementationVersion === 'v2') { - // updatedInput = this.convertSourceInputv1Tov2(input as SourceInput[]); - // } else if (requestVersion === 'v2' && implementationVersion === 'v0') { - // updatedInput = this.convertSourceInputv2Tov0(input as SourceInputV2[]); - // } else if (requestVersion === 'v2' && implementationVersion === 'v1') { - // updatedInput = this.convertSourceInputv2Tov1(input as SourceInputV2[]); - // } - // return { implementationVersion, input: updatedInput }; } private static getCompatibleStatusCode(status: number): number { diff --git a/src/middlewares/routeActivation.ts b/src/middlewares/routeActivation.ts index 126749b0830..ffb1e15e80b 100644 --- a/src/middlewares/routeActivation.ts +++ b/src/middlewares/routeActivation.ts @@ -106,19 +106,4 @@ export class RouteActivationMiddleware { RouteActivationMiddleware.shouldActivateRoute(destination, deliveryFilterList), ); } - - // This middleware will be used by source endpoint when we completely deprecate v0, v1 versions. - public static isVersionAllowed(ctx: Context, next: Next) { - const { version } = ctx.params; - if (version === 'v0' || version === 'v1') { - ctx.status = 500; - ctx.body = - '/v0, /v1 versioned endpoints are deprecated. Use /v2 version endpoint. This is probably caused because of source transformation call from an outdated rudder-server version. Please upgrade rudder-server to a minimum of 1.xx.xx version.'; - } else if (version === 'v2') { - next(); - } else { - ctx.status = 404; - ctx.body = 'Path not found. Verify the version of your api call.'; - } - } } diff --git a/src/types/index.ts b/src/types/index.ts index 54ff3a994ea..ee225bb0c0d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -352,17 +352,20 @@ type Source = { }; type SourceInput = { - event: NonNullable[]; + event: { + query_parameters?: any; + [key: string]: any; + }; source?: Source; }; type SourceRequestV2 = { - method: string; - url: string; - proto: string; + method?: string; + url?: string; + proto?: string; body: string; - headers: NonNullable; - query_parameters: NonNullable; + headers?: Record; + query_parameters?: Record; }; type SourceInputV2 = { From f4b38eba3ca8dff602915853fda5cd7ca284bba3 Mon Sep 17 00:00:00 2001 From: Sandeep Digumarty Date: Thu, 7 Nov 2024 10:48:57 +0530 Subject: [PATCH 088/147] feat(GARL): support vdm next for GARL (#3835) * feat(GARL): support vdm next for GARL * feat(GARL): support vdm next for GARL * feat(GARL): support vdm next for GARL * chore: updated tests with new structure --- .../recordTransform.js | 71 +++++++++++++++++-- .../transform.js | 20 +++++- .../google_adwords_remarketing_lists/util.js | 47 +++++++----- .../util.test.js | 20 ++++-- .../processor/data.ts | 37 +++++----- .../router/audience.ts | 2 +- .../router/data.ts | 12 ++-- .../router/record.ts | 2 +- 8 files changed, 151 insertions(+), 60 deletions(-) diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index b05ddb07a28..f8a2b0e5862 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -7,9 +7,11 @@ const { constructPayload, returnArrayOfSubarrays, getSuccessRespEvents, + isEventSentByVDMV1Flow, + isEventSentByVDMV2Flow, } = require('../../util'); const { populateConsentFromConfig } = require('../../util/googleUtils'); -const { populateIdentifiers, responseBuilder } = require('./util'); +const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util'); const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); @@ -19,6 +21,9 @@ const processRecordEventArray = ( destination, accessToken, developerToken, + audienceId, + typeOfList, + isHashRequired, operationType, ) => { let outputPayloads = {}; @@ -31,7 +36,12 @@ const processRecordEventArray = ( metadata.push(record.metadata); }); - const userIdentifiersList = populateIdentifiers(fieldsArray, destination); + const userIdentifiersList = populateIdentifiers( + fieldsArray, + destination, + typeOfList, + isHashRequired, + ); const outputPayload = constructPayload(message, offlineDataJobsMapping); outputPayload.operations = []; @@ -68,7 +78,7 @@ const processRecordEventArray = ( Object.values(outputPayloads).forEach((data) => { const consentObj = populateConsentFromConfig(destination.Config, consentConfigMap); toSendEvents.push( - responseBuilder(accessToken, developerToken, data, destination, message, consentObj), + responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), ); }); @@ -77,12 +87,13 @@ const processRecordEventArray = ( return successResponse; }; -async function processRecordInputs(groupedRecordInputs) { - const { destination, message, metadata } = groupedRecordInputs[0]; +function preparepayload(events, config) { + const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); + const { audienceId, typeOfList, isHashRequired } = config; - const groupedRecordsByAction = lodash.groupBy(groupedRecordInputs, (record) => + const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), ); @@ -97,6 +108,9 @@ async function processRecordInputs(groupedRecordInputs) { destination, accessToken, developerToken, + audienceId, + typeOfList, + isHashRequired, 'remove', ); } @@ -108,6 +122,9 @@ async function processRecordInputs(groupedRecordInputs) { destination, accessToken, developerToken, + audienceId, + typeOfList, + isHashRequired, 'add', ); } @@ -119,6 +136,9 @@ async function processRecordInputs(groupedRecordInputs) { destination, accessToken, developerToken, + audienceId, + typeOfList, + isHashRequired, 'add', ); } @@ -139,6 +159,45 @@ async function processRecordInputs(groupedRecordInputs) { return finalResponse; } +function processRecordInputsV0(groupedRecordInputs) { + const { destination, message } = groupedRecordInputs[0]; + const { audienceId, typeOfList, isHashRequired } = destination.Config; + + return preparepayload(groupedRecordInputs, { + audienceId: getOperationAudienceId(audienceId, message), + typeOfList, + isHashRequired, + }); +} + +function processRecordInputsV1(groupedRecordInputs) { + const { connection } = groupedRecordInputs[0]; + const { audienceId, typeOfList, isHashRequired } = connection.config.destination; + + const events = groupedRecordInputs.map((record) => ({ + ...record, + message: { + ...record.message, + fields: record.message.identifiers, + }, + })); + + return preparepayload(events, { + audienceId, + typeOfList, + isHashRequired, + }); +} + +function processRecordInputs(groupedRecordInputs) { + const event = groupedRecordInputs[0]; + // First check for rETL flow and second check for ES flow + if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) { + return processRecordInputsV0(groupedRecordInputs); + } + return processRecordInputsV1(groupedRecordInputs); +} + module.exports = { processRecordInputs, }; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/transform.js b/src/v0/destinations/google_adwords_remarketing_lists/transform.js index 3deb9be7759..299ab948461 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/transform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/transform.js @@ -12,7 +12,7 @@ const { const { populateConsentFromConfig } = require('../../util/googleUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); const { processRecordInputs } = require('./recordTransform'); -const { populateIdentifiers, responseBuilder } = require('./util'); +const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util'); function extraKeysPresent(dictionary, keyList) { // eslint-disable-next-line no-restricted-syntax @@ -37,12 +37,18 @@ function extraKeysPresent(dictionary, keyList) { const createPayload = (message, destination) => { const { listData } = message.properties; const properties = ['add', 'remove']; + const { typeOfList, isHashRequired } = destination.Config; let outputPayloads = {}; const typeOfOperation = Object.keys(listData); typeOfOperation.forEach((key) => { if (properties.includes(key)) { - const userIdentifiersList = populateIdentifiers(listData[key], destination); + const userIdentifiersList = populateIdentifiers( + listData[key], + destination, + typeOfList, + isHashRequired, + ); if (userIdentifiersList.length === 0) { logger.info( `Google_adwords_remarketing_list]:: No attributes are present in the '${key}' property.`, @@ -113,8 +119,16 @@ const processEvent = async (metadata, message, destination) => { Object.values(createdPayload).forEach((data) => { const consentObj = populateConsentFromConfig(destination.Config, consentConfigMap); + const { audienceId } = destination.Config; response.push( - responseBuilder(accessToken, developerToken, data, destination, message, consentObj), + responseBuilder( + accessToken, + developerToken, + data, + destination, + getOperationAudienceId(audienceId, message), + consentObj, + ), ); }); return response; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/util.js b/src/v0/destinations/google_adwords_remarketing_lists/util.js index 3e04dd8f6f6..f4c33a9a6fb 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/util.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/util.js @@ -29,26 +29,24 @@ const hashEncrypt = (object) => { }); }; -const responseBuilder = (accessToken, developerToken, body, { Config }, message, consentBlock) => { +const responseBuilder = ( + accessToken, + developerToken, + body, + { Config }, + audienceId, + consentBlock, +) => { const payload = body; const response = defaultRequestConfig(); const filteredCustomerId = removeHyphens(Config.customerId); response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}/offlineUserDataJobs`; response.body.JSON = removeUndefinedAndNullValues(payload); - let operationAudienceId = Config.audienceId || Config.listId; - const mappedToDestination = get(message, MappedToDestinationKey); - if (!operationAudienceId && mappedToDestination) { - const { objectType } = getDestinationExternalIDInfoForRetl( - message, - 'GOOGLE_ADWORDS_REMARKETING_LISTS', - ); - operationAudienceId = objectType; - } - if (!isDefinedAndNotNullAndNotEmpty(operationAudienceId)) { + if (!isDefinedAndNotNullAndNotEmpty(audienceId)) { throw new ConfigurationError('List ID is a mandatory field'); } response.params = { - listId: operationAudienceId, + listId: audienceId, customerId: filteredCustomerId, consent: consentBlock, }; @@ -69,14 +67,15 @@ const responseBuilder = (accessToken, developerToken, body, { Config }, message, * This function helps creates an array with proper mapping for userIdentiFier. * Logics: Here we are creating an array with all the attributes provided in the add/remove array * inside listData. - * @param {rudder event message properties listData add} attributeArray - * @param {rudder event destination} Config + * @param {Array} attributeArray rudder event message properties listData add + * @param {object} Config rudder event destination + * @param {string} typeOfList + * @param {boolean} isHashRequired * @returns */ -const populateIdentifiers = (attributeArray, { Config }) => { +const populateIdentifiers = (attributeArray, { Config }, typeOfList, isHashRequired) => { const userIdentifier = []; - const { typeOfList } = Config; - const { isHashRequired, userSchema } = Config; + const { userSchema } = Config; let attribute; if (TYPEOFLIST[typeOfList]) { attribute = TYPEOFLIST[typeOfList]; @@ -116,7 +115,21 @@ const populateIdentifiers = (attributeArray, { Config }) => { return userIdentifier; }; +const getOperationAudienceId = (audienceId, message) => { + let operationAudienceId = audienceId; + const mappedToDestination = get(message, MappedToDestinationKey); + if (!operationAudienceId && mappedToDestination) { + const { objectType } = getDestinationExternalIDInfoForRetl( + message, + 'GOOGLE_ADWORDS_REMARKETING_LISTS', + ); + operationAudienceId = objectType; + } + return operationAudienceId; +}; + module.exports = { populateIdentifiers, responseBuilder, + getOperationAudienceId, }; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/util.test.js b/src/v0/destinations/google_adwords_remarketing_lists/util.test.js index a5897776c09..0b74b07b8e7 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/util.test.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/util.test.js @@ -1,4 +1,4 @@ -const { populateIdentifiers, responseBuilder } = require('./util'); +const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util'); const { API_VERSION } = require('./config'); const accessToken = 'abcd1234'; const developerToken = 'ijkl9101'; @@ -29,7 +29,7 @@ const body = { const baseDestination = { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -150,7 +150,7 @@ describe('GARL utils test', () => { developerToken, body, baseDestination, - message, + getOperationAudienceId(baseDestination.Config.audienceId, message), consentBlock, ); expect(response).toEqual(expectedResponse); @@ -166,7 +166,7 @@ describe('GARL utils test', () => { developerToken, body, destination2, - message, + getOperationAudienceId(baseDestination.Config.audienceId, message), consentBlock, ); expect(response).toEqual(); @@ -178,13 +178,13 @@ describe('GARL utils test', () => { it('Should throw error if operationAudienceId is not defined', () => { try { const destination1 = Object.create(baseDestination); - destination1.Config.listId = ''; + destination1.Config.audienceId = ''; const response = responseBuilder( accessToken, developerToken, body, destination1, - message, + getOperationAudienceId(baseDestination.Config.audienceId, message), consentBlock, ); expect(response).toEqual(); @@ -196,7 +196,13 @@ describe('GARL utils test', () => { describe('populateIdentifiers function tests', () => { it('Should hash and return identifiers for a given list of attributes', () => { - const identifier = populateIdentifiers(attributeArray, baseDestination); + const { typeOfList, isHashRequired } = baseDestination.Config; + const identifier = populateIdentifiers( + attributeArray, + baseDestination, + typeOfList, + isHashRequired, + ); expect(identifier).toEqual(hashedArray); }); }); diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/processor/data.ts b/test/integrations/destinations/google_adwords_remarketing_lists/processor/data.ts index e20ed895455..4398bc14e16 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/processor/data.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/processor/data.ts @@ -20,7 +20,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -151,7 +151,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '769-372-9833', loginCustomerId: '870-483-0944', subAccount: true, @@ -269,7 +269,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -387,7 +387,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -495,7 +495,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -585,7 +585,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -673,7 +673,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -749,7 +749,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: true, @@ -845,7 +845,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -2740,7 +2740,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -2993,7 +2993,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -6724,7 +6724,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -6880,7 +6880,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -6977,7 +6977,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -10708,7 +10708,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -10961,7 +10961,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -11207,7 +11207,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -11328,7 +11328,7 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', + audienceId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -11412,7 +11412,6 @@ export const data = [ destination: { Config: { rudderAccountId: 'rudder-acc-id', - listId: 'list111', customerId: '7693729833', loginCustomerId: '', subAccount: false, diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/audience.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/audience.ts index e0b534bb15d..2158a57a5d2 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/audience.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/audience.ts @@ -4,7 +4,7 @@ import { generateGoogleOAuthMetadata } from '../../../testUtils'; const destination: Destination = { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts index f5789bf7ef7..a5e28996b10 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts @@ -92,7 +92,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -187,7 +187,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -332,7 +332,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -451,7 +451,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -578,7 +578,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, @@ -675,7 +675,7 @@ export const data = [ destination: { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts index bedf1128664..de76aae17c8 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts @@ -4,7 +4,7 @@ import { generateGoogleOAuthMetadata } from '../../../testUtils'; const destination: Destination = { Config: { rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', - listId: '7090784486', + audienceId: '7090784486', customerId: '7693729833', loginCustomerId: '', subAccount: false, From 80d7b417be7a0e459de49caca25aba43ffdba337 Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Fri, 8 Nov 2024 10:48:02 +0530 Subject: [PATCH 089/147] fix: unsafe property getting set via set value library (#3853) * fix: unsafe property getting set via set value library * fix: update integrations-lib dependency * chore: remove unnecessary commented code --------- Co-authored-by: Sai Sankeerth --- package-lock.json | 7 +- package.json | 2 +- src/v0/util/index.js | 2 +- .../ga4/processor/pageTestData.ts | 212 ++++++++++++++++++ 4 files changed, 218 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ccf7ed2c2ae..2454751ce36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@koa/router": "^12.0.0", "@ndhoule/extend": "^2.0.0", "@pyroscope/nodejs": "^0.2.9", - "@rudderstack/integrations-lib": "^0.2.10", + "@rudderstack/integrations-lib": "^0.2.12", "@rudderstack/json-template-engine": "^0.18.0", "@rudderstack/workflow-engine": "^0.8.13", "@shopify/jest-koa-mocks": "^5.1.1", @@ -6602,8 +6602,9 @@ } }, "node_modules/@rudderstack/integrations-lib": { - "version": "0.2.10", - "license": "MIT", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@rudderstack/integrations-lib/-/integrations-lib-0.2.12.tgz", + "integrity": "sha512-xy+T9SHFkSeVDd4svGOyrTtIGljZ/l4qUh5o5EQWk3dTStzaV9mKnbXLsG62kEO3aTmCVg+VYr4OPwZY2+6rxQ==", "dependencies": { "axios": "^1.4.0", "axios-mock-adapter": "^1.22.0", diff --git a/package.json b/package.json index 79571462d3a..c2dc3df7bee 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@koa/router": "^12.0.0", "@ndhoule/extend": "^2.0.0", "@pyroscope/nodejs": "^0.2.9", - "@rudderstack/integrations-lib": "^0.2.10", + "@rudderstack/integrations-lib": "^0.2.12", "@rudderstack/json-template-engine": "^0.18.0", "@rudderstack/workflow-engine": "^0.8.13", "@shopify/jest-koa-mocks": "^5.1.1", diff --git a/src/v0/util/index.js b/src/v0/util/index.js index f034ab802b2..1676498fdb9 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -10,7 +10,7 @@ const Handlebars = require('handlebars'); const fs = require('fs'); const path = require('path'); const lodash = require('lodash'); -const set = require('set-value'); +const { setValue: set } = require('@rudderstack/integrations-lib'); const get = require('get-value'); const uaParser = require('ua-parser-js'); const moment = require('moment-timezone'); diff --git a/test/integrations/destinations/ga4/processor/pageTestData.ts b/test/integrations/destinations/ga4/processor/pageTestData.ts index fa0b187aea0..672f7e8f634 100644 --- a/test/integrations/destinations/ga4/processor/pageTestData.ts +++ b/test/integrations/destinations/ga4/processor/pageTestData.ts @@ -301,4 +301,216 @@ export const pageTestData: ProcessorTestData[] = [ }, mockFns: defaultMockFns, }, + { + id: 'ga4-page-test-4', + name: 'ga4', + description: + 'Scenario to test setting of reserved properties like constructor, __proto__, prototype in page call', + scenario: 'Business', + successCriteria: + 'Response status code should be 200 and event payload should not fail due to reserved properties', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + apiSecret: 'api_secr', + debugMode: false, + typesOfClient: 'gtag', + measurementId: 'meas_id', + firebaseAppId: '', + whitelistedEvents: [ + { + eventName: '', + }, + ], + blacklistedEvents: [ + { + eventName: '', + }, + ], + eventFilteringOption: 'disable', + piiPropertiesToIgnore: [ + { + piiProperty: '', + }, + ], + sdkBaseUrl: 'https://www.googletagmanager.com', + serverContainerUrl: '', + debugView: true, + useNativeSDK: false, + connectionMode: 'cloud', + capturePageView: 'rs', + useNativeSDKToSend: false, + extendPageViewParams: false, + overrideClientAndSessionId: false, + eventDelivery: false, + }, + ID: '2ncdvkljndsvkuiurf', + WorkspaceID: 'wspId', + DestinationDefinition: { + ...destination.DestinationDefinition, + }, + Transformations: [], + IsConnectionEnabled: true, + IsProcessorEnabled: true, + Name: 'my ga4', + Enabled: true, + }, + message: { + name: '', + type: 'page', + sentAt: '2022-04-29T05:17:09Z', + userId: '', + channel: 'web', + context: { + os: { + name: '', + version: '', + }, + app: { + name: 'RudderLabs JavaScript SDK', + version: '3.7.6', + namespace: 'com.rudderlabs.javascript', + installType: 'npm', + }, + page: { + url: 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + path: '/', + title: 'Mercedes-Benz Tire Center', + search: '?constructor.prototype.tenable_propexxx=tenable_something', + tab_url: + 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + referrer: '$direct', + initial_referrer: '$direct', + referring_domain: '', + initial_referring_domain: '', + }, + locale: 'en-US', + screen: { + width: 800, + height: 600, + density: 1, + innerWidth: 1600, + innerHeight: 1200, + }, + traits: {}, + library: { + name: 'RudderLabs JavaScript SDK', + version: '3.7.6', + }, + campaign: {}, + timezone: 'GMT+0000', + sessionId: 123465, + userAgent: + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.207 Safari/537.36', + }, + rudderId: '7d02bb53-ff1a-46a2-9cb1-1ea78dcd4ca8', + timestamp: '2022-04-29T05:17:09Z', + properties: { + url: 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + path: '/', + title: 'Mercedes-Benz Tire Center', + search: '?constructor.prototype.tenable_propexxx=tenable_something', + tab_url: + 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + vehicle: { + make: '', + trim: '', + year: '', + model: '', + ratio: '', + width: '', + option: '', + diameter: '', + }, + national: true, + referrer: '$direct', + search_type: 'Vehicle', + initial_referrer: '$direct', + oem_program_code: 'CODE', + referring_domain: '', + initial_referring_domain: '', + 'constructor.prototype.tenable_propexxx': 'tenable_something', + }, + receivedAt: '2022-04-29T05:17:09Z', + request_ip: '34.201.223.160', + anonymousId: 'f577a7e1-6c76-49c3-8312-12846471e025', + integrations: { + All: true, + }, + originalTimestamp: '2022-04-29T05:17:09Z', + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + body: { + XML: {}, + FORM: {}, + JSON: { + events: [ + { + name: 'page_view', + params: { + url: 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + path: '/', + title: 'Mercedes-Benz Tire Center', + search: '?constructor.prototype.tenable_propexxx=tenable_something', + tab_url: + 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + national: true, + referrer: '$direct', + page_title: 'Mercedes-Benz Tire Center', + session_id: 123465, + search_type: 'Vehicle', + page_location: + 'https://somewebsite.com/?constructor.prototype.tenable_propexxx=tenable_something', + page_referrer: '$direct', + initial_referrer: '$direct', + oem_program_code: 'CODE', + engagement_time_msec: 1, + 'constructor.prototype.tenable_propexxx': 'tenable_something', + }, + }, + ], + client_id: 'f577a7e1-6c76-49c3-8312-12846471e025', + timestamp_micros: 1651209429000000, + }, + JSON_ARRAY: {}, + }, + type: 'REST', + files: {}, + method: 'POST', + params: { + api_secret: 'api_secr', + measurement_id: 'meas_id', + }, + userId: '', + headers: { + HOST: 'www.google-analytics.com', + 'Content-Type': 'application/json', + }, + version: '1', + endpoint: 'https://www.google-analytics.com/mp/collect', + }, + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + mockFns: defaultMockFns, + }, ]; From adc8976990fa98c5b874472aee180cadfabb0088 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:48:00 +0530 Subject: [PATCH 090/147] feat: update on twitter_ads (#3856) --- .../data/TwitterAdsTrackConfig.json | 8 + src/v0/destinations/twitter_ads/transform.js | 24 +- .../twitter_ads/processor/data.ts | 233 +++++++++++++++++- .../destinations/twitter_ads/router/data.ts | 1 + 4 files changed, 263 insertions(+), 3 deletions(-) diff --git a/src/v0/destinations/twitter_ads/data/TwitterAdsTrackConfig.json b/src/v0/destinations/twitter_ads/data/TwitterAdsTrackConfig.json index 9394e25c0a2..1eaf40db49f 100644 --- a/src/v0/destinations/twitter_ads/data/TwitterAdsTrackConfig.json +++ b/src/v0/destinations/twitter_ads/data/TwitterAdsTrackConfig.json @@ -44,5 +44,13 @@ "destKey": "contents", "sourceKeys": "properties.contents", "required": false + }, + { + "destKey": "ip_address", + "sourceKeys": ["context.ip", "request_ip"] + }, + { + "destKey": "user_agent", + "sourceKeys": "context.userAgent" } ] diff --git a/src/v0/destinations/twitter_ads/transform.js b/src/v0/destinations/twitter_ads/transform.js index 268dca36366..71536be2d91 100644 --- a/src/v0/destinations/twitter_ads/transform.js +++ b/src/v0/destinations/twitter_ads/transform.js @@ -131,6 +131,20 @@ function processTrack(message, metadata, destination) { identifiers.push({ twclid: message.properties.twclid }); } + if (message.properties.ip_address) { + const ipAddress = message.properties.ip_address.trim(); + if (ipAddress) { + identifiers.push({ ip_address: ipAddress }); + } + } + + if (message.properties.user_agent) { + const userAgent = message.properties.user_agent.trim(); + if (userAgent) { + identifiers.push({ user_agent: userAgent }); + } + } + requestJson = populateContents(requestJson); requestJson.identifiers = identifiers; @@ -149,9 +163,15 @@ function validateRequest(message) { ); } - if (!properties.email && !properties.phone && !properties.twclid) { + if ( + !properties.email && + !properties.phone && + !properties.twclid && + !properties.ip_address && + !properties.user_agent + ) { throw new InstrumentationError( - '[TWITTER ADS]: one of twclid, phone or email must be present in properties.', + '[TWITTER ADS]: one of twclid, phone, email, ip_address or user_agent must be present in properties.', ); } } diff --git a/test/integrations/destinations/twitter_ads/processor/data.ts b/test/integrations/destinations/twitter_ads/processor/data.ts index b6a75128801..0ae21ffc98e 100644 --- a/test/integrations/destinations/twitter_ads/processor/data.ts +++ b/test/integrations/destinations/twitter_ads/processor/data.ts @@ -131,6 +131,7 @@ export const data = [ conversion_time: '2023-06-01T06:03:08.739Z', number_items: 2, price_currency: 'USD', + user_agent: 'chrome', value: '25', conversion_id: '213123', contents: [ @@ -290,7 +291,8 @@ export const data = [ }, }, statusCode: 400, - error: '[TWITTER ADS]: one of twclid, phone or email must be present in properties.', + error: + '[TWITTER ADS]: one of twclid, phone, email, ip_address or user_agent must be present in properties.', statTags: { errorCategory: 'dataValidation', errorType: 'instrumentation', @@ -424,6 +426,7 @@ export const data = [ conversion_time: '2023-06-01T06:03:08.739Z', number_items: 2, price_currency: 'USD', + user_agent: 'chrome', value: '25.55', conversion_id: '213123', identifiers: [ @@ -842,6 +845,7 @@ export const data = [ conversion_time: '2023-06-01T06:03:08.739Z', number_items: 2, price_currency: 'USD', + user_agent: 'chrome', value: '25', conversion_id: '213123', contents: [ @@ -894,6 +898,233 @@ export const data = [ }, }, }, + { + name: 'twitter_ads', + description: 'Test case for track event with ip_address as an identifier', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'track', + event: 'Home Page Viewed', + channel: 'web', + context: { + source: 'test', + userAgent: 'chrome', + traits: { + anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', + email: 'abc@gmail.com', + phone: '+1234589947', + ge: 'male', + }, + device: { + advertisingId: 'abc123', + }, + library: { + name: 'rudder-sdk-ruby-sync', + version: '1.0.6', + }, + }, + messageId: '7208bbb6-2c4e-45bb-bf5b-ad426f3593e9', + timestamp: '2020-08-14T05:30:30.118Z', + properties: { + affiliation: 'Google Store', + checkout_id: 'fksdjfsdjfisjf9sdfjsd9f', + ip_address: '8.25.197.25', + }, + anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', + integrations: { + All: true, + }, + }, + metadata: { + secret: { + consumerKey: 'qwe', + consumerSecret: 'fdghv', + accessToken: 'dummyAccessToken', + accessTokenSecret: 'testAccessTokenSecret', + }, + }, + destination: { + Config: { + pixelId: 'dummyPixelId', + rudderAccountId: '2EOknn1JNH7WK1MfNku4fGYKkRK', + twitterAdsEventNames: [ + { + rudderEventName: 'ABC Searched', + twitterEventId: 'tw-234234324234', + }, + { + rudderEventName: 'Home Page Viewed', + twitterEventId: 'tw-odt2o-odt2q', + }, + ], + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.twitter.com/12/measurement/conversions/dummyPixelId', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + conversions: [ + { + conversion_time: '2020-08-14T05:30:30.118Z', + user_agent: 'chrome', + event_id: 'tw-odt2o-odt2q', + identifiers: [ + { + ip_address: '8.25.197.25', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: { + secret: { + consumerKey: 'qwe', + consumerSecret: 'fdghv', + accessToken: 'dummyAccessToken', + accessTokenSecret: 'testAccessTokenSecret', + }, + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'twitter_ads', + description: 'Test case for track event with user_agent as an identifier', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'track', + event: 'Home Page Viewed', + channel: 'web', + context: { + source: 'test', + traits: { + anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', + email: 'abc@gmail.com', + phone: '+1234589947', + ge: 'male', + }, + }, + properties: { + affiliation: 'Google Store', + user_agent: + ' Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36.', + }, + anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', + integrations: { + All: true, + }, + }, + metadata: { + secret: { + accessTokenSecret: 'testAccessTokenSecret', + }, + }, + destination: { + Config: { + pixelId: 'dummyPixelId', + rudderAccountId: '2EOknn1JNH7WK1MfNku4fGYKkRK', + twitterAdsEventNames: [ + { + rudderEventName: 'ABC Searched', + twitterEventId: 'tw-234234324234', + }, + { + rudderEventName: 'Home Page Viewed', + twitterEventId: 'tw-odt2o-odt2q', + }, + ], + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.twitter.com/12/measurement/conversions/dummyPixelId', + headers: { + Authorization: authHeaderConstant, + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + conversions: [ + { + event_id: 'tw-odt2o-odt2q', + identifiers: [ + { + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36.', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + metadata: { + secret: { + accessTokenSecret: 'testAccessTokenSecret', + }, + }, + statusCode: 200, + }, + ], + }, + }, + }, ].map((tc) => ({ ...tc, mockFns: (_) => { diff --git a/test/integrations/destinations/twitter_ads/router/data.ts b/test/integrations/destinations/twitter_ads/router/data.ts index ce9aea65958..7e8061dd7e5 100644 --- a/test/integrations/destinations/twitter_ads/router/data.ts +++ b/test/integrations/destinations/twitter_ads/router/data.ts @@ -146,6 +146,7 @@ export const data = [ ], number_items: 2, price_currency: 'USD', + user_agent: 'chrome', value: '25', }, ], From f83148797735ffcbaf9dec5ef5096bd7cacbcd91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:57:46 +0530 Subject: [PATCH 091/147] chore(deps-dev): bump husky from 9.1.1 to 9.1.6 (#3807) Bumps [husky](https://github.com/typicode/husky) from 9.1.1 to 9.1.6. - [Release notes](https://github.com/typicode/husky/releases) - [Commits](https://github.com/typicode/husky/compare/v9.1.1...v9.1.6) --- updated-dependencies: - dependency-name: husky dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Co-authored-by: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2454751ce36..1c9e84bf11b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -107,7 +107,7 @@ "eslint-plugin-unicorn": "^46.0.1", "glob": "^10.3.3", "http-terminator": "^3.2.0", - "husky": "^9.1.1", + "husky": "^9.1.6", "jest": "^29.5.0", "jest-sonar": "^0.2.16", "jest-when": "^3.5.2", @@ -13684,9 +13684,10 @@ } }, "node_modules/husky": { - "version": "9.1.1", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", + "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", "dev": true, - "license": "MIT", "bin": { "husky": "bin.js" }, diff --git a/package.json b/package.json index c2dc3df7bee..45003843836 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "eslint-plugin-unicorn": "^46.0.1", "glob": "^10.3.3", "http-terminator": "^3.2.0", - "husky": "^9.1.1", + "husky": "^9.1.6", "jest": "^29.5.0", "jest-sonar": "^0.2.16", "jest-when": "^3.5.2", From 5426d6c753932f52bdd368b7a78db2c32aaf23ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:26:15 +0530 Subject: [PATCH 092/147] chore(deps): bump libphonenumber-js from 1.11.1 to 1.11.12 (#3813) Bumps [libphonenumber-js](https://gitlab.com/catamphetamine/libphonenumber-js) from 1.11.1 to 1.11.12. - [Changelog](https://gitlab.com/catamphetamine/libphonenumber-js/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/catamphetamine/libphonenumber-js/compare/v1.11.1...v1.11.12) --- updated-dependencies: - dependency-name: libphonenumber-js dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Co-authored-by: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c9e84bf11b..4d1f1902118 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "koa": "^2.15.3", "koa-bodyparser": "^4.4.0", "koa2-swagger-ui": "^5.7.0", - "libphonenumber-js": "^1.11.1", + "libphonenumber-js": "^1.11.12", "lodash": "^4.17.21", "match-json": "^1.3.5", "md5": "^2.3.0", @@ -16547,8 +16547,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.11.1", - "license": "MIT" + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.12.tgz", + "integrity": "sha512-QkJn9/D7zZ1ucvT++TQSvZuSA2xAWeUytU+DiEQwbPKLyrDpvbul2AFs1CGbRAPpSCCk47aRAb5DX5mmcayp4g==" }, "node_modules/lilconfig": { "version": "2.1.0", diff --git a/package.json b/package.json index 45003843836..255dbb98b66 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "koa": "^2.15.3", "koa-bodyparser": "^4.4.0", "koa2-swagger-ui": "^5.7.0", - "libphonenumber-js": "^1.11.1", + "libphonenumber-js": "^1.11.12", "lodash": "^4.17.21", "match-json": "^1.3.5", "md5": "^2.3.0", From 716744f8c5f72164b40b8f53bd9105939546623d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 11:16:59 +0530 Subject: [PATCH 093/147] chore(deps): bump SonarSource/sonarcloud-github-action from 3.0.0 to 3.1.0 (#3819) chore(deps): bump SonarSource/sonarcloud-github-action Bumps [SonarSource/sonarcloud-github-action](https://github.com/sonarsource/sonarcloud-github-action) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/sonarsource/sonarcloud-github-action/releases) - [Commits](https://github.com/sonarsource/sonarcloud-github-action/compare/v3.0.0...v3.1.0) --- updated-dependencies: - dependency-name: SonarSource/sonarcloud-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> --- .github/workflows/dt-test-and-report-code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 33b9d881d97..2c768988823 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -80,7 +80,7 @@ jobs: - name: SonarCloud Scan if: always() - uses: SonarSource/sonarcloud-github-action@v3.0.0 + uses: SonarSource/sonarcloud-github-action@v3.1.0 env: GITHUB_TOKEN: ${{ secrets.PAT }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From bfd7edc5608c60a39644a1d4ad6e15e5dbcbea0e Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:16:24 +0530 Subject: [PATCH 094/147] fix: linkedin ads conversionValue object as well as price is not mandatory (#3860) --- src/cdk/v2/destinations/linkedin_ads/utils.js | 6 +- .../destinations/linkedin_ads/utils.test.js | 9 +- .../processor/validationTestData.ts | 117 ++++++++++++++++-- 3 files changed, 112 insertions(+), 20 deletions(-) diff --git a/src/cdk/v2/destinations/linkedin_ads/utils.js b/src/cdk/v2/destinations/linkedin_ads/utils.js index 69fea4299d0..93a46fe68b9 100644 --- a/src/cdk/v2/destinations/linkedin_ads/utils.js +++ b/src/cdk/v2/destinations/linkedin_ads/utils.js @@ -89,7 +89,7 @@ function checkIfPricePresent(properties) { } const calculateConversionObject = (message) => { - const { properties, event } = message; + const { properties } = message; const calculateAmount = () => { if (properties?.products && properties.products.length > 0) { @@ -107,9 +107,7 @@ const calculateConversionObject = (message) => { }; return conversionObject; } - throw new InstrumentationError( - `[LinkedIn Conversion API]: Cannot map price for event ${event}. Aborting`, - ); + return null; }; const deduceConversionRules = (trackEventName, destConfig) => { diff --git a/src/cdk/v2/destinations/linkedin_ads/utils.test.js b/src/cdk/v2/destinations/linkedin_ads/utils.test.js index ee52928198a..d66bda47dc1 100644 --- a/src/cdk/v2/destinations/linkedin_ads/utils.test.js +++ b/src/cdk/v2/destinations/linkedin_ads/utils.test.js @@ -29,12 +29,13 @@ describe('formatEmail', () => { }); describe('calculateConversionObject', () => { - // Returns a conversion object with currency code 'USD' and amount 0 when message properties are empty - it('should throw instrumentation error when message properties are empty', () => { + // Returns empty object when message properties are empty + it('should return empty object when message properties are empty', () => { const message = { properties: {} }; expect(() => { - fetchUserIds(calculateConversionObject(message)); - }).toThrow(InstrumentationError); + const conversionObject = calculateConversionObject(message); + expect(conversionObject).toEqual({}); + }); }); // Returns a conversion object with currency code 'USD' and amount 0 when message properties price is defined but quantity is 0 diff --git a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts index 4579cf68ee2..5cb6ff8cf27 100644 --- a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts @@ -1,4 +1,9 @@ -import { generateMetadata, generateTrackPayload, overrideDestination } from '../../../testUtils'; +import { + generateMetadata, + generateTrackPayload, + overrideDestination, + transformResultBuilder, +} from '../../../testUtils'; import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; @@ -75,6 +80,14 @@ const commonStats = { workspaceId: 'default-workspaceId', }; +const commonHeader = { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202402', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', +}; + const commonTimestamp = new Date('2023-10-14'); const olderTimestamp = new Date('2023-07-13'); @@ -234,7 +247,7 @@ export const validationTestData: ProcessorTestData[] = [ description: 'Track call : properties without product array and no price', scenario: 'Business', successCriteria: - 'should throw error with status code 400 and error message regarding price is a mandatory field for linkedin conversions', + 'should not have conversionValue object as price is a mandatory field for linkedin conversions', feature: 'processor', module: 'destination', version: 'v0', @@ -243,7 +256,7 @@ export const validationTestData: ProcessorTestData[] = [ body: [ { message: generateTrackPayload({ - event: 'random event', + event: 'ABC Searched', properties: commonUserProperties, context: { traits: commonUserTraits, @@ -264,11 +277,51 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { - error: - '[LinkedIn Conversion API]: Cannot map price for event random event. Aborting: Workflow: procWorkflow, Step: commonFields, ChildStep: undefined, OriginalError: [LinkedIn Conversion API]: Cannot map price for event random event. Aborting', + output: transformResultBuilder({ + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://api.linkedin.com/rest/conversionEvents`, + headers: commonHeader, + params: {}, + FORM: {}, + files: {}, + JSON: { + elements: [ + { + conversion: 'urn:lla:llaPartnerConversion:1234567', + conversionHappenedAt: 1697241600000, + eventId: '12345', + user: { + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08', + }, + ], + }, + }, + { + conversion: 'urn:lla:llaPartnerConversion:34567', + conversionHappenedAt: 1697241600000, + eventId: '12345', + user: { + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08', + }, + ], + }, + }, + ], + }, + userId: '', + }), + statusCode: 200, metadata: generateMetadata(1), - statTags: commonStats, - statusCode: 400, }, ], }, @@ -289,7 +342,7 @@ export const validationTestData: ProcessorTestData[] = [ body: [ { message: generateTrackPayload({ - event: 'random event', + event: 'ABC Searched', properties: commonUserPropertiesWithProductWithoutPrice, context: { traits: commonUserTraits, @@ -310,11 +363,51 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { - error: - '[LinkedIn Conversion API]: Cannot map price for event random event. Aborting: Workflow: procWorkflow, Step: commonFields, ChildStep: undefined, OriginalError: [LinkedIn Conversion API]: Cannot map price for event random event. Aborting', + output: transformResultBuilder({ + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://api.linkedin.com/rest/conversionEvents`, + headers: commonHeader, + params: {}, + FORM: {}, + files: {}, + JSON: { + elements: [ + { + conversion: 'urn:lla:llaPartnerConversion:1234567', + conversionHappenedAt: 1697241600000, + eventId: '12345', + user: { + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08', + }, + ], + }, + }, + { + conversion: 'urn:lla:llaPartnerConversion:34567', + conversionHappenedAt: 1697241600000, + eventId: '12345', + user: { + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '48ddb93f0b30c475423fe177832912c5bcdce3cc72872f8051627967ef278e08', + }, + ], + }, + }, + ], + }, + userId: '', + }), + statusCode: 200, metadata: generateMetadata(1), - statTags: commonStats, - statusCode: 400, }, ], }, From f959a7dc2487dc7e36377f5f2e265014f692f476 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Mon, 11 Nov 2024 13:12:49 +0530 Subject: [PATCH 095/147] fix: marketo bulk upload handle special chars (#3859) --- .../marketo_bulk_upload/transform.js | 11 ++- .../marketo_bulk_upload/processor/data.ts | 86 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/v0/destinations/marketo_bulk_upload/transform.js b/src/v0/destinations/marketo_bulk_upload/transform.js index 1943d817cde..ada1d8c66ae 100644 --- a/src/v0/destinations/marketo_bulk_upload/transform.js +++ b/src/v0/destinations/marketo_bulk_upload/transform.js @@ -35,7 +35,16 @@ function responseBuilderSimple(message, destination) { Object.keys(fieldHashmap).forEach((key) => { const val = traits[fieldHashmap[key]]; if (isDefined(val)) { - payload[key] = val; + let newVal = val; + // If value contains comma or newline then we need to escape it + if (typeof val === 'string') { + newVal = val + .toString() + .replaceAll(/\\/g, '\\\\') + .replaceAll(/,/g, '\\,') + .replaceAll(/\n/g, '\\n'); + } + payload[key] = newVal; } }); const response = defaultRequestConfig(); diff --git a/test/integrations/destinations/marketo_bulk_upload/processor/data.ts b/test/integrations/destinations/marketo_bulk_upload/processor/data.ts index 90a3ca8584a..3a2b700534d 100644 --- a/test/integrations/destinations/marketo_bulk_upload/processor/data.ts +++ b/test/integrations/destinations/marketo_bulk_upload/processor/data.ts @@ -595,4 +595,90 @@ export const data = [ }, }, }, + { + name: 'marketo_bulk_upload', + description: 'Test 6: Any comma or new line should be escaped through transform payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'identify', + userId: 'nicholas003', + anonymousId: 'anonId_003', + context: { + traits: { + firstName: 'Test', + lastName: 'hello\\world,new\nline', + email: 'badRecord.email.com', + city: '776 Elm St.\nRt. ,101', + }, + }, + request_ip: '192.168.10.106', + }, + destination: { + ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + Config: { + munchkinId: 'XXXX', + clientId: 'YYYY', + clientSecret: 'ZZZZ', + columnFieldsMapping: [ + { + to: 'firstName', + from: 'firstName', + }, + { + to: 'lastName', + from: 'lastName', + }, + { + to: 'email', + from: 'email', + }, + { + to: 'city', + from: 'city', + }, + ], + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: '/fileUpload', + headers: {}, + params: {}, + body: { + JSON: { + firstName: 'Test', + lastName: 'hello\\\\world\\,new\\nline', + email: 'badRecord.email.com', + city: '776 Elm St.\\nRt. \\,101', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, ]; From fa93f0917d4f75fc197a6ea4c574d37faa0a3f77 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:38:48 +0530 Subject: [PATCH 096/147] fix: adding throttled status code for server unavailable error in salesforce (#3862) * fix: adding throttled status code for server unavailable in salesforce * fix: adding doc ref * fix: adding doc ref * fix: adding error message dynamically --- src/v0/destinations/salesforce/utils.js | 45 +++++++++++++++---- .../salesforce/dataDelivery/business.ts | 10 ++--- .../salesforce/dataDelivery/data.ts | 14 +++--- .../salesforce/dataDelivery/other.ts | 4 +- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/v0/destinations/salesforce/utils.js b/src/v0/destinations/salesforce/utils.js index a7731f07de4..bbd5216c5bd 100644 --- a/src/v0/destinations/salesforce/utils.js +++ b/src/v0/destinations/salesforce/utils.js @@ -23,6 +23,29 @@ const { const ACCESS_TOKEN_CACHE = new Cache(ACCESS_TOKEN_CACHE_TTL); +/** + * Extracts and returns the error message from a response object. + * If the response is an array and contains a message in the first element, + * it returns that message. Otherwise, it returns the stringified response. + * Error Message Format Example: ref: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/errorcodes.htm#:~:text=Incorrect%20ID%20example + [ + { + "fields" : [ "Id" ], + "message" : "Account ID: id value of incorrect type: 001900K0001pPuOAAU", + "errorCode" : "MALFORMED_ID" + } + ] + * @param {Object|Array} response - The response object or array to extract the message from. + * @returns {string} The extracted error message or the stringified response. + */ + +const getErrorMessage = (response) => { + if (Array.isArray(response) && response?.[0]?.message && response?.[0]?.message?.length > 0) { + return response[0].message; + } + return JSON.stringify(response); +}; + /** * ref: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/errorcodes.htm * handles Salesforce application level failures @@ -77,15 +100,19 @@ const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authori } else if (status === 503 || status === 500) { // The salesforce server is unavailable to handle the request. Typically this occurs if the server is down // for maintenance or is currently overloaded. - throw new RetryableError( - `${DESTINATION} Request Failed - due to "${ - response && Array.isArray(response) && response[0]?.message?.length > 0 - ? response[0].message - : JSON.stringify(response) - }", (Retryable) ${sourceMessage}`, - 500, - destResponse, - ); + // ref : https://help.salesforce.com/s/articleView?id=000387190&type=1 + if (matchErrorCode('SERVER_UNAVAILABLE')) { + throw new ThrottledError( + `${DESTINATION} Request Failed: ${status} - due to ${getErrorMessage(response)}, ${sourceMessage}`, + destResponse, + ); + } else { + throw new RetryableError( + `${DESTINATION} Request Failed: ${status} - due to "${getErrorMessage(response)}", (Retryable) ${sourceMessage}`, + 500, + destResponse, + ); + } } // check the error message let errorMessage = ''; diff --git a/test/integrations/destinations/salesforce/dataDelivery/business.ts b/test/integrations/destinations/salesforce/dataDelivery/business.ts index 4e98a3fc1a3..5374e3fae22 100644 --- a/test/integrations/destinations/salesforce/dataDelivery/business.ts +++ b/test/integrations/destinations/salesforce/dataDelivery/business.ts @@ -150,7 +150,7 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ output: { status: 500, message: - 'Salesforce Request Failed - due to "Session expired or invalid", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 500 - due to "Session expired or invalid", (Retryable) during Salesforce Response Handling', response: [ { error: @@ -277,16 +277,16 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ body: { output: { message: - 'Salesforce Request Failed - due to "Server Unavailable", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 503 - due to Server Unavailable, during Salesforce Response Handling', response: [ { error: '[{"message":"Server Unavailable","errorCode":"SERVER_UNAVAILABLE"}]', metadata: proxyMetdata, - statusCode: 500, + statusCode: 429, }, ], - statTags: statTags.retryable, - status: 500, + statTags: statTags.throttled, + status: 429, }, }, }, diff --git a/test/integrations/destinations/salesforce/dataDelivery/data.ts b/test/integrations/destinations/salesforce/dataDelivery/data.ts index d376289d97d..f157161751b 100644 --- a/test/integrations/destinations/salesforce/dataDelivery/data.ts +++ b/test/integrations/destinations/salesforce/dataDelivery/data.ts @@ -314,12 +314,12 @@ const legacyTests = [ }, output: { response: { - status: 500, + status: 429, body: { output: { - status: 500, + status: 429, message: - 'Salesforce Request Failed - due to "Server Unavailable", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 503 - due to Server Unavailable, during Salesforce Response Handling', destinationResponse: { response: [ { @@ -334,7 +334,7 @@ const legacyTests = [ errorCategory: 'network', destinationId: 'Non-determininable', workspaceId: 'Non-determininable', - errorType: 'retryable', + errorType: 'throttled', feature: 'dataDelivery', implementation: 'native', module: 'destination', @@ -461,7 +461,7 @@ const legacyTests = [ status: 503, }, message: - 'Salesforce Request Failed - due to "{"message":"Server Unavailable","errorCode":"SERVER_UNAVAILABLE"}", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 503 - due to "{"message":"Server Unavailable","errorCode":"SERVER_UNAVAILABLE"}", (Retryable) during Salesforce Response Handling', statTags: { destType: 'SALESFORCE', errorCategory: 'network', @@ -603,7 +603,7 @@ const legacyTests = [ output: { status: 500, message: - 'Salesforce Request Failed - due to ""[ECONNABORTED] :: Connection aborted"", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 500 - due to ""[ECONNABORTED] :: Connection aborted"", (Retryable) during Salesforce Response Handling', destinationResponse: { response: '[ECONNABORTED] :: Connection aborted', status: 500, @@ -696,7 +696,7 @@ const legacyTests = [ output: { status: 500, message: - 'Salesforce Request Failed - due to ""[EAI_AGAIN] :: Temporary failure in name resolution"", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 500 - due to ""[EAI_AGAIN] :: Temporary failure in name resolution"", (Retryable) during Salesforce Response Handling', destinationResponse: { response: '[EAI_AGAIN] :: Temporary failure in name resolution', status: 500, diff --git a/test/integrations/destinations/salesforce/dataDelivery/other.ts b/test/integrations/destinations/salesforce/dataDelivery/other.ts index b3361caba7f..8bf154de9b5 100644 --- a/test/integrations/destinations/salesforce/dataDelivery/other.ts +++ b/test/integrations/destinations/salesforce/dataDelivery/other.ts @@ -58,7 +58,7 @@ export const otherSalesforceScenariosV1: ProxyV1TestData[] = [ ], statTags, message: - 'Salesforce Request Failed - due to "{"error":{"message":"Service Unavailable","description":"The server is currently unable to handle the request due to temporary overloading or maintenance of the server. Please try again later."}}", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 503 - due to "{"error":{"message":"Service Unavailable","description":"The server is currently unable to handle the request due to temporary overloading or maintenance of the server. Please try again later."}}", (Retryable) during Salesforce Response Handling', status: 500, }, }, @@ -96,7 +96,7 @@ export const otherSalesforceScenariosV1: ProxyV1TestData[] = [ ], statTags, message: - 'Salesforce Request Failed - due to ""Internal Server Error"", (Retryable) during Salesforce Response Handling', + 'Salesforce Request Failed: 500 - due to ""Internal Server Error"", (Retryable) during Salesforce Response Handling', status: 500, }, }, From 10d4cc068e216341d8c09bca4ed3e2dab5cbda26 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:34:39 +0530 Subject: [PATCH 097/147] chore: resolve conflicts and merge main to develop (#3865) chore: resolve conflicts --- CHANGELOG.md | 9 + package-lock.json | 4 +- package.json | 2 +- .../pinterest_tag/procWorkflow.yaml | 6 +- .../transform.js | 26 +- src/v0/util/index.test.js | 1 + .../data_scenarios/cdk_v2/failure.json | 8 - .../data_scenarios/cdk_v2/success.json | 12 - .../proc/batch_input_multiplex.json | 12 - .../proc/multiplex_partial_failure.json | 8 - .../destination/proc/multiplex_success.json | 8 - .../destination/router/failure_test.json | 8 - .../processor/data.ts | 2 +- .../router/data.ts | 420 ++++++++++++------ .../pinterest_tag/processor/data.ts | 13 +- .../destinations/pinterest_tag/router/data.ts | 4 +- .../destinations/pinterest_tag/step/data.ts | 11 +- 17 files changed, 318 insertions(+), 236 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcfd6f2835b..8c7591edec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.83.2](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.1...v1.83.2) (2024-11-05) + + +### Bug Fixes + +* update gaec destination with config validation ([#3847](https://github.com/rudderlabs/rudder-transformer/issues/3847)) ([e5c5b0a](https://github.com/rudderlabs/rudder-transformer/commit/e5c5b0a28070ff5ca89a274c3998b96780139149)) + +### [1.83.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.0...v1.83.1) (2024-11-01) + ## [1.83.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.82.2...v1.83.0) (2024-10-25) diff --git a/package-lock.json b/package-lock.json index 4d1f1902118..0965688626a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.2", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 255dbb98b66..65b7313e881 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.83.0", + "version": "1.83.2", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { diff --git a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml index 5d97da5a9ed..64d391c8882 100644 --- a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml @@ -167,11 +167,7 @@ steps: "content_ids": (props.product_id ?? props.sku ?? props.id)[], "contents": { "quantity": Number(props.quantity) || 1, - "item_price": String(props.price), - "item_name": String(props.name), - "id": props.product_id ?? props.sku, - "item_category": props.category, - "item_brand": props.brand + "item_price": String(props.price) }[] }; - name: combineAllEcomFields diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 13a294ea959..497d4f294f4 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -56,13 +56,11 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { if (isNumber(customerId)) { customerId = customerId.toString(); } - if (isNumber(loginCustomerId)) { - loginCustomerId = loginCustomerId.toString(); - } - if (!isString(customerId) || !isString(loginCustomerId)) { - throw new InstrumentationError('customerId and loginCustomerId should be a string or number'); + if (!isString(customerId)) { + throw new InstrumentationError('customerId should be a string or number'); } const filteredCustomerId = removeHyphens(customerId); + response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}:uploadConversionAdjustments`; response.body.JSON = payload; const accessToken = getAccessToken(metadata, 'access_token'); @@ -72,11 +70,19 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { 'developer-token': getValueFromMessage(metadata, 'secret.developer_token'), }; response.params = { event, customerId: filteredCustomerId }; - if (subAccount) - if (loginCustomerId) { - const filteredLoginCustomerId = removeHyphens(loginCustomerId); - response.headers['login-customer-id'] = filteredLoginCustomerId; - } else throw new ConfigurationError(`LoginCustomerId is required as subAccount is true.`); + if (subAccount) { + if (!loginCustomerId) { + throw new ConfigurationError(`loginCustomerId is required as subAccount is true.`); + } + if (isNumber(loginCustomerId)) { + loginCustomerId = loginCustomerId.toString(); + } + if (loginCustomerId && !isString(loginCustomerId)) { + throw new InstrumentationError('loginCustomerId should be a string or number'); + } + const filteredLoginCustomerId = removeHyphens(loginCustomerId); + response.headers['login-customer-id'] = filteredLoginCustomerId; + } if (loginCustomerId) { const filteredLoginCustomerId = removeHyphens(loginCustomerId); diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index eaf8b79d54e..0b05b6f2d69 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -977,6 +977,7 @@ describe('removeHyphens', () => { { input: null, expected: null }, { input: undefined, expected: undefined }, { input: 12345, expected: 12345 }, + { input: '123-12-241', expected: '12312241' }, ]; it('should remove hyphens from string else return the input as it is', () => { data.forEach(({ input, expected }) => { diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 154d24481dc..1635a3f0dbf 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -556,10 +556,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -683,10 +679,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index 88f430dd7c2..ced7433a282 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -556,10 +556,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -638,10 +634,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -720,10 +712,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3deb7d4b8ba..3ce7c150918 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -388,10 +388,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -470,10 +466,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -552,10 +544,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index a2652855d56..0e467c26d0b 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -388,10 +388,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -470,10 +466,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index ba4d5266f30..66b6c870a9e 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -207,10 +207,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -289,10 +285,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 197456f66af..9e36da50cb8 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -754,10 +754,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -785,10 +781,6 @@ "content_ids": ["123"], "contents": [ { - "id": "123", - "item_brand": "Gamepro", - "item_category": "Games", - "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts index 87fad8b9a54..fcdb6f15cae 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts @@ -814,7 +814,7 @@ export const data = [ }, }, statusCode: 400, - error: 'LoginCustomerId is required as subAccount is true.', + error: 'loginCustomerId is required as subAccount is true.', statTags: { errorCategory: 'dataValidation', errorType: 'configuration', diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 33cb4a832fc..b319a8cb3ba 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -427,6 +427,8 @@ const events = [ Config: { rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', + customerId: '1234567890', + subAccount: true, listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], authStatus: 'active', }, @@ -452,11 +454,17 @@ const events = [ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + customerID: {}, + subaccountID: 11, }, event: 'Page View', type: 'track', messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', userId: '12345', properties: { gclid: 'gclid1234', @@ -496,6 +504,43 @@ const events = [ }, integrations: { All: true }, name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 7, + userId: 'u1', + }, + destination: { + Config: { + customerId: '1234567890', + subAccount: true, + loginCustomerId: { id: '1234567890' }, + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + event: 'Page View', + type: 'track', + userId: '12345', + context: { + traits: { + email: 'user@testmail.com', + }, + }, + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + order_id: 10000, + total: 1000, + }, }, }, ]; @@ -628,30 +673,24 @@ export const data = [ body: { output: [ { + batched: false, batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - 'login-customer-id': '11', - }, - params: { event: 'Page View', customerId: '1234567890' }, body: { + FORM: {}, JSON: { - partialFailure: true, conversionAdjustments: [ { + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + adjustmentType: 'ENHANCEMENT', gclidDateTimePair: { - gclid: 'gclid1234', conversionDateTime: '2022-01-01 12:32:45-08:00', + gclid: 'gclid1234', }, - restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, orderId: '10000', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', + restatementValue: { + adjustedValue: 10, + currencyCode: 'INR', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', userIdentifiers: [ @@ -661,82 +700,102 @@ export const data = [ }, { addressInfo: { + city: 'London', hashedFirstName: 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', hashedLastName: '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - state: 'UK', - city: 'London', hashedStreetAddress: '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + state: 'UK', }, }, ], - adjustmentType: 'ENHANCEMENT', }, ], + partialFailure: true, }, JSON_ARRAY: {}, XML: {}, - FORM: {}, }, + endpoint: + 'https://googleads.googleapis.com/v17/customers/1234567890:uploadConversionAdjustments', files: {}, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '11', + }, + method: 'POST', + params: { + customerId: '1234567890', + event: 'Page View', + }, + type: 'REST', + version: '1', + }, + destination: { + Config: { + authStatus: 'active', + customerId: '1234567890', + listOfConversions: [ + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, + ], + loginCustomerId: '11', + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, + }, }, metadata: [ { + jobId: 1, secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, - jobId: 1, userId: 'u1', }, ], - batched: false, statusCode: 200, + }, + { + batched: false, destination: { Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + authStatus: 'active', customerId: '1234567890', - subAccount: true, - loginCustomerId: '11', listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, ], - authStatus: 'active', + loginCustomerId: '', + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, }, }, - }, - { + error: 'Message Type identify is not supported. Aborting message.', metadata: [ { + jobId: 2, secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, - jobId: 2, userId: 'u1', }, ], - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: '1234567890', - subAccount: true, - loginCustomerId: '', - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, - }, - batched: false, - statusCode: 400, - error: 'Message Type identify is not supported. Aborting message.', statTags: { destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', errorCategory: 'dataValidation', @@ -745,25 +804,35 @@ export const data = [ implementation: 'native', module: 'destination', }, + statusCode: 400, }, { - metadata: [{ secret: {}, jobId: 3, userId: 'u1' }], + batched: false, destination: { Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + authStatus: 'active', customerId: '1234567890', - subAccount: true, - loginCustomerId: '11', listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, ], - authStatus: 'active', + loginCustomerId: '11', + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, }, }, - batched: false, - statusCode: 500, error: 'OAuth - access token not found', + metadata: [ + { + jobId: 3, + secret: {}, + userId: 'u1', + }, + ], statTags: { destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', errorCategory: 'platform', @@ -772,32 +841,27 @@ export const data = [ implementation: 'native', module: 'destination', }, + statusCode: 500, }, { + batched: false, batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - 'login-customer-id': '11', - }, - params: { event: 'Page View', customerId: '1234567890' }, body: { + FORM: {}, JSON: { - partialFailure: true, conversionAdjustments: [ { + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + adjustmentType: 'ENHANCEMENT', gclidDateTimePair: { - gclid: 'gclid1234', conversionDateTime: '2022-01-01 12:32:45-08:00', + gclid: 'gclid1234', }, - restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, orderId: '10000', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', + restatementValue: { + adjustedValue: 10, + currencyCode: 'INR', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', userIdentifiers: [ @@ -807,116 +871,131 @@ export const data = [ }, { addressInfo: { + city: 'London', hashedFirstName: 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', hashedLastName: '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - state: 'UK', - city: 'London', hashedStreetAddress: '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + state: 'UK', }, }, ], - adjustmentType: 'ENHANCEMENT', }, ], + partialFailure: true, }, JSON_ARRAY: {}, XML: {}, - FORM: {}, }, + endpoint: + 'https://googleads.googleapis.com/v17/customers/1234567890:uploadConversionAdjustments', files: {}, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '11', + }, + method: 'POST', + params: { + customerId: '1234567890', + event: 'Page View', + }, + type: 'REST', + version: '1', + }, + destination: { + Config: { + authStatus: 'active', + customerId: 1234567890, + listOfConversions: [ + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, + ], + loginCustomerId: 11, + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, + }, }, metadata: [ { + jobId: 4, secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, - jobId: 4, userId: 'u1', }, ], - batched: false, statusCode: 200, + }, + { + batched: false, destination: { Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: 1234567890, - subAccount: true, - loginCustomerId: 11, + authStatus: 'active', + customerId: {}, listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, ], - authStatus: 'active', + loginCustomerId: 11, + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, }, }, - }, - { - batched: false, - statusCode: 400, - error: 'customerId and loginCustomerId should be a string or number', - statTags: { - destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'router', - implementation: 'native', - module: 'destination', - }, + error: 'customerId should be a string or number', metadata: [ { + jobId: 5, secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, - jobId: 5, userId: 'u1', }, ], - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: {}, - subAccount: true, - loginCustomerId: 11, - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', }, + statusCode: 400, }, { + batched: false, batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - 'login-customer-id': '65656565', - }, - params: { event: 'Page View', customerId: '1234567890' }, body: { + FORM: {}, JSON: { - partialFailure: true, conversionAdjustments: [ { + adjustmentDateTime: '2022-01-01 12:32:45-08:00', + adjustmentType: 'ENHANCEMENT', gclidDateTimePair: { - gclid: 'gclid1234', conversionDateTime: '2022-01-01 12:32:45-08:00', + gclid: 'gclid1234', }, - restatementValue: { adjustedValue: 10, currencyCode: 'INR' }, orderId: '10000', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', + restatementValue: { + adjustedValue: 10, + currencyCode: 'INR', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', userIdentifiers: [ @@ -926,51 +1005,112 @@ export const data = [ }, { addressInfo: { + city: 'London', hashedFirstName: 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', hashedLastName: '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - state: 'UK', - city: 'London', hashedStreetAddress: '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', + state: 'UK', }, }, ], - adjustmentType: 'ENHANCEMENT', }, ], + partialFailure: true, }, JSON_ARRAY: {}, XML: {}, - FORM: {}, }, + endpoint: + 'https://googleads.googleapis.com/v17/customers/1234567890:uploadConversionAdjustments', files: {}, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '65656565', + }, + method: 'POST', + params: { + customerId: '1234567890', + event: 'Page View', + }, + type: 'REST', + version: '1', + }, + destination: { + Config: { + authStatus: 'active', + configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', + customerId: '1234567890', + listOfConversions: [ + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, + ], + rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + subAccount: true, + }, }, metadata: [ { + jobId: 6, secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, - jobId: 6, userId: 'u1', }, ], - batched: false, statusCode: 200, + }, + { + batched: false, destination: { Config: { - configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', + authStatus: 'active', + customerId: '1234567890', listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, + { + conversions: 'Page View', + }, + { + conversions: 'Product Added', + }, ], - authStatus: 'active', + loginCustomerId: { + id: '1234567890', + }, + subAccount: true, + }, + }, + error: 'loginCustomerId should be a string or number', + metadata: [ + { + jobId: 7, + secret: { + access_token: 'abcd1234', + developer_token: 'ijkl91011', + refresh_token: 'efgh5678', + }, + userId: 'u1', }, + ], + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', }, + statusCode: 400, }, ], }, diff --git a/test/integrations/destinations/pinterest_tag/processor/data.ts b/test/integrations/destinations/pinterest_tag/processor/data.ts index 1788d13d563..b856d247d71 100644 --- a/test/integrations/destinations/pinterest_tag/processor/data.ts +++ b/test/integrations/destinations/pinterest_tag/processor/data.ts @@ -482,9 +482,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2407,9 +2405,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [ - { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, - ], + contents: [{ quantity: 1, item_price: 'undefined' }], }, }, JSON_ARRAY: {}, @@ -2670,7 +2666,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1, item_name: 'undefined' }], + contents: [{ item_price: 'undefined', quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3501,7 +3497,6 @@ export const data = [ subtotal: 22.5, affiliation: 'Google Store', checkout_id: 'fksdjfsdjfisjf9sdfjsd9f', - category: 'Apparel', }, anonymousId: '50be5c78-6c3f-4b60-be84-97805a316fb1', integrations: { All: true }, @@ -3568,8 +3563,6 @@ export const data = [ { quantity: 1, item_price: 'undefined', - item_name: 'undefined', - item_category: 'Apparel', }, ], currency: 'USD', diff --git a/test/integrations/destinations/pinterest_tag/router/data.ts b/test/integrations/destinations/pinterest_tag/router/data.ts index 28c82c4679c..c9ab29a45a9 100644 --- a/test/integrations/destinations/pinterest_tag/router/data.ts +++ b/test/integrations/destinations/pinterest_tag/router/data.ts @@ -815,9 +815,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, { diff --git a/test/integrations/destinations/pinterest_tag/step/data.ts b/test/integrations/destinations/pinterest_tag/step/data.ts index 8f0680a77c0..b607e3c9faf 100644 --- a/test/integrations/destinations/pinterest_tag/step/data.ts +++ b/test/integrations/destinations/pinterest_tag/step/data.ts @@ -468,9 +468,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [ - { id: '123', item_name: 'undefined', quantity: 2, item_price: '25' }, - ], + contents: [{ quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2422,9 +2420,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [ - { id: '1234', item_name: 'undefined', quantity: 1, item_price: 'undefined' }, - ], + contents: [{ quantity: 1, item_price: 'undefined' }], }, }, JSON_ARRAY: {}, @@ -2689,7 +2685,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_name: 'undefined', item_price: 'undefined', quantity: 1 }], + contents: [{ item_price: 'undefined', quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3609,7 +3605,6 @@ export const data = [ num_items: 0, contents: [ { - item_name: 'undefined', quantity: 1, item_price: 'undefined', }, From c1626ab3c0abc7295f00d4b692fbba773719e6c3 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:56:14 +0530 Subject: [PATCH 098/147] chore: resolve conflicts again (#3867) --- .../router/data.ts | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index b319a8cb3ba..fe0acf79647 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -543,6 +543,41 @@ const events = [ }, }, }, + { + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 8, + userId: 'u1', + }, + destination: { + Config: { + customerId: '1234567890', + subAccount: true, + listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], + authStatus: 'active', + }, + }, + message: { + event: 'Page View', + type: 'track', + userId: '12345', + context: { + traits: { + email: 'user@testmail.com', + }, + }, + properties: { + gclid: 'gclid1234', + conversionDateTime: '2022-01-01 12:32:45-08:00', + order_id: 10000, + total: 1000, + }, + }, + }, ]; const invalidRtTfCases = [ @@ -967,6 +1002,7 @@ export const data = [ userId: 'u1', }, ], + statusCode: 400, statTags: { destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', errorCategory: 'dataValidation', @@ -975,7 +1011,6 @@ export const data = [ implementation: 'native', module: 'destination', }, - statusCode: 400, }, { batched: false, @@ -1112,6 +1147,41 @@ export const data = [ }, statusCode: 400, }, + { + batched: false, + statusCode: 400, + error: 'loginCustomerId is required as subAccount is true.', + statTags: { + destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'router', + implementation: 'native', + module: 'destination', + }, + metadata: [ + { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + jobId: 8, + userId: 'u1', + }, + ], + destination: { + Config: { + customerId: '1234567890', + subAccount: true, + listOfConversions: [ + { conversions: 'Page View' }, + { conversions: 'Product Added' }, + ], + authStatus: 'active', + }, + }, + }, ], }, }, From b5baa7568b888ea1355a8df3e34981d0ae8a9f36 Mon Sep 17 00:00:00 2001 From: Sai Sankeerth Date: Mon, 11 Nov 2024 16:29:32 +0530 Subject: [PATCH 099/147] chore: remove repeated test cases --- .../router/data.ts | 74 ------------------- 1 file changed, 74 deletions(-) diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index 66514e75d8b..fe0acf79647 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -1182,80 +1182,6 @@ export const data = [ }, }, }, - { - batched: false, - statusCode: 400, - error: 'loginCustomerId is required as subAccount is true.', - statTags: { - destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', - errorCategory: 'dataValidation', - errorType: 'configuration', - feature: 'router', - implementation: 'native', - module: 'destination', - }, - metadata: [ - { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 6, - userId: 'u1', - }, - ], - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - customerId: '1234567890', - subAccount: true, - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, - }, - }, - { - batched: false, - statusCode: 400, - error: 'loginCustomerId should be a string or number', - statTags: { - destType: 'GOOGLE_ADWORDS_ENHANCED_CONVERSIONS', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'router', - implementation: 'native', - module: 'destination', - }, - metadata: [ - { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 7, - userId: 'u1', - }, - ], - destination: { - Config: { - loginCustomerId: { - id: '1234567890', - }, - customerId: '1234567890', - subAccount: true, - listOfConversions: [ - { conversions: 'Page View' }, - { conversions: 'Product Added' }, - ], - authStatus: 'active', - }, - }, - }, ], }, }, From b10a39f1e329f4b2efe2d433e064febcbb13354d Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 11 Nov 2024 11:12:07 +0000 Subject: [PATCH 100/147] chore(release): 1.84.0 --- CHANGELOG.md | 17 +++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c7591edec5..c3c5528ff65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.84.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.2...v1.84.0) (2024-11-11) + + +### Features + +* gaec migration ([#3855](https://github.com/rudderlabs/rudder-transformer/issues/3855)) ([7a26459](https://github.com/rudderlabs/rudder-transformer/commit/7a264590b61d3d31d5559c8ac53fd572b40cddec)) +* **GARL:** support vdm next for GARL ([#3835](https://github.com/rudderlabs/rudder-transformer/issues/3835)) ([f4b38eb](https://github.com/rudderlabs/rudder-transformer/commit/f4b38eba3ca8dff602915853fda5cd7ca284bba3)) +* update on twitter_ads ([#3856](https://github.com/rudderlabs/rudder-transformer/issues/3856)) ([adc8976](https://github.com/rudderlabs/rudder-transformer/commit/adc8976990fa98c5b874472aee180cadfabb0088)) + + +### Bug Fixes + +* adding throttled status code for server unavailable error in salesforce ([#3862](https://github.com/rudderlabs/rudder-transformer/issues/3862)) ([fa93f09](https://github.com/rudderlabs/rudder-transformer/commit/fa93f0917d4f75fc197a6ea4c574d37faa0a3f77)) +* linkedin ads conversionValue object as well as price is not mandatory ([#3860](https://github.com/rudderlabs/rudder-transformer/issues/3860)) ([bfd7edc](https://github.com/rudderlabs/rudder-transformer/commit/bfd7edc5608c60a39644a1d4ad6e15e5dbcbea0e)) +* marketo bulk upload handle special chars ([#3859](https://github.com/rudderlabs/rudder-transformer/issues/3859)) ([f959a7d](https://github.com/rudderlabs/rudder-transformer/commit/f959a7dc2487dc7e36377f5f2e265014f692f476)) +* unsafe property getting set via set value library ([#3853](https://github.com/rudderlabs/rudder-transformer/issues/3853)) ([80d7b41](https://github.com/rudderlabs/rudder-transformer/commit/80d7b417be7a0e459de49caca25aba43ffdba337)) + ### [1.83.2](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.1...v1.83.2) (2024-11-05) diff --git a/package-lock.json b/package-lock.json index 0965688626a..0422078f21e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.83.2", + "version": "1.84.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.83.2", + "version": "1.84.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 65b7313e881..907c340cbfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.83.2", + "version": "1.84.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 7ad4423499959684ecabff6b50a77695c1749f35 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Tue, 12 Nov 2024 12:42:44 +0530 Subject: [PATCH 101/147] chore: remove query_parameter injection --- .../util/conversionStrategies/strategyV2ToV0.ts | 1 - .../util/conversionStrategies/strategyV2ToV1.ts | 3 --- src/controllers/util/index.test.ts | 12 ++++++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV0.ts b/src/controllers/util/conversionStrategies/strategyV2ToV0.ts index 031039e5386..5d90b8cdda5 100644 --- a/src/controllers/util/conversionStrategies/strategyV2ToV0.ts +++ b/src/controllers/util/conversionStrategies/strategyV2ToV0.ts @@ -6,7 +6,6 @@ export class StrategyV2ToV0 extends VersionConversionStrategy { try { const v0Event = JSON.parse(sourceEvent.request.body); - v0Event.query_parameters = sourceEvent.request.query_parameters; return { output: v0Event }; } catch (err) { const conversionError = diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts index 0872d549f0f..d651917096f 100644 --- a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts +++ b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts @@ -6,9 +6,6 @@ export class StrategyV2ToV1 extends VersionConversionStrategy { try { const v1Event = { event: JSON.parse(sourceEvent.request.body), source: sourceEvent.source }; - if (sourceEvent.request) { - v1Event.event.query_parameters = sourceEvent.request.query_parameters; - } return { output: v1Event }; } catch (err) { const conversionError = diff --git a/src/controllers/util/index.test.ts b/src/controllers/util/index.test.ts index 138572a8eac..f1503f7f813 100644 --- a/src/controllers/util/index.test.ts +++ b/src/controllers/util/index.test.ts @@ -190,9 +190,9 @@ describe('adaptInputToVersion', () => { const expected = { implementationVersion: 'v0', input: [ - { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, - { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, - { output: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } } }, + { output: { key: 'value' } }, + { output: { key: 'value' } }, + { output: { key: 'value' } }, ], }; @@ -277,19 +277,19 @@ describe('adaptInputToVersion', () => { input: [ { output: { - event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + event: { key: 'value' }, source: { id: 'source_id', config: { configField1: 'configVal1' } }, }, }, { output: { - event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + event: { key: 'value' }, source: { id: 'source_id', config: { configField1: 'configVal1' } }, }, }, { output: { - event: { key: 'value', query_parameters: { paramkey: ['paramvalue'] } }, + event: { key: 'value' }, source: { id: 'source_id', config: { configField1: 'configVal1' } }, }, }, From 640a11eb3dca5735fed3ad9ad5bd058974b069d6 Mon Sep 17 00:00:00 2001 From: Sandeep Digumarty Date: Tue, 12 Nov 2024 13:12:18 +0530 Subject: [PATCH 102/147] feat: moved userSchema to connection config in GARL vdmv2 (#3870) * feat: moved userSchema to connection config in GARL vdmv2 * feat: moved userSchema to connection config in GARL vdmv2 * chore: added tests --- .../config.js | 2 + .../recordTransform.js | 28 ++- .../transform.js | 4 +- .../google_adwords_remarketing_lists/util.js | 41 +++- .../util.test.js | 2 +- .../router/data.ts | 223 +++++++++++++++++- .../router/record.ts | 119 +++++++++- 7 files changed, 405 insertions(+), 14 deletions(-) diff --git a/src/v0/destinations/google_adwords_remarketing_lists/config.js b/src/v0/destinations/google_adwords_remarketing_lists/config.js index 0478a1b11bf..1e943aee562 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/config.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/config.js @@ -7,6 +7,7 @@ const CONFIG_CATEGORIES = { AUDIENCE_LIST: { type: 'audienceList', name: 'offlineDataJobs' }, ADDRESSINFO: { type: 'addressInfo', name: 'addressInfo' }, }; +const ADDRESS_INFO_ATTRIBUTES = ['firstName', 'lastName', 'country', 'postalCode']; const attributeMapping = { email: 'hashedEmail', phone: 'hashedPhoneNumber', @@ -31,6 +32,7 @@ module.exports = { hashAttributes, offlineDataJobsMapping: MAPPING_CONFIG[CONFIG_CATEGORIES.AUDIENCE_LIST.name], addressInfoMapping: MAPPING_CONFIG[CONFIG_CATEGORIES.ADDRESSINFO.name], + ADDRESS_INFO_ATTRIBUTES, consentConfigMap, destType: 'google_adwords_remarketing_lists', }; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index f8a2b0e5862..1c6284cd09b 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -11,7 +11,11 @@ const { isEventSentByVDMV2Flow, } = require('../../util'); const { populateConsentFromConfig } = require('../../util/googleUtils'); -const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util'); +const { + populateIdentifiersForRecordEvent, + responseBuilder, + getOperationAudienceId, +} = require('./util'); const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); @@ -23,6 +27,7 @@ const processRecordEventArray = ( developerToken, audienceId, typeOfList, + userSchema, isHashRequired, operationType, ) => { @@ -36,10 +41,10 @@ const processRecordEventArray = ( metadata.push(record.metadata); }); - const userIdentifiersList = populateIdentifiers( + const userIdentifiersList = populateIdentifiersForRecordEvent( fieldsArray, - destination, typeOfList, + userSchema, isHashRequired, ); @@ -91,7 +96,7 @@ function preparepayload(events, config) { const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); - const { audienceId, typeOfList, isHashRequired } = config; + const { audienceId, typeOfList, isHashRequired, userSchema } = config; const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), @@ -110,6 +115,7 @@ function preparepayload(events, config) { developerToken, audienceId, typeOfList, + userSchema, isHashRequired, 'remove', ); @@ -124,6 +130,7 @@ function preparepayload(events, config) { developerToken, audienceId, typeOfList, + userSchema, isHashRequired, 'add', ); @@ -138,6 +145,7 @@ function preparepayload(events, config) { developerToken, audienceId, typeOfList, + userSchema, isHashRequired, 'add', ); @@ -161,19 +169,26 @@ function preparepayload(events, config) { function processRecordInputsV0(groupedRecordInputs) { const { destination, message } = groupedRecordInputs[0]; - const { audienceId, typeOfList, isHashRequired } = destination.Config; + const { audienceId, typeOfList, isHashRequired, userSchema } = destination.Config; return preparepayload(groupedRecordInputs, { audienceId: getOperationAudienceId(audienceId, message), typeOfList, + userSchema, isHashRequired, }); } function processRecordInputsV1(groupedRecordInputs) { - const { connection } = groupedRecordInputs[0]; + const { connection, message } = groupedRecordInputs[0]; const { audienceId, typeOfList, isHashRequired } = connection.config.destination; + const identifiers = message?.identifiers; + let userSchema; + if (identifiers) { + userSchema = Object.keys(identifiers); + } + const events = groupedRecordInputs.map((record) => ({ ...record, message: { @@ -185,6 +200,7 @@ function processRecordInputsV1(groupedRecordInputs) { return preparepayload(events, { audienceId, typeOfList, + userSchema, isHashRequired, }); } diff --git a/src/v0/destinations/google_adwords_remarketing_lists/transform.js b/src/v0/destinations/google_adwords_remarketing_lists/transform.js index 299ab948461..4d173589e84 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/transform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/transform.js @@ -37,7 +37,7 @@ function extraKeysPresent(dictionary, keyList) { const createPayload = (message, destination) => { const { listData } = message.properties; const properties = ['add', 'remove']; - const { typeOfList, isHashRequired } = destination.Config; + const { typeOfList, userSchema, isHashRequired } = destination.Config; let outputPayloads = {}; const typeOfOperation = Object.keys(listData); @@ -45,8 +45,8 @@ const createPayload = (message, destination) => { if (properties.includes(key)) { const userIdentifiersList = populateIdentifiers( listData[key], - destination, typeOfList, + userSchema, isHashRequired, ); if (userIdentifiersList.length === 0) { diff --git a/src/v0/destinations/google_adwords_remarketing_lists/util.js b/src/v0/destinations/google_adwords_remarketing_lists/util.js index f4c33a9a6fb..8e0aed03656 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/util.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/util.js @@ -18,6 +18,7 @@ const { TYPEOFLIST, BASE_ENDPOINT, hashAttributes, + ADDRESS_INFO_ATTRIBUTES, } = require('./config'); const hashEncrypt = (object) => { @@ -68,14 +69,13 @@ const responseBuilder = ( * Logics: Here we are creating an array with all the attributes provided in the add/remove array * inside listData. * @param {Array} attributeArray rudder event message properties listData add - * @param {object} Config rudder event destination * @param {string} typeOfList + * @param {Array} userSchema * @param {boolean} isHashRequired * @returns */ -const populateIdentifiers = (attributeArray, { Config }, typeOfList, isHashRequired) => { +const populateIdentifiers = (attributeArray, typeOfList, userSchema, isHashRequired) => { const userIdentifier = []; - const { userSchema } = Config; let attribute; if (TYPEOFLIST[typeOfList]) { attribute = TYPEOFLIST[typeOfList]; @@ -115,6 +115,40 @@ const populateIdentifiers = (attributeArray, { Config }, typeOfList, isHashRequi return userIdentifier; }; +const populateIdentifiersForRecordEvent = ( + identifiersArray, + typeOfList, + userSchema, + isHashRequired, +) => { + const userIdentifiers = []; + + if (isDefinedAndNotNullAndNotEmpty(identifiersArray)) { + // traversing through every element in the add array + identifiersArray.forEach((identifiers) => { + if (isHashRequired) { + hashEncrypt(identifiers); + } + if (TYPEOFLIST[typeOfList] && identifiers[TYPEOFLIST[typeOfList]]) { + userIdentifiers.push({ [TYPEOFLIST[typeOfList]]: identifiers[TYPEOFLIST[typeOfList]] }); + } else { + Object.entries(attributeMapping).forEach(([key, mappedKey]) => { + if (identifiers[key] && userSchema.includes(key)) + userIdentifiers.push({ [mappedKey]: identifiers[key] }); + }); + const addressInfo = constructPayload(identifiers, addressInfoMapping); + if ( + isDefinedAndNotNullAndNotEmpty(addressInfo) && + (userSchema.includes('addressInfo') || + userSchema.some((schema) => ADDRESS_INFO_ATTRIBUTES.includes(schema))) + ) + userIdentifiers.push({ addressInfo }); + } + }); + } + return userIdentifiers; +}; + const getOperationAudienceId = (audienceId, message) => { let operationAudienceId = audienceId; const mappedToDestination = get(message, MappedToDestinationKey); @@ -132,4 +166,5 @@ module.exports = { populateIdentifiers, responseBuilder, getOperationAudienceId, + populateIdentifiersForRecordEvent, }; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/util.test.js b/src/v0/destinations/google_adwords_remarketing_lists/util.test.js index 0b74b07b8e7..a41c00f12f4 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/util.test.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/util.test.js @@ -199,8 +199,8 @@ describe('GARL utils test', () => { const { typeOfList, isHashRequired } = baseDestination.Config; const identifier = populateIdentifiers( attributeArray, - baseDestination, typeOfList, + baseDestination.Config.userSchema, isHashRequired, ); expect(identifier).toEqual(hashedArray); diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts index a5e28996b10..6878e81f0dc 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts @@ -1,5 +1,9 @@ import { rETLAudienceRouterRequest } from './audience'; -import { rETLRecordRouterRequest } from './record'; +import { + rETLRecordRouterRequest, + rETLRecordRouterRequestVDMv2General, + rETLRecordRouterRequestVDMv2UserId, +} from './record'; import { API_VERSION } from '../../../../../src/v0/destinations/google_adwords_remarketing_lists/config'; export const data = [ @@ -732,4 +736,221 @@ export const data = [ }, }, }, + { + name: 'google_adwords_remarketing_lists record event tests VDMv2 General typeOfList', + description: 'Test 2', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: rETLRecordRouterRequestVDMv2General, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/7693729833/offlineUserDataJobs`, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + }, + params: { + listId: '7090784486', + customerId: '7693729833', + consent: { + adPersonalization: 'UNSPECIFIED', + adUserData: 'UNSPECIFIED', + }, + }, + body: { + JSON: { + operations: [ + { + create: { + userIdentifiers: [ + { + hashedEmail: + 'd3142c8f9c9129484daf28df80cc5c955791efed5e69afabb603bc8cb9ffd419', + }, + { + hashedPhoneNumber: + '8846dcb6ab2d73a0e67dbd569fa17cec2d9d391e5b05d1dd42919bc21ae82c45', + }, + { + addressInfo: { + hashedFirstName: + '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + hashedLastName: + 'dcf000c2386fb76d22cefc0d118a8511bb75999019cd373df52044bccd1bd251', + countryCode: 'US', + postalCode: '1245', + }, + }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + secret: { + access_token: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + jobId: 1, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', + audienceId: '7090784486', + customerId: '7693729833', + loginCustomerId: '', + subAccount: false, + }, + DestinationDefinition: { + Config: {}, + DisplayName: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + ID: '1aIXqM806xAVm92nx07YwKbRrO9', + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + }, + Enabled: true, + ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + IsConnectionEnabled: true, + IsProcessorEnabled: true, + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + Transformations: [], + WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', + }, + }, + ], + }, + }, + }, + }, + { + name: 'google_adwords_remarketing_lists record event tests VDMv2 UserId typeOfList', + description: 'Test 3', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: rETLRecordRouterRequestVDMv2UserId, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: [ + { + version: '1', + type: 'REST', + method: 'POST', + endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/7693729833/offlineUserDataJobs`, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + }, + params: { + listId: '7090784486', + customerId: '7693729833', + consent: { + adPersonalization: 'UNSPECIFIED', + adUserData: 'UNSPECIFIED', + }, + }, + body: { + JSON: { + operations: [ + { + create: { + userIdentifiers: [ + { + thirdPartyUserId: 'useri1234', + }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + ], + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + secret: { + access_token: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + jobId: 2, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', + audienceId: '7090784486', + customerId: '7693729833', + loginCustomerId: '', + subAccount: false, + }, + DestinationDefinition: { + Config: {}, + DisplayName: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + ID: '1aIXqM806xAVm92nx07YwKbRrO9', + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + }, + Enabled: true, + ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + IsConnectionEnabled: true, + IsProcessorEnabled: true, + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + Transformations: [], + WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', + }, + }, + ], + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts index de76aae17c8..2661500b4de 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts @@ -1,4 +1,5 @@ -import { Destination, RouterTransformationRequest } from '../../../../../src/types'; +import { Connection, Destination, RouterTransformationRequest } from '../../../../../src/types'; +import { VDM_V2_SCHEMA_VERSION } from '../../../../../src/v0/util/constant'; import { generateGoogleOAuthMetadata } from '../../../testUtils'; const destination: Destination = { @@ -27,6 +28,57 @@ const destination: Destination = { IsProcessorEnabled: true, }; +const destination2: Destination = { + Config: { + rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw', + audienceId: '7090784486', + customerId: '7693729833', + loginCustomerId: '', + subAccount: false, + }, + ID: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + Enabled: true, + WorkspaceID: '1TSN08muJTZwH8iCDmnnRt1pmLd', + DestinationDefinition: { + ID: '1aIXqM806xAVm92nx07YwKbRrO9', + Name: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + DisplayName: 'GOOGLE_ADWORDS_REMARKETING_LISTS', + Config: {}, + }, + Transformations: [], + IsConnectionEnabled: true, + IsProcessorEnabled: true, +}; + +const connection1: Connection = { + sourceId: '2MUWghI7u85n91dd1qzGyswpZan', + destinationId: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + enabled: true, + config: { + destination: { + schemaVersion: VDM_V2_SCHEMA_VERSION, + isHashRequired: true, + typeOfList: 'General', + audienceId: '7090784486', + }, + }, +}; + +const connection2: Connection = { + sourceId: '2MUWghI7u85n91dd1qzGyswpZan', + destinationId: '1mMy5cqbtfuaKZv1IhVQKnBdVwe', + enabled: true, + config: { + destination: { + schemaVersion: VDM_V2_SCHEMA_VERSION, + isHashRequired: true, + typeOfList: 'userID', + audienceId: '7090784486', + }, + }, +}; + export const rETLRecordRouterRequest: RouterTransformationRequest = { input: [ { @@ -153,6 +205,71 @@ export const rETLRecordRouterRequest: RouterTransformationRequest = { destType: 'google_adwords_remarketing_lists', }; +export const rETLRecordRouterRequestVDMv2General: RouterTransformationRequest = { + input: [ + { + destination: destination2, + connection: connection1, + message: { + action: 'insert', + context: { + ip: '14.5.67.21', + library: { + name: 'http', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + email: 'test@abc.com', + phone: '@09876543210', + firstName: 'test', + lastName: 'rudderlabs', + country: 'US', + postalCode: '1245', + }, + type: 'record', + }, + metadata: generateGoogleOAuthMetadata(1), + }, + ], + destType: 'google_adwords_remarketing_lists', +}; + +export const rETLRecordRouterRequestVDMv2UserId: RouterTransformationRequest = { + input: [ + { + destination: destination2, + connection: connection2, + message: { + action: 'insert', + context: { + ip: '14.5.67.21', + library: { + name: 'http', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + email: 'test@abc.com', + phone: '@09876543210', + firstName: 'test', + lastName: 'rudderlabs', + country: 'US', + postalCode: '1245', + thirdPartyUserId: 'useri1234', + }, + type: 'record', + }, + metadata: generateGoogleOAuthMetadata(2), + }, + ], + destType: 'google_adwords_remarketing_lists', +}; + module.exports = { rETLRecordRouterRequest, + rETLRecordRouterRequestVDMv2General, + rETLRecordRouterRequestVDMv2UserId, }; From 70ab9c814c295fc0e7d0b606e5b981510b0bbe3f Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Tue, 12 Nov 2024 14:50:45 +0530 Subject: [PATCH 103/147] chore: fix workflow to consider empty commits --- .github/workflows/verify.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4fca34673a4..4bd66285bd8 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -43,8 +43,12 @@ jobs: - name: Run format Checks run: | - npx prettier --write $(cat changed_files.txt) + if [ -s changed_files.txt ]; then + npx prettier --write $(cat changed_files.txt) + fi + - run: git diff --exit-code + - name: Formatting Error message if: ${{ failure() }} run: | From 1c134f84601aaea78581078137cb9955de576f9e Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:36:09 +0530 Subject: [PATCH 104/147] feat: iterable EUDC (#3828) * feat: iterable EUDC * chore: simplyfied functions * chore: modifications added * chore: fix * chore: modification for endpoint * chore: removed dataCenter to check default --- src/v0/destinations/iterable/config.js | 36 ++-- src/v0/destinations/iterable/transform.js | 21 ++- src/v0/destinations/iterable/util.js | 32 ++-- .../iterable/processor/aliasTestData.ts | 59 ++++++- .../iterable/processor/identifyTestData.ts | 57 +++++++ .../iterable/processor/pageScreenTestData.ts | 65 +++++++- .../iterable/processor/trackTestData.ts | 55 +++++++ .../destinations/iterable/router/data.ts | 155 ++++++++++++++++++ 8 files changed, 439 insertions(+), 41 deletions(-) diff --git a/src/v0/destinations/iterable/config.js b/src/v0/destinations/iterable/config.js index f74fdb4975e..125367875f2 100644 --- a/src/v0/destinations/iterable/config.js +++ b/src/v0/destinations/iterable/config.js @@ -1,42 +1,45 @@ const { getMappingConfig } = require('../../util'); -const BASE_URL = 'https://api.iterable.com/api/'; +const BASE_URL = { + USDC: 'https://api.iterable.com/api/', + EUDC: 'https://api.eu.iterable.com/api/', +}; const ConfigCategory = { IDENTIFY_BROWSER: { name: 'IterableRegisterBrowserTokenConfig', action: 'identifyBrowser', - endpoint: `${BASE_URL}users/registerBrowserToken`, + endpoint: `users/registerBrowserToken`, }, IDENTIFY_DEVICE: { name: 'IterableRegisterDeviceTokenConfig', action: 'identifyDevice', - endpoint: `${BASE_URL}users/registerDeviceToken`, + endpoint: `users/registerDeviceToken`, }, IDENTIFY: { name: 'IterableIdentifyConfig', action: 'identify', - endpoint: `${BASE_URL}users/update`, + endpoint: `users/update`, }, PAGE: { name: 'IterablePageConfig', action: 'page', - endpoint: `${BASE_URL}events/track`, + endpoint: `events/track`, }, SCREEN: { name: 'IterablePageConfig', action: 'screen', - endpoint: `${BASE_URL}events/track`, + endpoint: `events/track`, }, TRACK: { name: 'IterableTrackConfig', action: 'track', - endpoint: `${BASE_URL}events/track`, + endpoint: `events/track`, }, TRACK_PURCHASE: { name: 'IterableTrackPurchaseConfig', action: 'trackPurchase', - endpoint: `${BASE_URL}commerce/trackPurchase`, + endpoint: `commerce/trackPurchase`, }, PRODUCT: { name: 'IterableProductConfig', @@ -46,7 +49,7 @@ const ConfigCategory = { UPDATE_CART: { name: 'IterableProductConfig', action: 'updateCart', - endpoint: `${BASE_URL}commerce/updateCart`, + endpoint: `commerce/updateCart`, }, DEVICE: { name: 'IterableDeviceConfig', @@ -56,30 +59,33 @@ const ConfigCategory = { ALIAS: { name: 'IterableAliasConfig', action: 'alias', - endpoint: `${BASE_URL}users/updateEmail`, + endpoint: `users/updateEmail`, }, CATALOG: { name: 'IterableCatalogConfig', action: 'catalogs', - endpoint: `${BASE_URL}catalogs`, + endpoint: `catalogs`, }, }; const mappingConfig = getMappingConfig(ConfigCategory, __dirname); +// Function to construct endpoint based on the selected data center +const constructEndpoint = (dataCenter, category) => { + const baseUrl = BASE_URL[dataCenter] || BASE_URL.USDC; // Default to USDC if not found + return `${baseUrl}${category.endpoint}`; +}; + const IDENTIFY_MAX_BATCH_SIZE = 1000; const IDENTIFY_MAX_BODY_SIZE_IN_BYTES = 4000000; -const IDENTIFY_BATCH_ENDPOINT = 'https://api.iterable.com/api/users/bulkUpdate'; const TRACK_MAX_BATCH_SIZE = 8000; -const TRACK_BATCH_ENDPOINT = 'https://api.iterable.com/api/events/trackBulk'; module.exports = { mappingConfig, ConfigCategory, - TRACK_BATCH_ENDPOINT, + constructEndpoint, TRACK_MAX_BATCH_SIZE, IDENTIFY_MAX_BATCH_SIZE, - IDENTIFY_BATCH_ENDPOINT, IDENTIFY_MAX_BODY_SIZE_IN_BYTES, }; diff --git a/src/v0/destinations/iterable/transform.js b/src/v0/destinations/iterable/transform.js index 207a8d11865..dd67deef69e 100644 --- a/src/v0/destinations/iterable/transform.js +++ b/src/v0/destinations/iterable/transform.js @@ -14,6 +14,7 @@ const { filterEventsAndPrepareBatchRequests, registerDeviceTokenEventPayloadBuilder, registerBrowserTokenEventPayloadBuilder, + getCategoryWithEndpoint, } = require('./util'); const { constructPayload, @@ -116,12 +117,11 @@ const responseBuilderForRegisterDeviceOrBrowserTokenEvents = (message, destinati /** * Function to find category value - * @param {*} messageType * @param {*} message * @returns */ -const getCategory = (messageType, message) => { - const eventType = messageType.toLowerCase(); +const getCategory = (message, dataCenter) => { + const eventType = message.type.toLowerCase(); switch (eventType) { case EventType.IDENTIFY: @@ -129,17 +129,17 @@ const getCategory = (messageType, message) => { get(message, MappedToDestinationKey) && getDestinationExternalIDInfoForRetl(message, 'ITERABLE').objectType !== 'users' ) { - return ConfigCategory.CATALOG; + return getCategoryWithEndpoint(ConfigCategory.CATALOG, dataCenter); } - return ConfigCategory.IDENTIFY; + return getCategoryWithEndpoint(ConfigCategory.IDENTIFY, dataCenter); case EventType.PAGE: - return ConfigCategory.PAGE; + return getCategoryWithEndpoint(ConfigCategory.PAGE, dataCenter); case EventType.SCREEN: - return ConfigCategory.SCREEN; + return getCategoryWithEndpoint(ConfigCategory.SCREEN, dataCenter); case EventType.TRACK: - return getCategoryUsingEventName(message); + return getCategoryUsingEventName(message, dataCenter); case EventType.ALIAS: - return ConfigCategory.ALIAS; + return getCategoryWithEndpoint(ConfigCategory.ALIAS, dataCenter); default: throw new InstrumentationError(`Message type ${eventType} not supported`); } @@ -150,8 +150,7 @@ const process = (event) => { if (!message.type) { throw new InstrumentationError('Event type is required'); } - const messageType = message.type.toLowerCase(); - const category = getCategory(messageType, message); + const category = getCategory(message, destination.Config.dataCenter); const response = responseBuilder(message, category, destination); if (hasMultipleResponses(message, category, destination.Config)) { diff --git a/src/v0/destinations/iterable/util.js b/src/v0/destinations/iterable/util.js index 7c1509c2b79..b918600253f 100644 --- a/src/v0/destinations/iterable/util.js +++ b/src/v0/destinations/iterable/util.js @@ -14,10 +14,9 @@ const { ConfigCategory, mappingConfig, TRACK_MAX_BATCH_SIZE, - TRACK_BATCH_ENDPOINT, IDENTIFY_MAX_BATCH_SIZE, - IDENTIFY_BATCH_ENDPOINT, IDENTIFY_MAX_BODY_SIZE_IN_BYTES, + constructEndpoint, } = require('./config'); const { JSON_MIME_TYPE } = require('../../util/constant'); const { EventType, MappedToDestinationKey } = require('../../../constants'); @@ -88,12 +87,17 @@ const hasMultipleResponses = (message, category, config) => { return isIdentifyEvent && isIdentifyCategory && hasToken && hasRegisterDeviceOrBrowserKey; }; +const getCategoryWithEndpoint = (categoryConfig, dataCenter) => ({ + ...categoryConfig, + endpoint: constructEndpoint(dataCenter, categoryConfig), +}); + /** * Returns category value * @param {*} message * @returns */ -const getCategoryUsingEventName = (message) => { +const getCategoryUsingEventName = (message, dataCenter) => { let { event } = message; if (typeof event === 'string') { event = event.toLowerCase(); @@ -101,12 +105,12 @@ const getCategoryUsingEventName = (message) => { switch (event) { case 'order completed': - return ConfigCategory.TRACK_PURCHASE; + return getCategoryWithEndpoint(ConfigCategory.TRACK_PURCHASE, dataCenter); case 'product added': case 'product removed': - return ConfigCategory.UPDATE_CART; + return getCategoryWithEndpoint(ConfigCategory.UPDATE_CART, dataCenter); default: - return ConfigCategory.TRACK; + return getCategoryWithEndpoint(ConfigCategory.TRACK, dataCenter); } }; @@ -444,8 +448,8 @@ const processUpdateUserBatch = (chunk, registerDeviceOrBrowserTokenEvents) => { batchEventResponse.batchedRequest.body.JSON = { users: batch.users }; const { destination, metadata, nonBatchedRequests } = batch; - const { apiKey } = destination.Config; - + const { apiKey, dataCenter } = destination.Config; + const IDENTIFY_BATCH_ENDPOINT = constructEndpoint(dataCenter, { endpoint: 'users/bulkUpdate' }); const batchedResponse = combineBatchedAndNonBatchedEvents( apiKey, metadata, @@ -552,8 +556,8 @@ const processTrackBatch = (chunk) => { const metadata = []; const { destination } = chunk[0]; - const { apiKey } = destination.Config; - + const { apiKey, dataCenter } = destination.Config; + const TRACK_BATCH_ENDPOINT = constructEndpoint(dataCenter, { endpoint: 'events/trackBulk' }); chunk.forEach((event) => { metadata.push(event.metadata); events.push(get(event, `${MESSAGE_JSON_PATH}`)); @@ -653,12 +657,13 @@ const mapRegisterDeviceOrBrowserTokenEventsWithJobId = (events) => { */ const categorizeEvent = (event) => { const { message, metadata, destination, error } = event; + const { dataCenter } = destination.Config; if (error) { return { type: 'error', data: event }; } - if (message.endpoint === ConfigCategory.IDENTIFY.endpoint) { + if (message.endpoint === constructEndpoint(dataCenter, ConfigCategory.IDENTIFY)) { return { type: 'updateUser', data: { message, metadata, destination } }; } @@ -667,8 +672,8 @@ const categorizeEvent = (event) => { } if ( - message.endpoint === ConfigCategory.IDENTIFY_BROWSER.endpoint || - message.endpoint === ConfigCategory.IDENTIFY_DEVICE.endpoint + message.endpoint === constructEndpoint(dataCenter, ConfigCategory.IDENTIFY_BROWSER) || + message.endpoint === constructEndpoint(dataCenter, ConfigCategory.IDENTIFY_DEVICE) ) { return { type: 'registerDeviceOrBrowser', data: { message, metadata, destination } }; } @@ -753,4 +758,5 @@ module.exports = { filterEventsAndPrepareBatchRequests, registerDeviceTokenEventPayloadBuilder, registerBrowserTokenEventPayloadBuilder, + getCategoryWithEndpoint, }; diff --git a/test/integrations/destinations/iterable/processor/aliasTestData.ts b/test/integrations/destinations/iterable/processor/aliasTestData.ts index cac43767bbe..1ee41348596 100644 --- a/test/integrations/destinations/iterable/processor/aliasTestData.ts +++ b/test/integrations/destinations/iterable/processor/aliasTestData.ts @@ -1,4 +1,8 @@ -import { generateMetadata, transformResultBuilder } from './../../../testUtils'; +import { + generateMetadata, + overrideDestination, + transformResultBuilder, +} from './../../../testUtils'; import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; @@ -15,6 +19,7 @@ const destination: Destination = { Transformations: [], Config: { apiKey: 'testApiKey', + dataCenter: 'USDC', preferUserId: false, trackAllPages: true, trackNamedPages: false, @@ -94,4 +99,56 @@ export const aliasTestData: ProcessorTestData[] = [ }, }, }, + { + id: 'iterable-alias-test-1', + name: 'iterable', + description: 'Alias call with dataCenter as EUDC', + scenario: 'Business', + successCriteria: + 'Response should contain status code 200 and it should contain update email payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { dataCenter: 'EUDC' }), + message: { + anonymousId: 'anonId', + userId: 'new@email.com', + previousId: 'old@email.com', + name: 'ApplicationLoaded', + context: {}, + properties, + type: 'alias', + sentAt, + originalTimestamp, + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + headers, + endpoint: 'https://api.eu.iterable.com/api/users/updateEmail', + JSON: { + currentEmail: 'old@email.com', + newEmail: 'new@email.com', + }, + }), + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/iterable/processor/identifyTestData.ts b/test/integrations/destinations/iterable/processor/identifyTestData.ts index d05f87a11f1..21d294e2322 100644 --- a/test/integrations/destinations/iterable/processor/identifyTestData.ts +++ b/test/integrations/destinations/iterable/processor/identifyTestData.ts @@ -2,6 +2,7 @@ import { generateMetadata, transformResultBuilder, generateIndentifyPayload, + overrideDestination, } from './../../../testUtils'; import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; @@ -19,6 +20,7 @@ const destination: Destination = { Transformations: [], Config: { apiKey: 'testApiKey', + dataCenter: 'USDC', preferUserId: false, trackAllPages: true, trackNamedPages: false, @@ -55,6 +57,7 @@ const sentAt = '2020-08-28T16:26:16.473Z'; const originalTimestamp = '2020-08-28T16:26:06.468Z'; const updateUserEndpoint = 'https://api.iterable.com/api/users/update'; +const updateUserEndpointEUDC = 'https://api.eu.iterable.com/api/users/update'; export const identifyTestData: ProcessorTestData[] = [ { @@ -404,4 +407,58 @@ export const identifyTestData: ProcessorTestData[] = [ }, }, }, + { + id: 'iterable-identify-test-7', + name: 'iterable', + description: 'Indentify call to update user in iterable with EUDC dataCenter', + scenario: 'Business', + successCriteria: + 'Response should contain status code 200 and it should contain update user payload with all user traits and updateUserEndpointEUDC', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { dataCenter: 'EUDC' }), + message: { + anonymousId, + context: { + traits: user1Traits, + }, + traits: user1Traits, + type: 'identify', + sentAt, + originalTimestamp, + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + headers, + endpoint: updateUserEndpointEUDC, + JSON: { + email: user1Traits.email, + userId: anonymousId, + dataFields: user1Traits, + preferUserId: false, + mergeNestedObjects: true, + }, + }), + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/iterable/processor/pageScreenTestData.ts b/test/integrations/destinations/iterable/processor/pageScreenTestData.ts index 074d6b56dfb..a27cf9fe3b8 100644 --- a/test/integrations/destinations/iterable/processor/pageScreenTestData.ts +++ b/test/integrations/destinations/iterable/processor/pageScreenTestData.ts @@ -1,4 +1,8 @@ -import { generateMetadata, transformResultBuilder } from './../../../testUtils'; +import { + generateMetadata, + overrideDestination, + transformResultBuilder, +} from './../../../testUtils'; import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; @@ -15,6 +19,7 @@ const destination: Destination = { Transformations: [], Config: { apiKey: 'testApiKey', + dataCenter: 'USDC', preferUserId: false, trackAllPages: true, trackNamedPages: false, @@ -43,6 +48,7 @@ const sentAt = '2020-08-28T16:26:16.473Z'; const originalTimestamp = '2020-08-28T16:26:06.468Z'; const pageEndpoint = 'https://api.iterable.com/api/events/track'; +const pageEndpointEUDC = 'https://api.eu.iterable.com/api/events/track'; export const pageScreenTestData: ProcessorTestData[] = [ { @@ -406,4 +412,61 @@ export const pageScreenTestData: ProcessorTestData[] = [ }, }, }, + { + id: 'iterable-page-test-4', + name: 'iterable', + description: 'Page call with dataCenter as EUDC', + scenario: 'Business', + successCriteria: + 'Response should contain status code 200 and it should contain endpoint as pageEndpointEUDC', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { dataCenter: 'EUDC' }), + message: { + anonymousId, + name: 'ApplicationLoaded', + context: { + traits: { + email: 'sayan@gmail.com', + }, + }, + properties, + type: 'page', + sentAt, + originalTimestamp, + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + headers, + endpoint: pageEndpointEUDC, + JSON: { + userId: anonymousId, + dataFields: properties, + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded page', + }, + }), + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/iterable/processor/trackTestData.ts b/test/integrations/destinations/iterable/processor/trackTestData.ts index 296275ad773..2b7d2a9c47a 100644 --- a/test/integrations/destinations/iterable/processor/trackTestData.ts +++ b/test/integrations/destinations/iterable/processor/trackTestData.ts @@ -1,6 +1,7 @@ import { generateMetadata, generateTrackPayload, + overrideDestination, transformResultBuilder, } from './../../../testUtils'; import { Destination } from '../../../../../src/types'; @@ -19,6 +20,7 @@ const destination: Destination = { Transformations: [], Config: { apiKey: 'testApiKey', + dataCenter: 'USDC', preferUserId: false, trackAllPages: true, trackNamedPages: false, @@ -126,6 +128,7 @@ const sentAt = '2020-08-28T16:26:16.473Z'; const originalTimestamp = '2020-08-28T16:26:06.468Z'; const endpoint = 'https://api.iterable.com/api/events/track'; +const endpointEUDC = 'https://api.eu.iterable.com/api/events/track'; const updateCartEndpoint = 'https://api.iterable.com/api/commerce/updateCart'; const trackPurchaseEndpoint = 'https://api.iterable.com/api/commerce/trackPurchase'; @@ -714,4 +717,56 @@ export const trackTestData: ProcessorTestData[] = [ }, }, }, + { + id: 'iterable-track-test-9', + name: 'iterable', + description: 'Track call to add event with user with EUDC dataCenter', + scenario: 'Business', + successCriteria: + 'Response should contain status code 200 and it should contain event properties, event name and endpointEUDC', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { dataCenter: 'EUDC' }), + message: { + anonymousId, + event: 'Email Opened', + type: 'track', + context: {}, + properties, + sentAt, + originalTimestamp, + }, + metadata: generateMetadata(1), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + headers, + endpoint: endpointEUDC, + JSON: { + userId: 'anonId', + createdAt: 1598631966468, + eventName: 'Email Opened', + dataFields: properties, + }, + }), + statusCode: 200, + metadata: generateMetadata(1), + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/iterable/router/data.ts b/test/integrations/destinations/iterable/router/data.ts index 09eedc8eb85..1917c078ebd 100644 --- a/test/integrations/destinations/iterable/router/data.ts +++ b/test/integrations/destinations/iterable/router/data.ts @@ -247,6 +247,7 @@ export const data = [ destination: { Config: { apiKey: '12345', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: false, trackCategorisedPages: true, @@ -308,6 +309,7 @@ export const data = [ destConfig: { defaultConfig: [ 'apiKey', + 'dataCenter', 'mapToSingleEvent', 'trackAllPages', 'trackCategorisedPages', @@ -339,6 +341,7 @@ export const data = [ }, Config: { apiKey: '12345', + dataCenter: 'USDC', mapToSingleEvent: true, trackAllPages: false, trackCategorisedPages: true, @@ -414,6 +417,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: true, trackCategorisedPages: false, @@ -442,6 +446,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: true, trackCategorisedPages: false, @@ -472,6 +477,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: false, trackCategorisedPages: true, @@ -623,6 +629,7 @@ export const data = [ destination: { Config: { apiKey: '12345', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: false, trackCategorisedPages: true, @@ -686,6 +693,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: true, trackCategorisedPages: false, @@ -732,6 +740,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: true, trackCategorisedPages: false, @@ -765,6 +774,7 @@ export const data = [ destination: { Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', + dataCenter: 'USDC', mapToSingleEvent: false, trackAllPages: false, trackCategorisedPages: true, @@ -821,6 +831,7 @@ export const data = [ destConfig: { defaultConfig: [ 'apiKey', + 'dataCenter', 'mapToSingleEvent', 'trackAllPages', 'trackCategorisedPages', @@ -852,6 +863,7 @@ export const data = [ }, Config: { apiKey: '12345', + dataCenter: 'USDC', mapToSingleEvent: true, trackAllPages: false, trackCategorisedPages: true, @@ -867,4 +879,147 @@ export const data = [ }, }, }, + { + name: 'iterable', + description: 'Simple identify call with EUDC dataCenter', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + receivedAt: '2022-09-27T11:12:59.080Z', + sentAt: '2022-09-27T11:13:03.777Z', + messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', + originalTimestamp: '2022-09-27T11:13:03.777Z', + traits: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + channel: 'sources', + rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', + context: { + sources: { + version: 'feat.SupportForTrack', + job_run_id: 'ccpdlajh6cfi19mr1vs0', + task_run_id: 'ccpdlajh6cfi19mr1vsg', + batch_id: '4917ad78-280b-40d2-a30d-119434152a0f', + job_id: '2FLKJDcTdjPHQpq7pUjB34dQ5w6/Syncher', + task_id: 'rows_100', + }, + mappedToDestination: 'true', + externalId: [ + { id: 'Tiffany', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + ], + }, + timestamp: '2022-09-27T11:12:59.079Z', + type: 'identify', + userId: 'Tiffany', + recordId: '10', + request_ip: '10.1.86.248', + }, + metadata: { jobId: 2, userId: 'u1' }, + destination: { + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + dataCenter: 'EUDC', + hubID: '22066036', + }, + Enabled: true, + }, + }, + { + message: { + receivedAt: '2022-09-27T11:12:59.080Z', + sentAt: '2022-09-27T11:13:03.777Z', + messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', + originalTimestamp: '2022-09-27T11:13:03.777Z', + traits: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + channel: 'sources', + rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', + context: { + sources: { + version: 'feat.SupportForTrack', + job_run_id: 'ccpdlajh6cfi19mr1vs0', + task_run_id: 'ccpdlajh6cfi19mr1vsg', + batch_id: '4917ad78-280b-40d2-a30d-119434152a0f', + job_id: '2FLKJDcTdjPHQpq7pUjB34dQ5w6/Syncher', + task_id: 'rows_100', + }, + mappedToDestination: 'true', + externalId: [ + { id: 'ABC', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + ], + }, + timestamp: '2022-09-27T11:12:59.079Z', + type: 'identify', + userId: 'Tiffany', + recordId: '10', + request_ip: '10.1.86.248', + }, + metadata: { jobId: 2, userId: 'u1' }, + destination: { + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + dataCenter: 'EUDC', + hubID: '22066036', + }, + Enabled: true, + }, + }, + ], + destType: 'iterable', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.eu.iterable.com/api/catalogs/test-ruchira/items', + headers: { + 'Content-Type': 'application/json', + api_key: '583af2f8-15ba-49c0-8511-76383e7de07e', + }, + params: {}, + body: { + JSON: { + documents: { + Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + }, + replaceUploadedFieldsOnly: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [ + { jobId: 2, userId: 'u1' }, + { jobId: 2, userId: 'u1' }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + dataCenter: 'EUDC', + hubID: '22066036', + }, + Enabled: true, + }, + }, + ], + }, + }, + }, + }, ]; From 51bbc02d5b00ce1b8fe8c91b4a7041e926bae9bd Mon Sep 17 00:00:00 2001 From: Sandeep Digumarty Date: Wed, 13 Nov 2024 16:30:35 +0530 Subject: [PATCH 105/147] feat: now getting consent related fields from connection config from retl for GARL (#3877) --- .../recordTransform.js | 38 +++++++++++++++++-- .../router/data.ts | 4 +- .../router/record.ts | 2 + 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index 1c6284cd09b..5866b665385 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -29,6 +29,8 @@ const processRecordEventArray = ( typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, operationType, ) => { let outputPayloads = {}; @@ -81,7 +83,10 @@ const processRecordEventArray = ( const toSendEvents = []; Object.values(outputPayloads).forEach((data) => { - const consentObj = populateConsentFromConfig(destination.Config, consentConfigMap); + const consentObj = populateConsentFromConfig( + { userDataConsent, personalizationConsent }, + consentConfigMap, + ); toSendEvents.push( responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), ); @@ -96,7 +101,14 @@ function preparepayload(events, config) { const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); - const { audienceId, typeOfList, isHashRequired, userSchema } = config; + const { + audienceId, + typeOfList, + isHashRequired, + userSchema, + userDataConsent, + personalizationConsent, + } = config; const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), @@ -117,6 +129,8 @@ function preparepayload(events, config) { typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, 'remove', ); } @@ -132,6 +146,8 @@ function preparepayload(events, config) { typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, 'add', ); } @@ -147,6 +163,8 @@ function preparepayload(events, config) { typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, 'add', ); } @@ -169,19 +187,29 @@ function preparepayload(events, config) { function processRecordInputsV0(groupedRecordInputs) { const { destination, message } = groupedRecordInputs[0]; - const { audienceId, typeOfList, isHashRequired, userSchema } = destination.Config; + const { + audienceId, + typeOfList, + isHashRequired, + userSchema, + userDataConsent, + personalizationConsent, + } = destination.Config; return preparepayload(groupedRecordInputs, { audienceId: getOperationAudienceId(audienceId, message), typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, }); } function processRecordInputsV1(groupedRecordInputs) { const { connection, message } = groupedRecordInputs[0]; - const { audienceId, typeOfList, isHashRequired } = connection.config.destination; + const { audienceId, typeOfList, isHashRequired, userDataConsent, personalizationConsent } = + connection.config.destination; const identifiers = message?.identifiers; let userSchema; @@ -202,6 +230,8 @@ function processRecordInputsV1(groupedRecordInputs) { typeOfList, userSchema, isHashRequired, + userDataConsent, + personalizationConsent, }); } diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts index 6878e81f0dc..12d5c65f8f1 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/data.ts @@ -884,8 +884,8 @@ export const data = [ listId: '7090784486', customerId: '7693729833', consent: { - adPersonalization: 'UNSPECIFIED', - adUserData: 'UNSPECIFIED', + adPersonalization: 'GRANTED', + adUserData: 'GRANTED', }, }, body: { diff --git a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts index 2661500b4de..b3f1095b1d5 100644 --- a/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts +++ b/test/integrations/destinations/google_adwords_remarketing_lists/router/record.ts @@ -75,6 +75,8 @@ const connection2: Connection = { isHashRequired: true, typeOfList: 'userID', audienceId: '7090784486', + personalizationConsent: 'GRANTED', + userDataConsent: 'GRANTED', }, }, }; From e6b5fb749dcf66036257a439ce994b9aa9eacebf Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Wed, 13 Nov 2024 17:58:38 +0530 Subject: [PATCH 106/147] chore: output of conversion is optional --- .../conversionStrategies/strategyV1ToV2.ts | 2 +- .../conversionStrategies/strategyV2ToV0.ts | 2 +- .../conversionStrategies/strategyV2ToV1.ts | 2 +- src/controllers/util/index.test.ts | 2 -- src/services/source/nativeIntegration.ts | 25 ++++++++++++++----- src/types/index.ts | 2 +- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/controllers/util/conversionStrategies/strategyV1ToV2.ts b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts index b4f04ef8589..7cf4e778080 100644 --- a/src/controllers/util/conversionStrategies/strategyV1ToV2.ts +++ b/src/controllers/util/conversionStrategies/strategyV1ToV2.ts @@ -35,7 +35,7 @@ export class StrategyV1ToV2 extends VersionConversionStrategy, conversionError }; + return { conversionError }; } }); } diff --git a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts index d651917096f..52cade0d9d3 100644 --- a/src/controllers/util/conversionStrategies/strategyV2ToV1.ts +++ b/src/controllers/util/conversionStrategies/strategyV2ToV1.ts @@ -10,7 +10,7 @@ export class StrategyV2ToV1 extends VersionConversionStrategy { implementationVersion: 'v0', input: [ { - output: {}, conversionError: new SyntaxError('Unexpected end of JSON input'), }, ], @@ -322,7 +321,6 @@ describe('adaptInputToVersion', () => { implementationVersion: 'v1', input: [ { - output: {}, conversionError: new SyntaxError('Unexpected end of JSON input'), }, ], diff --git a/src/services/source/nativeIntegration.ts b/src/services/source/nativeIntegration.ts index 58a6a19649d..078716df96c 100644 --- a/src/services/source/nativeIntegration.ts +++ b/src/services/source/nativeIntegration.ts @@ -53,12 +53,25 @@ export class NativeIntegrationSourceService implements SourceService { metaTO, ); } - const newSourceEvent = sourceEvent.output; - const { headers } = newSourceEvent; - delete newSourceEvent.headers; - const respEvents: RudderMessage | RudderMessage[] | SourceTransformationResponse = - await sourceHandler.process(newSourceEvent); - return SourcePostTransformationService.handleSuccessEventsSource(respEvents, { headers }); + + if (sourceEvent.output) { + const newSourceEvent = sourceEvent.output; + + const { headers } = newSourceEvent; + if (headers) { + delete newSourceEvent.headers; + } + + const respEvents: RudderMessage | RudderMessage[] | SourceTransformationResponse = + await sourceHandler.process(newSourceEvent); + return SourcePostTransformationService.handleSuccessEventsSource(respEvents, { + headers, + }); + } + return SourcePostTransformationService.handleFailureEventsSource( + new Error('Error post version converstion, converstion output is undefined'), + metaTO, + ); } catch (error: FixMe) { stats.increment('source_transform_errors', { source: sourceType, diff --git a/src/types/index.ts b/src/types/index.ts index ee225bb0c0d..7c07f659df3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -374,7 +374,7 @@ type SourceInputV2 = { }; type SourceInputConversionResult = { - output: T; + output?: T; conversionError?: Error; }; From e90d2ad878f1350bc5b905a27772f9dc380ce5a5 Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Wed, 13 Nov 2024 18:32:09 +0530 Subject: [PATCH 107/147] chore: added test cases for v1-v2 conversion errors --- src/controllers/util/index.test.ts | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/controllers/util/index.test.ts b/src/controllers/util/index.test.ts index c5cefdeeeb3..4559bccc523 100644 --- a/src/controllers/util/index.test.ts +++ b/src/controllers/util/index.test.ts @@ -402,6 +402,47 @@ describe('adaptInputToVersion', () => { expect(result).toEqual(expected); }); + + it('should fail trying to convert input from v1 to v2 format when the request version is v1 and the implementation version is v2', () => { + const sourceType = 'someSourceType'; + const requestVersion = 'v1'; + + // Mock return value for getSourceVersionsMap + jest + .spyOn(ControllerUtility as any, 'getSourceVersionsMap') + .mockReturnValue(new Map([['someSourceType', 'v2']])); + + const input = [ + { + event: { + key: 'value', + query_parameters: { paramkey: ['paramvalue'] }, + largeNumber: BigInt(12345678901234567890n), + }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + { + event: { key: 'value', largeNumber: BigInt(12345678901234567890n) }, + source: { id: 'source_id', config: { configField1: 'configVal1' } }, + }, + ]; + + const expected = { + implementationVersion: 'v2', + input: [ + { + conversionError: new TypeError('Do not know how to serialize a BigInt'), + }, + { + conversionError: new TypeError('Do not know how to serialize a BigInt'), + }, + ], + }; + + const result = ControllerUtility.adaptInputToVersion(sourceType, requestVersion, input); + + expect(result).toEqual(expected); + }); }); type timestampTestCases = { From 12ac3de6e7cc91a6cd52c33bc342f74bbaa8a631 Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:46:40 +0530 Subject: [PATCH 108/147] feat: added support to eu/us2 datacenter for gainsight px destination (#3871) * feat: added support to eu/us2 datacenter for gainsight px destination * fix: added unit test --- src/v0/destinations/gainsight_px/config.js | 31 ++++++++++++++++--- .../destinations/gainsight_px/config.test.js | 27 ++++++++++++++++ src/v0/destinations/gainsight_px/transform.js | 13 ++++---- src/v0/destinations/gainsight_px/util.js | 10 +++--- 4 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 src/v0/destinations/gainsight_px/config.test.js diff --git a/src/v0/destinations/gainsight_px/config.js b/src/v0/destinations/gainsight_px/config.js index cc058f88d24..a5ced4f1a75 100644 --- a/src/v0/destinations/gainsight_px/config.js +++ b/src/v0/destinations/gainsight_px/config.js @@ -1,12 +1,27 @@ const { getMappingConfig } = require('../../util'); const BASE_ENDPOINT = 'https://api.aptrinsic.com/v1'; -const ENDPOINTS = { - USERS_ENDPOINT: `${BASE_ENDPOINT}/users`, - CUSTOM_EVENTS_ENDPOINT: `${BASE_ENDPOINT}/events/custom`, - ACCOUNTS_ENDPOINT: `${BASE_ENDPOINT}/accounts`, +const BASE_EU_ENDPOINT = 'https://api-eu.aptrinsic.com/v1'; +const BASE_US2_ENDPOINT = 'https://api-us2.aptrinsic.com/v1'; + +const getBaseEndpoint = (Config) => { + const { dataCenter } = Config; + switch (dataCenter) { + case 'EU': + return BASE_EU_ENDPOINT; + case 'US2': + return BASE_US2_ENDPOINT; + default: + return BASE_ENDPOINT; + } }; +const getUsersEndpoint = (Config) => `${getBaseEndpoint(Config)}/users`; + +const getCustomEventsEndpoint = (Config) => `${getBaseEndpoint(Config)}/events/custom`; + +const getAccountsEndpoint = (Config) => `${getBaseEndpoint(Config)}/accounts`; + const CONFIG_CATEGORIES = { IDENTIFY: { type: 'identify', name: 'GainsightPX_Identify' }, TRACK: { type: 'track', name: 'GainsightPX_Track' }, @@ -79,10 +94,16 @@ const ACCOUNT_EXCLUSION_FIELDS = [ ]; module.exports = { - ENDPOINTS, USER_EXCLUSION_FIELDS, ACCOUNT_EXCLUSION_FIELDS, identifyMapping: MAPPING_CONFIG[CONFIG_CATEGORIES.IDENTIFY.name], trackMapping: MAPPING_CONFIG[CONFIG_CATEGORIES.TRACK.name], groupMapping: MAPPING_CONFIG[CONFIG_CATEGORIES.GROUP.name], + getUsersEndpoint, + getCustomEventsEndpoint, + getAccountsEndpoint, + BASE_ENDPOINT, + BASE_EU_ENDPOINT, + BASE_US2_ENDPOINT, + getBaseEndpoint, }; diff --git a/src/v0/destinations/gainsight_px/config.test.js b/src/v0/destinations/gainsight_px/config.test.js new file mode 100644 index 00000000000..825396d3505 --- /dev/null +++ b/src/v0/destinations/gainsight_px/config.test.js @@ -0,0 +1,27 @@ +const { BASE_ENDPOINT, BASE_EU_ENDPOINT, BASE_US2_ENDPOINT, getBaseEndpoint } = require('./config'); + +describe('getBaseEndpoint method test', () => { + it('Should return BASE_ENDPOINT when destination.Config.dataCenter is not "EU" or "US2"', () => { + const Config = { + dataCenter: 'US', + }; + const result = getBaseEndpoint(Config); + expect(result).toBe(BASE_ENDPOINT); + }); + + it('Should return BASE_EU_ENDPOINT when destination.Config.dataCenter is "EU"', () => { + const Config = { + dataCenter: 'EU', + }; + const result = getBaseEndpoint(Config); + expect(result).toBe(BASE_EU_ENDPOINT); + }); + + it('Should return BASE_US2_ENDPOINT when destination.Config.dataCenter is "US2"', () => { + const Config = { + dataCenter: 'US2', + }; + const result = getBaseEndpoint(Config); + expect(result).toBe(BASE_US2_ENDPOINT); + }); +}); diff --git a/src/v0/destinations/gainsight_px/transform.js b/src/v0/destinations/gainsight_px/transform.js index 0911b76b6cb..496099a6b41 100644 --- a/src/v0/destinations/gainsight_px/transform.js +++ b/src/v0/destinations/gainsight_px/transform.js @@ -27,12 +27,13 @@ const { formatEventProps, } = require('./util'); const { - ENDPOINTS, USER_EXCLUSION_FIELDS, ACCOUNT_EXCLUSION_FIELDS, trackMapping, groupMapping, identifyMapping, + getUsersEndpoint, + getCustomEventsEndpoint, } = require('./config'); const { JSON_MIME_TYPE } = require('../../util/constant'); @@ -92,7 +93,7 @@ const identifyResponseBuilder = async (message, { Config }, metadata) => { if (isUserPresent) { // update user response.method = defaultPutRequestConfig.requestMethod; - response.endpoint = `${ENDPOINTS.USERS_ENDPOINT}/${userId}`; + response.endpoint = `${getUsersEndpoint(Config)}/${userId}`; response.body.JSON = removeUndefinedAndNullValues(payload); return response; } @@ -100,7 +101,7 @@ const identifyResponseBuilder = async (message, { Config }, metadata) => { // create new user payload.identifyId = userId; response.method = defaultPostRequestConfig.requestMethod; - response.endpoint = ENDPOINTS.USERS_ENDPOINT; + response.endpoint = getUsersEndpoint(Config); response.body.JSON = removeUndefinedAndNullValues(payload); return response; }; @@ -162,7 +163,7 @@ const newGroupResponseBuilder = async (message, { Config }, metadata) => { 'X-APTRINSIC-API-KEY': Config.apiKey, 'Content-Type': JSON_MIME_TYPE, }; - response.endpoint = `${ENDPOINTS.USERS_ENDPOINT}/${userId}`; + response.endpoint = `${getUsersEndpoint(Config)}/${userId}`; response.body.JSON = { accountId: groupId, }; @@ -230,7 +231,7 @@ const groupResponseBuilder = async (message, { Config }, metadata) => { 'X-APTRINSIC-API-KEY': Config.apiKey, 'Content-Type': JSON_MIME_TYPE, }; - response.endpoint = `${ENDPOINTS.USERS_ENDPOINT}/${userId}`; + response.endpoint = `${getUsersEndpoint(Config)}/${userId}`; response.body.JSON = { accountId: groupId, }; @@ -271,7 +272,7 @@ const trackResponseBuilder = (message, { Config }) => { 'X-APTRINSIC-API-KEY': Config.apiKey, 'Content-Type': JSON_MIME_TYPE, }; - response.endpoint = ENDPOINTS.CUSTOM_EVENTS_ENDPOINT; + response.endpoint = getCustomEventsEndpoint(Config); return response; }; diff --git a/src/v0/destinations/gainsight_px/util.js b/src/v0/destinations/gainsight_px/util.js index 7300189297b..71d85438de9 100644 --- a/src/v0/destinations/gainsight_px/util.js +++ b/src/v0/destinations/gainsight_px/util.js @@ -1,9 +1,9 @@ const { NetworkError } = require('@rudderstack/integrations-lib'); -const { ENDPOINTS } = require('./config'); const tags = require('../../util/tags'); const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); const { JSON_MIME_TYPE } = require('../../util/constant'); const { handleHttpRequest } = require('../../../adapters/network'); +const { getUsersEndpoint, getAccountsEndpoint } = require('./config'); const handleErrorResponse = (error, customErrMessage, expectedErrStatus, defaultStatus = 400) => { let destResp; @@ -38,10 +38,10 @@ const handleErrorResponse = (error, customErrMessage, expectedErrStatus, default * @returns */ const objectExists = async (id, Config, objectType, metadata) => { - let url = `${ENDPOINTS.USERS_ENDPOINT}/${id}`; + let url = `${getUsersEndpoint(Config)}/${id}`; if (objectType === 'account') { - url = `${ENDPOINTS.ACCOUNTS_ENDPOINT}/${id}`; + url = `${getAccountsEndpoint(Config)}/${id}`; } const { httpResponse: res } = await handleHttpRequest( 'get', @@ -70,7 +70,7 @@ const objectExists = async (id, Config, objectType, metadata) => { const createAccount = async (payload, Config, metadata) => { const { httpResponse: res } = await handleHttpRequest( 'post', - ENDPOINTS.ACCOUNTS_ENDPOINT, + getAccountsEndpoint(Config), payload, { headers: { @@ -96,7 +96,7 @@ const createAccount = async (payload, Config, metadata) => { const updateAccount = async (accountId, payload, Config, metadata) => { const { httpResponse: res } = await handleHttpRequest( 'put', - `${ENDPOINTS.ACCOUNTS_ENDPOINT}/${accountId}`, + `${getAccountsEndpoint(Config)}/${accountId}`, payload, { headers: { From 6554893a38102c72f6619a4dd5f361dcfe2f1d61 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Fri, 15 Nov 2024 15:21:34 +0530 Subject: [PATCH 109/147] chore: clean up Marketo implementation for file upload et al (#3872) chore. clean up marketo implementation for fileupload et al. --- src/util/fetchDestinationHandlers.ts | 10 +- .../marketo_bulk_upload/config.js | 55 -- .../marketo_bulk_upload/fetchJobStatus.js | 153 ----- .../marketo_bulk_upload/fileUpload.js | 275 --------- .../marketo_bulk_upload.util.test.js | 542 ------------------ .../destinations/marketo_bulk_upload/poll.js | 126 ---- .../marketo_bulk_upload_example.csv | 0 .../destinations/marketo_bulk_upload/util.js | 436 -------------- .../marketo_bulk_upload_fileUpload_input.json | 272 --------- ...marketo_bulk_upload_fileUpload_output.json | 63 -- .../data/marketo_bulk_upload_input.json | 270 --------- .../marketo_bulk_upload_jobStatus_input.json | 102 ---- .../marketo_bulk_upload_jobStatus_output.json | 28 - .../data/marketo_bulk_upload_output.json | 89 --- .../data/marketo_bulk_upload_poll_input.json | 59 -- .../data/marketo_bulk_upload_poll_output.json | 17 - test/__tests__/marketo_bulk_upload.test.js | 127 ---- 17 files changed, 3 insertions(+), 2621 deletions(-) delete mode 100644 src/v0/destinations/marketo_bulk_upload/config.js delete mode 100644 src/v0/destinations/marketo_bulk_upload/fetchJobStatus.js delete mode 100644 src/v0/destinations/marketo_bulk_upload/fileUpload.js delete mode 100644 src/v0/destinations/marketo_bulk_upload/marketo_bulk_upload.util.test.js delete mode 100644 src/v0/destinations/marketo_bulk_upload/poll.js delete mode 100644 src/v0/destinations/marketo_bulk_upload/uploadFile/marketo_bulk_upload_example.csv delete mode 100644 src/v0/destinations/marketo_bulk_upload/util.js delete mode 100644 test/__tests__/data/marketo_bulk_upload_fileUpload_input.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_fileUpload_output.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_input.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_jobStatus_input.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_jobStatus_output.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_output.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_poll_input.json delete mode 100644 test/__tests__/data/marketo_bulk_upload_poll_output.json delete mode 100644 test/__tests__/marketo_bulk_upload.test.js diff --git a/src/util/fetchDestinationHandlers.ts b/src/util/fetchDestinationHandlers.ts index 2661ef2e686..fa8cbb47c39 100644 --- a/src/util/fetchDestinationHandlers.ts +++ b/src/util/fetchDestinationHandlers.ts @@ -1,22 +1,18 @@ -import * as V0MarketoBulkUploadFileUpload from '../v0/destinations/marketo_bulk_upload/fileUpload'; -import * as V0MarketoBulkUploadPollStatus from '../v0/destinations/marketo_bulk_upload/poll'; -import * as V0MarketoBulkUploadJobStatus from '../v0/destinations/marketo_bulk_upload/fetchJobStatus'; - const fileUploadHandlers = { v0: { - marketo_bulk_upload: V0MarketoBulkUploadFileUpload, + marketo_bulk_upload: undefined, }, }; const pollStatusHandlers = { v0: { - marketo_bulk_upload: V0MarketoBulkUploadPollStatus, + marketo_bulk_upload: undefined, }, }; const jobStatusHandlers = { v0: { - marketo_bulk_upload: V0MarketoBulkUploadJobStatus, + marketo_bulk_upload: undefined, }, }; diff --git a/src/v0/destinations/marketo_bulk_upload/config.js b/src/v0/destinations/marketo_bulk_upload/config.js deleted file mode 100644 index e3268711fe1..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/config.js +++ /dev/null @@ -1,55 +0,0 @@ -const ABORTABLE_CODES = ['601', '603', '605', '609', '610']; -const RETRYABLE_CODES = ['713', '602', '604', '611']; -const THROTTLED_CODES = ['502', '606', '607', '608', '615']; - -const MARKETO_FILE_SIZE = 10485760; -const MARKETO_FILE_PATH = `${__dirname}/uploadFile/marketo_bulkupload.csv`; - -const FETCH_ACCESS_TOKEN = 'marketo_bulk_upload_access_token_fetching'; - -const POLL_ACTIVITY = 'marketo_bulk_upload_polling'; -const POLL_STATUS_ERR_MSG = 'Could not poll status'; - -const UPLOAD_FILE = 'marketo_bulk_upload_upload_file'; -const FILE_UPLOAD_ERR_MSG = 'Could not upload file'; - -const JOB_STATUS_ACTIVITY = 'marketo_bulk_upload_get_job_status'; -const FETCH_FAILURE_JOB_STATUS_ERR_MSG = 'Could not fetch failure job status'; -const FETCH_WARNING_JOB_STATUS_ERR_MSG = 'Could not fetch warning job status'; -const ACCESS_TOKEN_FETCH_ERR_MSG = 'Error during fetching access token'; - -const SCHEMA_DATA_TYPE_MAP = { - string: 'string', - number: 'number', - boolean: 'boolean', - undefined: 'undefined', - float: 'number', - text: 'string', - currency: 'string', - integer: 'number', - reference: 'string', - datetime: 'string', - date: 'string', - email: 'string', - phone: 'string', - url: 'string', - object: 'object', -}; - -module.exports = { - ABORTABLE_CODES, - RETRYABLE_CODES, - THROTTLED_CODES, - MARKETO_FILE_SIZE, - POLL_ACTIVITY, - UPLOAD_FILE, - JOB_STATUS_ACTIVITY, - MARKETO_FILE_PATH, - FETCH_ACCESS_TOKEN, - POLL_STATUS_ERR_MSG, - FILE_UPLOAD_ERR_MSG, - FETCH_FAILURE_JOB_STATUS_ERR_MSG, - FETCH_WARNING_JOB_STATUS_ERR_MSG, - ACCESS_TOKEN_FETCH_ERR_MSG, - SCHEMA_DATA_TYPE_MAP, -}; diff --git a/src/v0/destinations/marketo_bulk_upload/fetchJobStatus.js b/src/v0/destinations/marketo_bulk_upload/fetchJobStatus.js deleted file mode 100644 index db3b13eeb84..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/fetchJobStatus.js +++ /dev/null @@ -1,153 +0,0 @@ -/* eslint-disable no-restricted-syntax */ -/* eslint-disable no-prototype-builtins */ -const { PlatformError } = require('@rudderstack/integrations-lib'); -const { getAccessToken } = require('./util'); -const { handleHttpRequest } = require('../../../adapters/network'); -const stats = require('../../../util/stats'); -const { JSON_MIME_TYPE } = require('../../util/constant'); -const { - handleFetchJobStatusResponse, - getFieldSchemaMap, - checkEventStatusViaSchemaMatching, -} = require('./util'); -const { removeUndefinedValues } = require('../../util'); - -const getJobsStatus = async (event, type, accessToken) => { - const { config, importId } = event; - const { munchkinId } = config; - let url; - // Get status of each lead for failed leads - // DOC: https://developers.marketo.com/rest-api/bulk-import/bulk-lead-import/#failures - const requestOptions = { - headers: { - 'Content-Type': JSON_MIME_TYPE, - Authorization: `Bearer ${accessToken}`, - }, - }; - if (type === 'fail') { - url = `https://${munchkinId}.mktorest.com/bulk/v1/leads/batch/${importId}/failures.json`; - } else { - url = `https://${munchkinId}.mktorest.com/bulk/v1/leads/batch/${importId}/warnings.json`; - } - const startTime = Date.now(); - const { processedResponse: resp } = await handleHttpRequest('get', url, requestOptions, { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/leads/batch/', - requestMethod: 'GET', - module: 'router', - }); - const endTime = Date.now(); - const requestTime = endTime - startTime; - - stats.histogram('marketo_bulk_upload_fetch_job_time', requestTime); - - return handleFetchJobStatusResponse(resp, type); -}; - -/** - * Handles the response from the server based on the provided type. - * Retrieves the job status using the getJobsStatus function and processes the response data. - * Matches the response data with the data received from the server. - * Returns a response object containing the failed keys, failed reasons, warning keys, warning reasons, and succeeded keys. - * @param {Object} event - An object containing the input data and metadata. - * @param {string} type - A string indicating the type of job status to retrieve ("fail" or "warn"). - * @returns {Object} - A response object with the failed keys, failed reasons, warning keys, warning reasons, and succeeded keys. - */ -const responseHandler = async (event, type) => { - let FailedKeys = []; - const unsuccessfulJobIdsArr = []; - let successfulJobIdsArr = []; - let reasons = {}; - - const { config } = event; - const accessToken = await getAccessToken(config); - - /** - * { - "FailedKeys" : [jobID1,jobID3], - "FailedReasons" : { - "jobID1" : "failure-reason-1", - "jobID3" : "failure-reason-2", - }, - "WarningKeys" : [jobID2,jobID4], - "WarningReasons" : { - "jobID2" : "warning-reason-1", - "jobID4" : "warning-reason-2", - }, - "SucceededKeys" : [jobID5] -} - */ - - const jobStatus = - type === 'fail' - ? await getJobsStatus(event, 'fail', accessToken) - : await getJobsStatus(event, 'warn', accessToken); - const jobStatusArr = jobStatus.toString().split('\n'); // responseArr = ['field1,field2,Import Failure Reason', 'val1,val2,reason',...] - const { input, metadata } = event; - let headerArr; - if (metadata?.csvHeader) { - headerArr = metadata.csvHeader.split(','); - } else { - throw new PlatformError('No csvHeader in metadata'); - } - const startTime = Date.now(); - const data = {}; - const fieldSchemaMapping = await getFieldSchemaMap(accessToken, config.munchkinId); - const unsuccessfulJobInfo = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - const mismatchJobIdArray = Object.keys(unsuccessfulJobInfo); - const dataTypeMismatchKeys = mismatchJobIdArray.map((strJobId) => parseInt(strJobId, 10)); - reasons = { ...unsuccessfulJobInfo }; - - const filteredEvents = input.filter( - (item) => !dataTypeMismatchKeys.includes(item.metadata.job_id), - ); - // create a map of job_id and data sent from server - // {: ','} - filteredEvents.forEach((i) => { - const response = headerArr.map((fieldName) => Object.values(i)[0][fieldName]).join(','); - data[i.metadata.job_id] = response; - }); - - // match marketo response data with received data from server - for (const element of jobStatusArr) { - // split response by comma but ignore commas inside double quotes - const elemArr = element.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/); - // ref : - // https://developers.marketo.com/rest-api/bulk-import/bulk-custom-object-import/#:~:text=Now%20we%E2%80%99ll%20make%20Get%20Import%20Custom%20Object%20Failures%20endpoint%20call%20to%20get%20additional%20failure%20detail%3A - const reasonMessage = elemArr.pop(); // get the column named "Import Failure Reason" - for (const [key, val] of Object.entries(data)) { - // joining the parameter values sent from marketo match it with received data from server - if (val === `${elemArr.map((item) => item.replace(/"/g, '')).join(',')}`) { - // add job keys if warning/failure - if (!unsuccessfulJobIdsArr.includes(key)) { - unsuccessfulJobIdsArr.push(key); - } - reasons[key] = reasonMessage; - } - } - } - - FailedKeys = unsuccessfulJobIdsArr.map((strJobId) => parseInt(strJobId, 10)); - successfulJobIdsArr = Object.keys(data).filter((x) => !unsuccessfulJobIdsArr.includes(x)); - - const SucceededKeys = successfulJobIdsArr.map((strJobId) => parseInt(strJobId, 10)); - const endTime = Date.now(); - const requestTime = endTime - startTime; - stats.histogram('marketo_bulk_upload_fetch_job_create_response_time', requestTime); - const response = { - statusCode: 200, - metadata: { - FailedKeys: [...dataTypeMismatchKeys, ...FailedKeys], - FailedReasons: reasons, - SucceededKeys, - }, - }; - return removeUndefinedValues(response); -}; - -const processJobStatus = async (event, type) => { - const resp = await responseHandler(event, type); - return resp; -}; -module.exports = { processJobStatus }; diff --git a/src/v0/destinations/marketo_bulk_upload/fileUpload.js b/src/v0/destinations/marketo_bulk_upload/fileUpload.js deleted file mode 100644 index b49a265fd53..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/fileUpload.js +++ /dev/null @@ -1,275 +0,0 @@ -/* eslint-disable no-plusplus */ -const FormData = require('form-data'); -const fs = require('fs'); -const { - NetworkError, - ConfigurationError, - RetryableError, - TransformationError, -} = require('@rudderstack/integrations-lib'); -const { - getAccessToken, - getMarketoFilePath, - handleFileUploadResponse, - getFieldSchemaMap, - hydrateStatusForServer, -} = require('./util'); -const { isHttpStatusSuccess } = require('../../util'); -const { MARKETO_FILE_SIZE, UPLOAD_FILE } = require('./config'); -const { - getHashFromArray, - removeUndefinedAndNullValues, - isDefinedAndNotNullAndNotEmpty, -} = require('../../util'); -const { handleHttpRequest } = require('../../../adapters/network'); -const { client } = require('../../../util/errorNotifier'); -const stats = require('../../../util/stats'); - -const fetchFieldSchemaNames = async (config, accessToken) => { - const fieldSchemaMapping = await getFieldSchemaMap(accessToken, config.munchkinId); - if (Object.keys(fieldSchemaMapping).length > 0) { - const fieldSchemaNames = Object.keys(fieldSchemaMapping); - return { fieldSchemaNames }; - } - throw new RetryableError('Failed to fetch Marketo Field Schema', 500, fieldSchemaMapping); -}; - -const getHeaderFields = (config, fieldSchemaNames) => { - const { columnFieldsMapping } = config; - - columnFieldsMapping.forEach((colField) => { - if (!fieldSchemaNames.includes(colField.to)) { - throw new ConfigurationError( - `The field ${colField.to} is not present in Marketo Field Schema. Aborting`, - ); - } - }); - const columnField = getHashFromArray(columnFieldsMapping, 'to', 'from', false); - return Object.keys(columnField); -}; -/** - * Processes input data to create a CSV file and returns the file data along with successful and unsuccessful job IDs. - * The file name is made unique with combination of UUID and current timestamp to avoid any overrides. It also has a - * maximum size limit of 10MB . The events that could be accomodated inside the file is marked as successful and the - * rest are marked as unsuccessful. Also the file is deleted when reading is complete. - * @param {Array} inputEvents - An array of input events. - * @param {Object} config - destination config - * @param {Array} headerArr - An array of header fields. - * @returns {Object} - An object containing the file stream, successful job IDs, and unsuccessful job IDs. - */ -const getFileData = async (inputEvents, config, headerArr) => { - const input = inputEvents; - const messageArr = []; - let startTime; - let endTime; - let requestTime; - startTime = Date.now(); - - input.forEach((i) => { - const inputData = i; - const jobId = inputData.metadata.job_id; - const data = {}; - data[jobId] = inputData.message; - messageArr.push(data); - }); - - if (isDefinedAndNotNullAndNotEmpty(config.deDuplicationField)) { - // dedup starts - // Time Complexity = O(n2) - const dedupMap = new Map(); - // iterating input and storing the occurences of messages - // with same dedup property received from config - // Example: dedup-property = email - // k (key) v (index of occurence in input) - // user@email [4,7,9] - // user2@email [2,3] - // user3@email [1] - input.forEach((element, index) => { - const indexAr = dedupMap.get(element.message[config.deDuplicationField]) || []; - indexAr.push(index); - dedupMap.set(element.message[config.deDuplicationField], indexAr); - return dedupMap; - }); - // 1. iterating dedupMap - // 2. storing the duplicate occurences in dupValues arr - // 3. iterating dupValues arr, and mapping each property on firstBorn - // 4. as dupValues arr is sorted hence the firstBorn will inherit properties of last occurence (most updated one) - // 5. store firstBorn to first occurence in input as it should get the highest priority - dedupMap.forEach((indexes) => { - let firstBorn = {}; - indexes.forEach((idx) => { - headerArr.forEach((headerStr) => { - // if duplicate item has defined property to offer we take it else old one remains - firstBorn[headerStr] = input[idx].message[headerStr] || firstBorn[headerStr]; - }); - }); - firstBorn = removeUndefinedAndNullValues(firstBorn); - input[indexes[0]].message = firstBorn; - }); - // dedup ends - } - - const csv = []; - csv.push(headerArr.toString()); - endTime = Date.now(); - requestTime = endTime - startTime; - stats.histogram('marketo_bulk_upload_create_header_time', requestTime); - const unsuccessfulJobs = []; - const successfulJobs = []; - const MARKETO_FILE_PATH = getMarketoFilePath(); - startTime = Date.now(); - messageArr.forEach((row) => { - const csvSize = JSON.stringify(csv); // stringify and remove all "stringification" extra data - const response = headerArr - .map((fieldName) => JSON.stringify(Object.values(row)[0][fieldName], '')) - .join(','); - if (csvSize.length <= MARKETO_FILE_SIZE) { - csv.push(response); - successfulJobs.push(Object.keys(row)[0]); - } else { - unsuccessfulJobs.push(Object.keys(row)[0]); - } - }); - endTime = Date.now(); - requestTime = endTime - startTime; - stats.histogram('marketo_bulk_upload_create_csvloop_time', requestTime); - const fileSize = Buffer.from(csv.join('\n')).length; - if (csv.length > 1) { - startTime = Date.now(); - fs.writeFileSync(MARKETO_FILE_PATH, csv.join('\n')); - const readStream = fs.readFileSync(MARKETO_FILE_PATH); - fs.unlinkSync(MARKETO_FILE_PATH); - endTime = Date.now(); - requestTime = endTime - startTime; - stats.histogram('marketo_bulk_upload_create_file_time', requestTime); - stats.histogram('marketo_bulk_upload_upload_file_size', fileSize); - - return { readStream, successfulJobs, unsuccessfulJobs }; - } - return { successfulJobs, unsuccessfulJobs }; -}; - -const getImportID = async (input, config, accessToken, csvHeader) => { - let readStream; - let successfulJobs; - let unsuccessfulJobs; - try { - ({ readStream, successfulJobs, unsuccessfulJobs } = await getFileData( - input, - config, - csvHeader, - )); - } catch (err) { - client.notify(err, `Marketo File Upload: Error while creating file: ${err.message}`, { - config, - csvHeader, - }); - throw new TransformationError( - `Marketo File Upload: Error while creating file: ${err.message}`, - 500, - ); - } - - const formReq = new FormData(); - const { munchkinId, deDuplicationField } = config; - // create file for multipart form - if (readStream) { - formReq.append('format', 'csv'); - formReq.append('file', readStream, 'marketo_bulk_upload.csv'); - formReq.append('access_token', accessToken); - // Upload data received from server as files to marketo - // DOC: https://developers.marketo.com/rest-api/bulk-import/bulk-lead-import/#import_file - const requestOptions = { - headers: { - ...formReq.getHeaders(), - }, - }; - if (isDefinedAndNotNullAndNotEmpty(deDuplicationField)) { - requestOptions.params = { - lookupField: deDuplicationField, - }; - } - const startTime = Date.now(); - const { processedResponse: resp } = await handleHttpRequest( - 'post', - `https://${munchkinId}.mktorest.com/bulk/v1/leads.json`, - formReq, - requestOptions, - { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/leads.json', - requestMethod: 'POST', - module: 'router', - }, - ); - const endTime = Date.now(); - const requestTime = endTime - startTime; - stats.counter('marketo_bulk_upload_upload_file_succJobs', successfulJobs.length); - stats.counter('marketo_bulk_upload_upload_file_unsuccJobs', unsuccessfulJobs.length); - if (!isHttpStatusSuccess(resp.status)) { - throw new NetworkError( - `Unable to upload file due to error : ${JSON.stringify(resp.response)}`, - hydrateStatusForServer(resp.status, 'During uploading file'), - ); - } - return handleFileUploadResponse(resp, successfulJobs, unsuccessfulJobs, requestTime); - } - return { importId: null, successfulJobs, unsuccessfulJobs }; -}; - -/** - * - * @param {*} input - * @param {*} config - * @returns returns the final response of fileUpload.js - */ -const responseHandler = async (input, config) => { - const accessToken = await getAccessToken(config); - /** - { - "importId" : , - "pollURL" : , - } - */ - const { fieldSchemaNames } = await fetchFieldSchemaNames(config, accessToken); - const headerForCsv = getHeaderFields(config, fieldSchemaNames); - if (Object.keys(headerForCsv).length === 0) { - throw new ConfigurationError( - 'Faulty configuration. Please map your traits to Marketo column fields', - ); - } - const { importId, successfulJobs, unsuccessfulJobs } = await getImportID( - input, - config, - accessToken, - headerForCsv, - ); - // if upload is successful - if (importId) { - const csvHeader = headerForCsv.toString(); - const metadata = { successfulJobs, unsuccessfulJobs, csvHeader }; - const response = { - statusCode: 200, - importId, - metadata, - }; - return response; - } - // if importId is returned null - stats.increment(UPLOAD_FILE, { - status: 500, - state: 'Retryable', - }); - return { - statusCode: 500, - FailedReason: '[Marketo File upload]: No import id received', - }; -}; -const processFileData = async (event) => { - const { input, config } = event; - const resp = await responseHandler(input, config); - return resp; -}; - -module.exports = { processFileData }; diff --git a/src/v0/destinations/marketo_bulk_upload/marketo_bulk_upload.util.test.js b/src/v0/destinations/marketo_bulk_upload/marketo_bulk_upload.util.test.js deleted file mode 100644 index 13e1b3a09a0..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/marketo_bulk_upload.util.test.js +++ /dev/null @@ -1,542 +0,0 @@ -const { - handleCommonErrorResponse, - handlePollResponse, - handleFileUploadResponse, - getAccessToken, - checkEventStatusViaSchemaMatching, -} = require('./util'); - -const { - AbortedError, - RetryableError, - NetworkError, - TransformationError, -} = require('@rudderstack/integrations-lib'); -const util = require('./util.js'); -const networkAdapter = require('../../../adapters/network'); -const { handleHttpRequest } = networkAdapter; - -// Mock the handleHttpRequest function -jest.mock('../../../adapters/network'); - -const successfulResponse = { - status: 200, - response: { - access_token: '', - token_type: 'bearer', - expires_in: 3600, - scope: 'dummy@scope.com', - success: true, - }, -}; - -const unsuccessfulResponse = { - status: 400, - response: '[ENOTFOUND] :: DNS lookup failed', -}; - -const emptyResponse = { - response: '', -}; - -const invalidClientErrorResponse = { - status: 401, - response: { - error: 'invalid_client', - error_description: 'Bad client credentials', - }, -}; - -describe('handleCommonErrorResponse', () => { - test('should throw AbortedError for abortable error codes', () => { - const resp = { - response: { - errors: [{ code: 1003, message: 'Aborted' }], - }, - }; - expect(() => handleCommonErrorResponse(resp, 'opErrorMessage', 'opActivity')).toThrow( - AbortedError, - ); - }); - - test('should throw ThrottledError for throttled error codes', () => { - const resp = { - response: { - errors: [{ code: 615, message: 'Throttled' }], - }, - }; - expect(() => handleCommonErrorResponse(resp, 'opErrorMessage', 'opActivity')).toThrow( - RetryableError, - ); - }); - - test('should throw RetryableError for other error codes', () => { - const resp = { - response: { - errors: [{ code: 2000, message: 'Retryable' }], - }, - }; - expect(() => handleCommonErrorResponse(resp, 'opErrorMessage', 'opActivity')).toThrow( - RetryableError, - ); - }); - - test('should throw RetryableError by default', () => { - const resp = { - response: { - errors: [], - }, - }; - expect(() => handleCommonErrorResponse(resp, 'opErrorMessage', 'opActivity')).toThrow( - RetryableError, - ); - }); -}); - -describe('handlePollResponse', () => { - // Tests that the function returns the response object if the polling operation was successful - it('should return the response object when the polling operation was successful', () => { - const pollStatus = { - response: { - success: true, - result: [ - { - batchId: '123', - status: 'Complete', - numOfLeadsProcessed: 2, - numOfRowsFailed: 1, - numOfRowsWithWarning: 0, - message: 'Import completed with errors, 2 records imported (2 members), 1 failed', - }, - ], - }, - }; - - const result = handlePollResponse(pollStatus); - - expect(result).toEqual(pollStatus.response); - }); - - // Tests that the function throws an AbortedError if the response contains an abortable error code - it('should throw an AbortedError when the response contains an abortable error code', () => { - const pollStatus = { - response: { - errors: [ - { - code: 1003, - message: 'Empty file', - }, - ], - }, - }; - - expect(() => handlePollResponse(pollStatus)).toThrow(AbortedError); - }); - - // Tests that the function throws a ThrottledError if the response contains a throttled error code - it('should throw a ThrottledError when the response contains a throttled error code', () => { - const pollStatus = { - response: { - errors: [ - { - code: 615, - message: 'Exceeded concurrent usage limit', - }, - ], - }, - }; - - expect(() => handlePollResponse(pollStatus)).toThrow(RetryableError); - }); - - // Tests that the function throws a RetryableError if the response contains an error code that is not abortable or throttled - it('should throw a RetryableError when the response contains an error code that is not abortable or throttled', () => { - const pollStatus = { - response: { - errors: [ - { - code: 601, - message: 'Unauthorized', - }, - ], - }, - }; - - expect(() => handlePollResponse(pollStatus)).toThrow(RetryableError); - }); - - // Tests that the function returns null if the polling operation was not successful - it('should return null when the polling operation was not successful', () => { - const pollStatus = { - response: { - success: false, - }, - }; - - const result = handlePollResponse(pollStatus); - - expect(result).toBeNull(); - }); -}); - -describe('handleFileUploadResponse', () => { - // Tests that the function returns an object with importId, successfulJobs, and unsuccessfulJobs when the response indicates a successful upload. - it('should return an object with importId, successfulJobs, and unsuccessfulJobs when the response indicates a successful upload', () => { - const resp = { - response: { - success: true, - result: [ - { - importId: '3404', - status: 'Queued', - }, - ], - }, - }; - const successfulJobs = []; - const unsuccessfulJobs = []; - const requestTime = 100; - - const result = handleFileUploadResponse(resp, successfulJobs, unsuccessfulJobs, requestTime); - - expect(result).toEqual({ - importId: '3404', - successfulJobs: [], - unsuccessfulJobs: [], - }); - }); - - // Tests that the function throws a RetryableError when the response indicates an empty file. - it('should throw a RetryableError when the response indicates an empty file', () => { - const resp = { - response: { - errors: [ - { - code: '1003', - message: 'Empty File', - }, - ], - }, - }; - const successfulJobs = []; - const unsuccessfulJobs = []; - const requestTime = 100; - - expect(() => { - handleFileUploadResponse(resp, successfulJobs, unsuccessfulJobs, requestTime); - }).toThrow(RetryableError); - }); - - // Tests that the function throws a RetryableError when the response indicates more than 10 concurrent uses. - it('should throw a RetryableError when the response indicates more than 10 concurrent uses', () => { - const resp = { - response: { - errors: [ - { - code: '615', - message: 'Concurrent Use Limit Exceeded', - }, - ], - }, - }; - const successfulJobs = []; - const unsuccessfulJobs = []; - const requestTime = 100; - - expect(() => { - handleFileUploadResponse(resp, successfulJobs, unsuccessfulJobs, requestTime); - }).toThrow(RetryableError); - }); - - // Tests that the function throws a RetryableError when the response contains an error code between 1000 and 1077. - it('should throw a Aborted when the response contains an error code between 1000 and 1077', () => { - const resp = { - response: { - errors: [ - { - code: 1001, - message: 'Some Error', - }, - ], - }, - }; - const successfulJobs = []; - const unsuccessfulJobs = []; - const requestTime = 100; - - expect(() => { - handleFileUploadResponse(resp, successfulJobs, unsuccessfulJobs, requestTime); - }).toThrow(AbortedError); - }); -}); - -describe('getAccessToken', () => { - beforeEach(() => { - handleHttpRequest.mockClear(); - }); - - it('should retrieve and return access token on successful response', async () => { - const url = - 'https://dummyMunchkinId.mktorest.com/identity/oauth/token?client_id=dummyClientId&client_secret=dummyClientSecret&grant_type=client_credentials'; - - handleHttpRequest.mockResolvedValueOnce({ - processedResponse: successfulResponse, - }); - - const config = { - clientId: 'dummyClientId', - clientSecret: 'dummyClientSecret', - munchkinId: 'dummyMunchkinId', - }; - - const result = await getAccessToken(config); - expect(result).toBe(''); - expect(handleHttpRequest).toHaveBeenCalledTimes(1); - // Ensure your mock response structure is consistent with the actual behavior - expect(handleHttpRequest).toHaveBeenCalledWith('get', url, { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/identity/oauth/token', - feature: 'transformation', - module: 'router', - requestMethod: 'GET', - }); - }); - - it('should throw a NetworkError on unsuccessful HTTP status', async () => { - handleHttpRequest.mockResolvedValueOnce({ - processedResponse: unsuccessfulResponse, - }); - - const config = { - clientId: 'dummyClientId', - clientSecret: 'dummyClientSecret', - munchkinId: 'dummyMunchkinId', - }; - - await expect(getAccessToken(config)).rejects.toThrow(NetworkError); - }); - - it('should throw a RetryableError when expires_in is 0', async () => { - handleHttpRequest.mockResolvedValueOnce({ - processedResponse: { - ...successfulResponse, - response: { ...successfulResponse.response, expires_in: 0 }, - }, - }); - - const config = { - clientId: 'dummyClientId', - clientSecret: 'dummyClientSecret', - munchkinId: 'dummyMunchkinId', - }; - - await expect(getAccessToken(config)).rejects.toThrow(RetryableError); - }); - - it('should throw an AbortedError on unsuccessful response', async () => { - handleHttpRequest.mockResolvedValueOnce({ processedResponse: invalidClientErrorResponse }); - - const config = { - clientId: 'invalidClientID', - clientSecret: 'dummyClientSecret', - munchkinId: 'dummyMunchkinId', - }; - - await expect(getAccessToken(config)).rejects.toThrow(NetworkError); - }); - - it('should throw transformation error response', async () => { - handleHttpRequest.mockResolvedValueOnce({ processedResponse: emptyResponse }); - - const config = { - clientId: 'dummyClientId', - clientSecret: 'dummyClientSecret', - munchkinId: 'dummyMunchkinId', - }; - - await expect(getAccessToken(config)).rejects.toThrow(TransformationError); - }); -}); - -describe('checkEventStatusViaSchemaMatching', () => { - // The function correctly identifies fields with expected data types. - it('if event data types match with expected data types we send no field as mismatch', () => { - const event = { - input: [ - { - message: { - email: 'value1', - id: 123, - isLead: true, - }, - metadata: { - job_id: 'job1', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'string', - id: 'integer', - isLead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({}); - }); - - // The function correctly identifies fields with unexpected data types. - it('if event data types do not match with expected data types we send that field as mismatch', () => { - const event = { - input: [ - { - message: { - email: 123, - city: '123', - islead: true, - }, - metadata: { - job_id: 'job1', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'string', - city: 'number', - islead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({ - job1: 'invalid email', - }); - }); - - // The function correctly handles events with multiple fields. - it('For array of events the mismatch object fills up with each event errors', () => { - const event = { - input: [ - { - message: { - id: 'value1', - testCustomFieldScore: 123, - isLead: true, - }, - metadata: { - job_id: 'job1', - }, - }, - { - message: { - email: 'value2', - id: 456, - testCustomFieldScore: false, - }, - metadata: { - job_id: 'job2', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'email', - id: 'integer', - testCustomFieldScore: 'integer', - isLead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({ - job1: 'invalid id', - job2: 'invalid testCustomFieldScore', - }); - }); - - // The function correctly handles events with missing fields. - it('it is not mandatory to send all the fields present in schema', () => { - const event = { - input: [ - { - message: { - email: 'value1', - isLead: true, - }, - metadata: { - job_id: 'job1', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'string', - id: 'number', - isLead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({}); - }); - - // The function correctly handles events with additional fields. But this will not happen in our use case - it('for any field beyond schema fields will be mapped as invalid', () => { - const event = { - input: [ - { - message: { - email: 'value1', - id: 124, - isLead: true, - abc: 'value2', - }, - metadata: { - job_id: 'job1', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'string', - id: 'number', - isLead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({ - job1: 'invalid abc', - }); - }); - - // The function correctly handles events with null values. - it('should ignore event properties with null values', () => { - const event = { - input: [ - { - message: { - email: 'value1', - id: null, - isLead: true, - }, - metadata: { - job_id: 'job1', - }, - }, - ], - }; - const fieldSchemaMapping = { - email: 'string', - id: 'number', - isLead: 'boolean', - }; - - const result = checkEventStatusViaSchemaMatching(event, fieldSchemaMapping); - - expect(result).toEqual({}); - }); -}); diff --git a/src/v0/destinations/marketo_bulk_upload/poll.js b/src/v0/destinations/marketo_bulk_upload/poll.js deleted file mode 100644 index f53347d6e52..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/poll.js +++ /dev/null @@ -1,126 +0,0 @@ -const { NetworkError } = require('@rudderstack/integrations-lib'); -const { removeUndefinedValues, isHttpStatusSuccess } = require('../../util'); -const { getAccessToken, handlePollResponse, hydrateStatusForServer } = require('./util'); -const { handleHttpRequest } = require('../../../adapters/network'); -const stats = require('../../../util/stats'); -const { JSON_MIME_TYPE } = require('../../util/constant'); -const { POLL_ACTIVITY } = require('./config'); - -const getPollStatus = async (event) => { - const accessToken = await getAccessToken(event.config); - const { munchkinId } = event.config; - - // To see the status of the import job polling is done - // DOC: https://developers.marketo.com/rest-api/bulk-import/bulk-lead-import/#polling_job_status - const requestOptions = { - headers: { - 'Content-Type': JSON_MIME_TYPE, - Authorization: `Bearer ${accessToken}`, - }, - }; - const pollUrl = `https://${munchkinId}.mktorest.com/bulk/v1/leads/batch/${event.importId}.json`; - const { processedResponse: pollStatus } = await handleHttpRequest( - 'get', - pollUrl, - requestOptions, - { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/leads/batch/importId.json', - requestMethod: 'GET', - module: 'router', - }, - ); - if (!isHttpStatusSuccess(pollStatus.status)) { - stats.counter(POLL_ACTIVITY, 1, { - status: pollStatus.status, - state: 'Retryable', - }); - throw new NetworkError( - `Could not poll status: due to error ${JSON.stringify(pollStatus.response)}`, - hydrateStatusForServer(pollStatus.status, 'During fetching poll status'), - ); - } - return handlePollResponse(pollStatus); -}; - -const responseHandler = async (event) => { - const pollResp = await getPollStatus(event); - // Server expects : - /** - * - * { - "Complete": true, - "statusCode": 200, - "hasFailed": true, - "InProgress": false, - "FailedJobURLs": "", // transformer URL - "HasWarning": false, - "WarningJobURLs": "", // transformer URL - } // Succesful Upload - { - "success": false, - "statusCode": 400, - "errorResponse": - } // Failed Upload - { - "success": false, - "Inprogress": true, - statusCode: 500, - } // Importing or Queue - - */ - if (pollResp) { - // As marketo lead import API or bulk API does not support record level error response we are considering - // file level errors only. - // ref: https://nation.marketo.com/t5/ideas/support-error-code-in-record-level-in-lead-bulk-api/idi-p/262191 - const { status, numOfRowsFailed, numOfRowsWithWarning, message } = pollResp.result[0]; - if (status === 'Complete') { - const response = { - Complete: true, - statusCode: 200, - InProgress: false, - hasFailed: numOfRowsFailed > 0, - FailedJobURLs: numOfRowsFailed > 0 ? '/getFailedJobs' : undefined, - HasWarning: numOfRowsWithWarning > 0, - WarningJobURLs: numOfRowsWithWarning > 0 ? '/getWarningJobs' : undefined, - }; - return removeUndefinedValues(response); - } - if (status === 'Importing' || status === 'Queued') { - return { - Complete: false, - statusCode: 500, - hasFailed: false, - InProgress: true, - HasWarning: false, - }; - } - if (status === 'Failed') { - return { - Complete: false, - statusCode: 500, - hasFailed: false, - InProgress: false, - HasWarning: false, - Error: message || 'Marketo Poll Status Failed', - }; - } - } - // when pollResp is null - return { - Complete: false, - statusCode: 500, - hasFailed: false, - InProgress: false, - HasWarning: false, - Error: 'No poll response received from Marketo', - }; -}; - -const processPolling = async (event) => { - const resp = await responseHandler(event); - return resp; -}; - -module.exports = { processPolling }; diff --git a/src/v0/destinations/marketo_bulk_upload/uploadFile/marketo_bulk_upload_example.csv b/src/v0/destinations/marketo_bulk_upload/uploadFile/marketo_bulk_upload_example.csv deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/v0/destinations/marketo_bulk_upload/util.js b/src/v0/destinations/marketo_bulk_upload/util.js deleted file mode 100644 index 033239b5e4c..00000000000 --- a/src/v0/destinations/marketo_bulk_upload/util.js +++ /dev/null @@ -1,436 +0,0 @@ -const { - AbortedError, - RetryableError, - NetworkError, - TransformationError, - isDefinedAndNotNull, -} = require('@rudderstack/integrations-lib'); -const { handleHttpRequest } = require('../../../adapters/network'); -const tags = require('../../util/tags'); -const { isHttpStatusSuccess, generateUUID } = require('../../util'); -const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); -const stats = require('../../../util/stats'); -const { - ABORTABLE_CODES, - THROTTLED_CODES, - POLL_ACTIVITY, - UPLOAD_FILE, - FETCH_ACCESS_TOKEN, - POLL_STATUS_ERR_MSG, - FILE_UPLOAD_ERR_MSG, - ACCESS_TOKEN_FETCH_ERR_MSG, - SCHEMA_DATA_TYPE_MAP, -} = require('./config'); -const logger = require('../../../logger'); - -const getMarketoFilePath = () => - `${__dirname}/uploadFile/${Date.now()}_marketo_bulk_upload_${generateUUID()}.csv`; - -// Server only aborts when status code is 400 -const hydrateStatusForServer = (statusCode, context) => { - const status = Number(statusCode); - if (Number.isNaN(status)) { - throw new TransformationError(`${context}: Couldn't parse status code ${statusCode}`); - } - if (status >= 400 && status <= 499) { - return 400; - } - return status; -}; - -/** - * Handles common error responses returned from API calls. - * Checks the error code and throws the appropriate error object based on the code. - * - * @param {object} resp - The response object containing the error information. - * @param {string} opErrorMessage - The error message to be used if the error code is not recognized. - * @param {string} opActivity - The activity name for tracking purposes. - * @throws {AbortedError} - If the error code is abortable. - * @throws {ThrottledError} - If the error code is within the range of throttled codes. - * @throws {RetryableError} - If the error code is neither abortable nor throttled. - * - * @example - * const resp = { - * response: { - * errors: [ - * { - * code: "1003", - * message: "Empty File" - * } - * ] - * } - * }; - * - * try { - * handleCommonErrorResponse(resp, "Error message", "Activity"); - * } catch (error) { - * console.log(error); - * } - */ -const handleCommonErrorResponse = (apiCallResult, opErrorMessage, opActivity) => { - // checking for invalid/expired token errors and evicting cache in that case - // rudderJobMetadata contains some destination info which is being used to evict the cache - if ( - apiCallResult.response?.errors && - apiCallResult.response?.errors?.length > 0 && - apiCallResult.response?.errors.some( - (errorObj) => errorObj.code === '601' || errorObj.code === '602', - ) - ) { - throw new RetryableError( - `[${opErrorMessage}]Error message: ${apiCallResult.response?.errors[0]?.message}`, - ); - } - if ( - apiCallResult.response?.errors?.length > 0 && - apiCallResult.response?.errors[0] && - ((apiCallResult.response?.errors[0]?.code >= 1000 && - apiCallResult.response?.errors[0]?.code <= 1077) || - ABORTABLE_CODES.includes(apiCallResult.response?.errors[0]?.code)) - ) { - // for empty file the code is 1003 and that should be retried - stats.increment(opActivity, { - status: 400, - state: 'Abortable', - }); - throw new AbortedError(apiCallResult.response?.errors[0]?.message || opErrorMessage, 400); - } else if (THROTTLED_CODES.includes(apiCallResult.response?.errors[0]?.code)) { - // for more than 10 concurrent uses the code is 615 and that should be retried - stats.increment(opActivity, { - status: 429, - state: 'Retryable', - }); - throw new RetryableError( - `[${opErrorMessage}]Error message: ${apiCallResult.response?.errors[0]?.message}`, - 500, - ); - } - // by default every thing will be retried - stats.increment(opActivity, { - status: 500, - state: 'Retryable', - }); - throw new RetryableError( - `[${opErrorMessage}]Error message: ${apiCallResult.response?.errors[0]?.message}`, - 500, - ); -}; - -const getAccessTokenURL = (config) => { - const { clientId, clientSecret, munchkinId } = config; - const url = `https://${munchkinId}.mktorest.com/identity/oauth/token?client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`; - return url; -}; - -// Fetch access token from client id and client secret -// DOC: https://developers.marketo.com/rest-api/authentication/ -const getAccessToken = async (config) => { - const url = getAccessTokenURL(config); - const { processedResponse: accessTokenResponse } = await handleHttpRequest('get', url, { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/identity/oauth/token', - requestMethod: 'GET', - module: 'router', - }); - - // sample response : {response: '[ENOTFOUND] :: DNS lookup failed', status: 400} - if (!isHttpStatusSuccess(accessTokenResponse.status)) { - throw new NetworkError( - `Could not retrieve authorisation token due to error ${JSON.stringify(accessTokenResponse)}`, - hydrateStatusForServer(accessTokenResponse.status, FETCH_ACCESS_TOKEN), - { - [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(accessTokenResponse.status), - }, - accessTokenResponse, - ); - } - if (accessTokenResponse.response?.success === false) { - handleCommonErrorResponse(accessTokenResponse, ACCESS_TOKEN_FETCH_ERR_MSG, FETCH_ACCESS_TOKEN); - } - - // when access token is present - if (accessTokenResponse.response.access_token) { - /* This scenario will handle the case when we get the following response - status: 200 - respnse: {"access_token":"","token_type":"bearer","expires_in":0,"scope":"dummy@scope.com"} - wherein "expires_in":0 denotes that we should refresh the accessToken but its not expired yet. - */ - if (accessTokenResponse.response?.expires_in === 0) { - throw new RetryableError( - `Request Failed for marketo_bulk_upload, Access Token Expired (Retryable).`, - 500, - ); - } - return accessTokenResponse.response.access_token; - } - throw new RetryableError( - `Could not retrieve authorisation token due to error ${JSON.stringify(accessTokenResponse)}`, - 500, - ); -}; - -/** - * Handles the response of a polling operation. - * Checks for any errors in the response and calls the `handleCommonErrorResponse` function to handle them. - * If the response is successful, increments the stats and returns the response. - * Otherwise, returns null. - * - * @param {object} pollStatus - The response object from the polling operation. - * @returns {object|null} - The response object if the polling operation was successful, otherwise null. - */ -const handlePollResponse = (pollStatus) => { - // DOC: https://developers.marketo.com/rest-api/error-codes/ - if (pollStatus.response.errors) { - /* Sample error response for poll is: - - { - "requestId": "e42b#14272d07d78", - "success": false, - "errors": [ - { - "code": "601", - "message": "Unauthorized" - } - ] - } - */ - handleCommonErrorResponse(pollStatus, POLL_STATUS_ERR_MSG, POLL_ACTIVITY); - } - - /* - Sample Successful Poll response structure: - { - "requestId":"8136#146daebc2ed", - "success":true, - "result":[ - { - "batchId":, - "status":"Complete", - "numOfLeadsProcessed":2, - "numOfRowsFailed":1, - "numOfRowsWithWarning":0, - "message":"Import completed with errors, 2 records imported (2 members), 1 failed" - } - ] - } - */ - if (pollStatus.response?.success) { - stats.counter(POLL_ACTIVITY, 1, { - status: 200, - state: 'Success', - }); - - if (pollStatus.response?.result?.length > 0) { - return pollStatus.response; - } - } - - return null; -}; - -const handleFetchJobStatusResponse = (resp, type) => { - const marketoResponse = resp.response; - const marketoReposnseStatus = resp.status; - - if (!isHttpStatusSuccess(marketoReposnseStatus)) { - logger.info('[Network Error]:Failed during fetching job status', { marketoResponse, type }); - throw new NetworkError( - `Unable to fetch job status: due to error ${JSON.stringify(marketoResponse)}`, - hydrateStatusForServer(marketoReposnseStatus, 'During fetching job status'), - ); - } - - if (marketoResponse?.success === false) { - logger.info('[Application Error]Failed during fetching job status', { marketoResponse, type }); - throw new RetryableError( - `Failure during fetching job status due to error : ${marketoResponse}`, - 500, - resp, - ); - } - - /* - successful response : - { - response: 'city, email,Import Failure ReasonChennai,s…a,Value for lookup field 'email' not found', - status: 200 - } - - */ - - return marketoResponse; -}; - -/** - * Handles the response received after a file upload request. - * Checks for errors in the response and throws appropriate error objects based on the error codes. - * If the response indicates a successful upload, extracts the importId and returns it along with other job details. - * - * @param {object} resp - The response object received after a file upload request. - * @param {array} successfulJobs - An array to store details of successful jobs. - * @param {array} unsuccessfulJobs - An array to store details of unsuccessful jobs. - * @param {number} requestTime - The time taken for the request in milliseconds. - * @returns {object} - An object containing the importId, successfulJobs, and unsuccessfulJobs. - */ -const handleFileUploadResponse = (resp, successfulJobs, unsuccessfulJobs, requestTime) => { - /* - For unsuccessful response - { - "requestId": "e42b#14272d07d78", - "success": false, - "errors": [ - { - "code": "1003", - "message": "Empty File" - } - ] - } - */ - if (resp.response?.errors) { - if (resp.response?.errors[0]?.code === '1003') { - stats.increment(UPLOAD_FILE, { - status: 500, - state: 'Retryable', - }); - throw new RetryableError( - `[${FILE_UPLOAD_ERR_MSG}]:Error Message ${resp.response.errors[0]?.message}`, - 500, - ); - } else { - handleCommonErrorResponse(resp, FILE_UPLOAD_ERR_MSG, UPLOAD_FILE); - } - } - - /** - * SuccessFul Upload Response : - { - "requestId": "d01f#15d672f8560", - "result": [ - { - "batchId": 3404, - "importId": "3404", - "status": "Queued" - } - ], - "success": true - } - */ - if ( - resp.response?.success && - resp.response?.result?.length > 0 && - resp.response?.result[0]?.importId - ) { - const { importId } = resp.response.result[0]; - stats.histogram('marketo_bulk_upload_upload_file_time', requestTime); - - stats.increment(UPLOAD_FILE, { - status: 200, - state: 'Success', - }); - return { importId, successfulJobs, unsuccessfulJobs }; - } - // if neither successful, nor the error message is appropriate sending importId as default null - return { importId: null, successfulJobs, unsuccessfulJobs }; -}; - -/** - * Retrieves the field schema mapping for a given access token and munchkin ID from the Marketo API. - * - * @param {string} accessToken - The access token used to authenticate the API request. - * @param {string} munchkinId - The munchkin ID of the Marketo instance. - * @returns {object} - The field schema mapping retrieved from the Marketo API. - */ -const getFieldSchemaMap = async (accessToken, munchkinId) => { - let fieldArr = []; - const fieldMap = {}; // map to store field name and data type - // ref: https://developers.marketo.com/rest-api/endpoint-reference/endpoint-index/#:~:text=Describe%20Lead2,leads/describe2.json - const { processedResponse: fieldSchemaMapping } = await handleHttpRequest( - 'get', - `https://${munchkinId}.mktorest.com/rest/v1/leads/describe2.json`, - { - params: { - access_token: accessToken, - }, - }, - { - destType: 'marketo_bulk_upload', - feature: 'transformation', - endpointPath: '/leads/describe2.json', - requestMethod: 'GET', - module: 'router', - }, - ); - if (fieldSchemaMapping.response.errors) { - handleCommonErrorResponse( - fieldSchemaMapping, - 'Error while fetching Marketo Field Schema', - 'FieldSchemaMapping', - ); - } - if ( - fieldSchemaMapping.response?.success && - fieldSchemaMapping.response?.result.length > 0 && - fieldSchemaMapping.response?.result[0] - ) { - fieldArr = - fieldSchemaMapping.response.result && Array.isArray(fieldSchemaMapping.response.result) - ? fieldSchemaMapping.response.result[0]?.fields - : []; - - fieldArr.forEach((field) => { - fieldMap[field?.name] = field?.dataType; - }); - } else { - throw new RetryableError( - `Failed to fetch Marketo Field Schema due to error ${JSON.stringify(fieldSchemaMapping)}`, - 500, - fieldSchemaMapping, - ); - } - return fieldMap; -}; - -/** - * Compares the data types of the fields in an event message with the expected data types defined in the field schema mapping. - * Identifies any mismatched fields and returns them as a map of job IDs and the corresponding invalid fields. - * - * @param {object} event - An object containing an `input` array of events. Each event has a `message` object with field-value pairs and a `metadata` object with a `job_id` property. - * @param {object} fieldSchemaMapping - An object containing the field schema mapping, which includes the expected data types for each field. - * @returns {object} - An object containing the job IDs as keys and the corresponding invalid fields as values. - */ -const checkEventStatusViaSchemaMatching = (event, fieldMap) => { - const mismatchedFields = {}; - const events = event.input; - events.forEach((ev) => { - const { message, metadata } = ev; - // eslint-disable-next-line @typescript-eslint/naming-convention - const { job_id } = metadata; - - Object.entries(message).forEach(([paramName, paramValue]) => { - const expectedDataType = SCHEMA_DATA_TYPE_MAP[fieldMap[paramName]]; - const actualDataType = typeof paramValue; - - if ( - isDefinedAndNotNull(paramValue) && - !mismatchedFields[job_id] && - actualDataType !== expectedDataType - ) { - mismatchedFields[job_id] = `invalid ${paramName}`; - } - }); - }); - return mismatchedFields; -}; - -module.exports = { - checkEventStatusViaSchemaMatching, - handlePollResponse, - handleFetchJobStatusResponse, - handleFileUploadResponse, - handleCommonErrorResponse, - hydrateStatusForServer, - getAccessToken, - getMarketoFilePath, - getFieldSchemaMap, -}; diff --git a/test/__tests__/data/marketo_bulk_upload_fileUpload_input.json b/test/__tests__/data/marketo_bulk_upload_fileUpload_input.json deleted file mode 100644 index 737cd36ec3b..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_fileUpload_input.json +++ /dev/null @@ -1,272 +0,0 @@ -[ - { - "request": { - "body": { - "config": { - "munchkinId": "munchkinId", - "clientId": "b", - "clientSecret": "clientSecret", - "columnFieldsMapping": [ - { - "to": "email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "munchkinId", - "clientId": "b", - "clientSecret": "clientSecret", - "columnFieldsMapping": [ - { - "to": "email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "munchkinId", - "clientId": "wrongClientId", - "clientSecret": "clientSecret", - "columnFieldsMapping": [ - { - "to": "email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "a", - "clientId": "b", - "clientSecret": "forThrottle", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "munchkinId", - "clientId": "b", - "clientSecret": "clientSecret", - "columnFieldsMapping": [ - { - "to": "email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "testMunchkin1", - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "to": "email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "testMunchkin2", - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "testMunchkin3", - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - }, - { - "request": { - "body": { - "config": { - "munchkinId": "testMunchkin4", - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "input": [ - { - "message": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "metadata": { - "job_id": 17 - } - } - ], - "destType": "MARKETO_BULK_UPLOAD" - } - } - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_fileUpload_output.json b/test/__tests__/data/marketo_bulk_upload_fileUpload_output.json deleted file mode 100644 index 0ea94284ae8..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_fileUpload_output.json +++ /dev/null @@ -1,63 +0,0 @@ -[ - { - "statusCode": 200, - "importId": "2977", - "metadata": { - "successfulJobs": ["17"], - "unsuccessfulJobs": [], - "csvHeader": "email" - } - }, - { - "statusCode": 200, - "importId": "2977", - "metadata": { - "successfulJobs": ["17"], - "unsuccessfulJobs": [], - "csvHeader": "email" - } - }, - { - "statusCode": 200, - "importId": "2977", - "metadata": { - "successfulJobs": ["17"], - "unsuccessfulJobs": [], - "csvHeader": "email" - } - }, - { - "statusCode": 400, - "error": "The field Email is not present in Marketo Field Schema. Aborting", - "metadata": null - }, - { - "statusCode": 200, - "importId": "2977", - "metadata": { - "successfulJobs": ["17"], - "unsuccessfulJobs": [], - "csvHeader": "email" - } - }, - { - "statusCode": 400, - "error": "[Could not upload file]Error message: undefined", - "metadata": null - }, - { - "statusCode": 400, - "error": "[Could not upload file]Error message: There are 10 imports currently being processed. Please try again later", - "metadata": null - }, - { - "statusCode": 400, - "error": "[Could not upload file]Error message: Empty file", - "metadata": null - }, - { - "statusCode": 400, - "error": "[Could not upload file]Error message: Any other error", - "metadata": null - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_input.json b/test/__tests__/data/marketo_bulk_upload_input.json deleted file mode 100644 index ce48c8e7fe2..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_input.json +++ /dev/null @@ -1,270 +0,0 @@ -[ - { - "message": { - "type": "identify", - "traits": { - "name": "Carlo Lombard", - "plan": "Quarterly Team+ Plan for Enuffsaid Media", - "email": "carlo@enuffsaid.media" - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "name" - }, - { - "to": "email__c", - "from": "email" - }, - { - "to": "plan__c", - "from": "plan" - } - ] - } - } - }, - { - "message": { - "traits": { - "name": "Carlo Lombard", - "plan": "Quarterly Team+ Plan for Enuffsaid Media", - "email": "carlo@enuffsaid.media" - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "name" - }, - { - "to": "email__c", - "from": "email" - }, - { - "to": "plan__c", - "from": "plan" - } - ] - } - } - }, - { - "message": { - "type": "track", - "traits": { - "name": "Carlo Lombard", - "plan": "Quarterly Team+ Plan for Enuffsaid Media", - "email": "carlo@enuffsaid.media" - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "name" - }, - { - "to": "email__c", - "from": "email" - }, - { - "to": "plan__c", - "from": "plan" - } - ] - } - } - }, - { - "message": { - "type": "identify", - "traits": { - "name": "Carlo Lombard", - "plan": "Quarterly Team+ Plan for Enuffsaid Media", - "email": "carlo@enuffsaid.media" - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "1" - }, - { - "to": "email__c", - "from": "email1" - }, - { - "to": "plan__c", - "from": "plan1" - } - ] - } - } - }, - { - "message": { - "type": "identify", - "traits": { - "name": "Carlo Lombard", - "plan": "Quarterly Team+ Plan for Enuffsaid Media", - "email": "carlo@enuffsaid.media" - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "name" - }, - { - "to": "email__c", - "from": "email1" - }, - { - "to": "plan__c", - "from": "plan1" - } - ] - } - } - }, - { - "message": { - "type": "identify", - "traits": { - "name": "Carlo Lombard", - "plan": 1 - }, - "userId": 476335, - "context": { - "ip": "14.0.2.238", - "page": { - "url": "enuffsaid.proposify.com", - "path": "/settings", - "method": "POST", - "referrer": "https://enuffsaid.proposify.com/login" - }, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" - }, - "rudderId": "786dfec9-jfh", - "messageId": "5d9bc6e2-ekjh" - }, - "destination": { - "ID": "1mMy5cqbtfuaKZv1IhVQKnBdVwe", - "Config": { - "munchkinId": "XXXX", - "clientId": "YYYY", - "clientSecret": "ZZZZ", - "columnFieldsMapping": [ - { - "to": "name__c", - "from": "name" - }, - { - "to": "email__c", - "from": "email" - }, - { - "to": "plan__c", - "from": "plan" - } - ] - } - } - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_jobStatus_input.json b/test/__tests__/data/marketo_bulk_upload_jobStatus_input.json deleted file mode 100644 index b36363e0db2..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_jobStatus_input.json +++ /dev/null @@ -1,102 +0,0 @@ -[ - { - "request": { - "body": { - "destType": "MARKETO_BULK_UPLOAD", - "importId": 12345, - "input": [ - { - "message": { - "firstName": "aa", - "email": "bb" - }, - "metadata": { - "job_id": 2 - } - }, - { - "message": { - "firstName": "aa", - "email": "bb", - "phone": "99" - }, - "metadata": { - "job_id": 4 - } - }, - { - "message": { - "firstName": "aa", - "email": "bb" - }, - "metadata": { - "job_id": 3 - } - } - ], - "config": { - "clientId": "b", - "clientSecret": "c", - "munchkinId": "a", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "metadata": {} - } - } - }, - { - "request": { - "body": { - "destType": "MARKETO_BULK_UPLOAD", - "importId": 12345, - "input": [ - { - "message": { - "firstName": "aa", - "email": "bb" - }, - "metadata": { - "job_id": 2 - } - }, - { - "message": { - "firstName": "aa", - "email": "bb", - "phone": "99" - }, - "metadata": { - "job_id": 4 - } - }, - { - "message": { - "firstName": "aa", - "email": "bb" - }, - "metadata": { - "job_id": 3 - } - } - ], - "config": { - "clientId": "b", - "clientSecret": "c", - "munchkinId": "testMunchkin3", - "columnFieldsMapping": [ - { - "to": "Email", - "from": "email" - } - ] - }, - "metadata": {} - } - } - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_jobStatus_output.json b/test/__tests__/data/marketo_bulk_upload_jobStatus_output.json deleted file mode 100644 index 60628f6b3f5..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_jobStatus_output.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "type": "warn", - "data": [ - { - "statusCode": 400, - "error": "No csvHeader in metadata" - }, - { - "statusCode": 400, - "error": "Unable to fetch job status: due to error \"\"" - } - ] - }, - { - "type": "fail", - "data": [ - { - "statusCode": 400, - "error": "No csvHeader in metadata" - }, - { - "statusCode": 400, - "error": "Unable to fetch job status: due to error \"\"" - } - ] - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_output.json b/test/__tests__/data/marketo_bulk_upload_output.json deleted file mode 100644 index 9911a7e8312..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_output.json +++ /dev/null @@ -1,89 +0,0 @@ -[ - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "/fileUpload", - "headers": {}, - "params": {}, - "body": { - "JSON": { - "name__c": "Carlo Lombard", - "email__c": "carlo@enuffsaid.media", - "plan__c": "Quarterly Team+ Plan for Enuffsaid Media" - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - { - "statusCode": 400, - "error": "Event type is required", - "statTags": { - "destination": "marketo_bulk_upload", - "stage": "transform", - "scope": "exception" - } - }, - { - "statusCode": 400, - "error": "Event type track is not supported", - "statTags": { - "destination": "marketo_bulk_upload", - "stage": "transform", - "scope": "exception" - } - }, - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "/fileUpload", - "headers": {}, - "params": {}, - "body": { - "JSON": {}, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "/fileUpload", - "headers": {}, - "params": {}, - "body": { - "JSON": { - "name__c": "Carlo Lombard" - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "/fileUpload", - "headers": {}, - "params": {}, - "body": { - "JSON": { - "name__c": "Carlo Lombard", - "plan__c": 1 - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_poll_input.json b/test/__tests__/data/marketo_bulk_upload_poll_input.json deleted file mode 100644 index f5457bd79c2..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_poll_input.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - { - "request": { - "body": { - "destType": "MARKETO_BULK_UPLOAD", - "importId": 1234, - "config": { - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "from": "email", - "to": "Email" - } - ], - "munchkinId": "a" - } - } - } - }, - { - "request": { - "body": { - "destType": "MARKETO_BULK_UPLOAD", - "importId": 1234, - "config": { - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "from": "email", - "to": "Email" - } - ], - "munchkinId": "testMunchkin4" - } - } - } - }, - { - "request": { - "body": { - "destType": "MARKETO_BULK_UPLOAD", - "importId": 1234, - "config": { - "clientId": "b", - "clientSecret": "c", - "columnFieldsMapping": [ - { - "from": "email", - "to": "Email" - } - ], - "munchkinId": "testMunchkin500" - } - } - } - } -] diff --git a/test/__tests__/data/marketo_bulk_upload_poll_output.json b/test/__tests__/data/marketo_bulk_upload_poll_output.json deleted file mode 100644 index 92e312072ea..00000000000 --- a/test/__tests__/data/marketo_bulk_upload_poll_output.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "Complete": true, - "statusCode": 200, - "hasFailed": false, - "InProgress": false, - "HasWarning": false - }, - { - "statusCode": 400, - "error": "Any 400 error" - }, - { - "statusCode": 400, - "error": "[Could not poll status]Error message: Any 500 error" - } -] diff --git a/test/__tests__/marketo_bulk_upload.test.js b/test/__tests__/marketo_bulk_upload.test.js deleted file mode 100644 index 6cf4d559b9d..00000000000 --- a/test/__tests__/marketo_bulk_upload.test.js +++ /dev/null @@ -1,127 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const vRouter = require("../../src/legacy/router"); - -const version = "v0"; -const integration = "marketo_bulk_upload"; -const transformer = require(`../../src/${version}/destinations/${integration}/transform`); - -jest.mock("axios"); -let reqTransformBody; -let respTransformBody; -let respFileUploadBody; -let reqFileUploadBody; -let reqPollBody; -let respPollBody; -let reqJobStatusBody; -let respJobStatusBody; - -try { - reqTransformBody = JSON.parse( - fs.readFileSync(path.resolve(__dirname, `./data/${integration}_input.json`)) - ); - respTransformBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_output.json`) - ) - ); - reqFileUploadBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_fileUpload_input.json`) - ) - ); - respFileUploadBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_fileUpload_output.json`) - ) - ); - reqPollBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_poll_input.json`) - ) - ); - respPollBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_poll_output.json`) - ) - ); - reqJobStatusBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_jobStatus_input.json`) - ) - ); - respJobStatusBody = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, `./data/${integration}_jobStatus_output.json`) - ) - ); -} catch (error) { - throw new Error("Could not read files." + error); -} - -describe(`${integration} Tests`, () => { - describe("Transformer.js", () => { - reqTransformBody.forEach(async (input, index) => { - it(`Payload - ${index}`, async () => { - try { - const output = await transformer.process(input); - expect(output).toEqual(respTransformBody[index]); - } catch (error) { - expect(error.message).toEqual(respTransformBody[index].error); - } - }); - }); - }); - - describe("fileUpload.js", () => { - reqFileUploadBody.forEach(async (input, index) => { - it(`Payload - ${index}`, async () => { - try { - const output = await vRouter.fileUpload(input); - expect(output).toEqual(respFileUploadBody[index]); - } catch (error) { - expect(error.message).toEqual(respFileUploadBody[index].error); - } - }); - }); - }); - - describe("poll.js", () => { - reqPollBody.forEach(async (input, index) => { - it(`Payload - ${index}`, async () => { - try { - const output = await vRouter.pollStatus(input); - expect(output).toEqual(respPollBody[index]); - } catch (error) { - expect(error.message).toEqual(respPollBody[index].error); - } - }); - }); - }); - - describe("fetchJobStatus.js for warn", () => { - reqJobStatusBody.forEach(async (input, index) => { - it(`Payload - ${index}`, async () => { - try { - const output = await vRouter.getJobStatus(input, "warn"); - expect(output).toEqual(respJobStatusBody[0].data[index]); - } catch (error) { - expect(error.message).toEqual(respJobStatusBody[0].data[index].error); - } - }); - }); - }); - - describe("fetchJobStatus.js for fail", () => { - reqJobStatusBody.forEach(async (input, index) => { - it(`Payload - ${index}`, async () => { - try { - const output = await vRouter.getJobStatus(input, "fail"); - expect(output).toEqual(respJobStatusBody[1].data[index]); - } catch (error) { - expect(error.message).toEqual(respJobStatusBody[1].data[index].error); - } - }); - }); - }); -}); From 3d7db7366e30df31c37cc473e344da82b49ed885 Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:59:49 +0530 Subject: [PATCH 110/147] feat: onboarding intercom v2 retl support (#3843) * feat: onboarding intercom v2 retl support * fix: fixing export error * fix: searching contact for insert record * fix: added more tests * fix: addressing comment * fix: minor change --- src/v0/destinations/intercom_v2/config.js | 7 + src/v0/destinations/intercom_v2/transform.js | 51 ++++- src/v0/destinations/intercom_v2/utils.js | 25 ++- .../destinations/intercom_v2/network.ts | 102 +++++++++ .../destinations/intercom_v2/router/data.ts | 199 ++++++++++++++++++ .../destinations/intercom_v2/router/rETL.ts | 182 ++++++++++++++++ 6 files changed, 558 insertions(+), 8 deletions(-) create mode 100644 test/integrations/destinations/intercom_v2/router/rETL.ts diff --git a/src/v0/destinations/intercom_v2/config.js b/src/v0/destinations/intercom_v2/config.js index c7cb43b093c..5ff5566d2d9 100644 --- a/src/v0/destinations/intercom_v2/config.js +++ b/src/v0/destinations/intercom_v2/config.js @@ -6,6 +6,12 @@ const ApiVersions = { v2: '2.10', }; +const RecordAction = { + INSERT: 'insert', + UPDATE: 'update', + DELETE: 'delete', +}; + const ConfigCategory = { IDENTIFY: { name: 'IntercomIdentifyConfig', @@ -25,4 +31,5 @@ module.exports = { ConfigCategory, MappingConfig, ApiVersions, + RecordAction, }; diff --git a/src/v0/destinations/intercom_v2/transform.js b/src/v0/destinations/intercom_v2/transform.js index 8d97e20bde7..3f9457410f9 100644 --- a/src/v0/destinations/intercom_v2/transform.js +++ b/src/v0/destinations/intercom_v2/transform.js @@ -1,4 +1,4 @@ -const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { handleRtTfSingleEventError, getSuccessRespEvents, @@ -17,13 +17,14 @@ const { addOrUpdateTagsToCompany, getStatusCode, getBaseEndpoint, + getRecordAction, } = require('./utils'); const { getName, filterCustomAttributes, addMetadataToPayload, } = require('../../../cdk/v2/destinations/intercom/utils'); -const { MappingConfig, ConfigCategory } = require('./config'); +const { MappingConfig, ConfigCategory, RecordAction } = require('./config'); const transformIdentifyPayload = (event) => { const { message, destination } = event; @@ -38,7 +39,7 @@ const transformIdentifyPayload = (event) => { } payload.name = getName(message); payload.custom_attributes = message.traits || message.context.traits || {}; - payload.custom_attributes = filterCustomAttributes(payload, 'user', destination); + payload.custom_attributes = filterCustomAttributes(payload, 'user', destination, message); return payload; }; @@ -66,7 +67,7 @@ const transformGroupPayload = (event) => { const category = ConfigCategory.GROUP; const payload = constructPayload(message, MappingConfig[category.name]); payload.custom_attributes = message.traits || message.context.traits || {}; - payload.custom_attributes = filterCustomAttributes(payload, 'company', destination); + payload.custom_attributes = filterCustomAttributes(payload, 'company', destination, message); return payload; }; @@ -131,6 +132,45 @@ const constructGroupResponse = async (event) => { return getResponse(method, endpoint, headers, finalPayload); }; +const constructRecordResponse = async (event) => { + const { message, destination, metadata } = event; + const { identifiers, fields } = message; + + let method = 'POST'; + let endpoint = `${getBaseEndpoint(destination)}/contacts`; + let payload = {}; + + const action = getRecordAction(message); + const contactId = await searchContact(event); + + if ((action === RecordAction.UPDATE || action === RecordAction.DELETE) && !contactId) { + throw new ConfigurationError('Contact is not present. Aborting.'); + } + + switch (action) { + case RecordAction.INSERT: + payload = { ...identifiers, ...fields }; + if (contactId) { + endpoint += `/${contactId}`; + payload = { ...fields }; + method = 'PUT'; + } + break; + case RecordAction.UPDATE: + endpoint += `/${contactId}`; + payload = { ...fields }; + method = 'PUT'; + break; + case RecordAction.DELETE: + endpoint += `/${contactId}`; + method = 'DELETE'; + break; + default: + throw new InstrumentationError(`action ${action} is not supported.`); + } + return getResponse(method, endpoint, getHeaders(metadata), payload); +}; + const processEvent = async (event) => { const { message } = event; const messageType = getEventType(message); @@ -145,6 +185,9 @@ const processEvent = async (event) => { case EventType.GROUP: response = await constructGroupResponse(event); break; + case EventType.RECORD: + response = constructRecordResponse(event); + break; default: throw new InstrumentationError(`message type ${messageType} is not supported.`); } diff --git a/src/v0/destinations/intercom_v2/utils.js b/src/v0/destinations/intercom_v2/utils.js index 69ea1385d93..df44b92e243 100644 --- a/src/v0/destinations/intercom_v2/utils.js +++ b/src/v0/destinations/intercom_v2/utils.js @@ -28,6 +28,8 @@ const { getAccessToken } = require('../../util'); const { ApiVersions, destType } = require('./config'); const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); +const getRecordAction = (message) => message?.action?.toLowerCase(); + /** * method to handle error during api call * ref docs: https://developers.intercom.com/docs/references/rest-api/errors/http-responses/ @@ -99,11 +101,25 @@ const getResponse = (method, endpoint, headers, payload) => { const searchContact = async (event) => { const { message, destination, metadata } = event; - const lookupField = getLookUpField(message); - let lookupFieldValue = getFieldValueFromMessage(message, lookupField); - if (!lookupFieldValue) { - lookupFieldValue = message?.context?.traits?.[lookupField]; + + const extractLookupFieldAndValue = () => { + const messageType = getEventType(message); + if (messageType === EventType.RECORD) { + const { identifiers } = message; + return Object.entries(identifiers || {})[0] || [null, null]; + } + const lookupField = getLookUpField(message); + const lookupFieldValue = + getFieldValueFromMessage(message, lookupField) || message?.context?.traits?.[lookupField]; + return [lookupField, lookupFieldValue]; + }; + + const [lookupField, lookupFieldValue] = extractLookupFieldAndValue(); + + if (!lookupField || !lookupFieldValue) { + throw new InstrumentationError('Missing lookup field or lookup field value for searchContact'); } + const data = JSON.stringify({ query: { operator: 'AND', @@ -329,4 +345,5 @@ module.exports = { attachContactToCompany, addOrUpdateTagsToCompany, getBaseEndpoint, + getRecordAction, }; diff --git a/test/integrations/destinations/intercom_v2/network.ts b/test/integrations/destinations/intercom_v2/network.ts index 26ff3c38ee2..e4cae04d078 100644 --- a/test/integrations/destinations/intercom_v2/network.ts +++ b/test/integrations/destinations/intercom_v2/network.ts @@ -746,6 +746,108 @@ const deliveryCallsData = [ }, }, }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'test-rETL-available@gmail.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'retl-available-contact-id', + workspace_id: 'rudderWorkspace', + external_id: 'detach-company-user-id', + role: 'user', + email: 'test-rETL-available@gmail.com', + }, + ], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'email', operator: '=', value: 'test-rETL-unavailable@gmail.com' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [], + }, + }, + }, + { + httpReq: { + method: 'post', + url: 'https://api.au.intercom.io/contacts/search', + data: { + query: { + operator: 'AND', + value: [{ field: 'external_id', operator: '=', value: 'known-user-id-1' }], + }, + }, + headers, + }, + httpRes: { + status: 200, + statusText: 'ok', + data: { + type: 'list', + total_count: 0, + pages: { + type: 'pages', + page: 1, + per_page: 50, + total_pages: 0, + }, + data: [ + { + type: 'contact', + id: 'contact-id-by-intercom-known-user-id-1', + workspace_id: 'rudderWorkspace', + external_id: 'user-id-1', + role: 'user', + email: 'test@rudderlabs.com', + }, + ], + }, + }, + }, ]; export const networkCallsData = [...deliveryCallsData]; diff --git a/test/integrations/destinations/intercom_v2/router/data.ts b/test/integrations/destinations/intercom_v2/router/data.ts index 76569140590..75f5ba6ae7b 100644 --- a/test/integrations/destinations/intercom_v2/router/data.ts +++ b/test/integrations/destinations/intercom_v2/router/data.ts @@ -17,6 +17,7 @@ import { userTraits, } from '../common'; import { RouterTestData } from '../../../testTypes'; +import { rETLRecordV2RouterRequest } from './rETL'; const routerRequest1: RouterTransformationRequest = { input: [ @@ -222,6 +223,26 @@ const routerRequest3: RouterTransformationRequest = { }, metadata: generateMetadata(3), }, + { + destination: destinationApiServerAU, + message: { + userId: 'known-user-id-1', + channel, + context: { + traits: { ...userTraits, external_id: 'known-user-id-1' }, + }, + type: 'identify', + integrations: { + All: true, + Intercom: { + lookup: 'external_id', + }, + }, + originalTimestamp, + timestamp, + }, + metadata: generateMetadata(4), + }, ], destType: 'intercom_v2', }; @@ -735,6 +756,38 @@ export const data: RouterTestData[] = [ metadata: [generateMetadata(3)], statusCode: 400, }, + { + batched: false, + batchedRequest: { + body: { + JSON: { + email: 'test@rudderlabs.com', + external_id: 'known-user-id-1', + name: 'John Snow', + owner_id: 13, + phone: '+91 9999999999', + custom_attributes: { + address: 'california usa', + age: 23, + }, + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: + 'https://api.au.intercom.io/contacts/contact-id-by-intercom-known-user-id-1', + files: {}, + headers, + method: 'PUT', + params: {}, + type: 'REST', + version: '1', + }, + destination: destinationApiServerAU, + metadata: [generateMetadata(4)], + statusCode: 200, + }, ], }, }, @@ -880,4 +933,150 @@ export const data: RouterTestData[] = [ }, }, }, + { + id: 'INTERCOM-V2-router-test-6', + scenario: 'Framework', + successCriteria: 'Some events should be transformed successfully and some should fail for rETL', + name: 'intercom_v2', + description: 'INTERCOM V2 rETL tests', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: rETLRecordV2RouterRequest, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: false, + batchedRequest: { + body: { + JSON: { + email: 'test-rETL-unavailable@gmail.com', + external_id: 'rEtl_external_id', + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/contacts', + files: {}, + headers, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(1)], + statusCode: 200, + }, + { + batched: false, + batchedRequest: { + body: { + JSON: { + external_id: 'rEtl_external_id', + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/contacts/retl-available-contact-id', + files: {}, + headers, + method: 'PUT', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(2)], + statusCode: 200, + }, + { + batched: false, + batchedRequest: { + body: { + JSON: {}, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/contacts/retl-available-contact-id', + files: {}, + headers, + method: 'DELETE', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(3)], + statusCode: 200, + }, + { + batched: false, + error: 'Contact is not present. Aborting.', + statTags: { + ...RouterInstrumentationErrorStatTags, + errorType: 'configuration', + }, + destination, + metadata: [generateMetadata(4)], + statusCode: 400, + }, + { + batched: false, + batchedRequest: { + body: { + JSON: { + external_id: 'rEtl_external_id', + }, + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + }, + endpoint: 'https://api.intercom.io/contacts/retl-available-contact-id', + files: {}, + headers, + method: 'PUT', + params: {}, + type: 'REST', + version: '1', + }, + destination: destination, + metadata: [generateMetadata(5)], + statusCode: 200, + }, + { + batched: false, + error: 'action dummyaction is not supported.', + statTags: { + ...RouterInstrumentationErrorStatTags, + }, + destination, + metadata: [generateMetadata(6)], + statusCode: 400, + }, + { + batched: false, + error: 'Missing lookup field or lookup field value for searchContact', + statTags: { + ...RouterInstrumentationErrorStatTags, + }, + destination, + metadata: [generateMetadata(7)], + statusCode: 400, + }, + ], + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/intercom_v2/router/rETL.ts b/test/integrations/destinations/intercom_v2/router/rETL.ts new file mode 100644 index 00000000000..0a36b8cfa61 --- /dev/null +++ b/test/integrations/destinations/intercom_v2/router/rETL.ts @@ -0,0 +1,182 @@ +import { RouterTransformationRequest } from '../../../../../src/types'; +import { destination } from '../common'; +import { generateMetadata } from '../../../testUtils'; + +export const rETLRecordV2RouterRequest: RouterTransformationRequest = { + input: [ + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '1', + rudderId: '1', + identifiers: { + email: 'test-rETL-unavailable@gmail.com', + }, + }, + metadata: generateMetadata(1), + }, + { + destination, + message: { + type: 'record', + action: 'update', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '2', + rudderId: '2', + identifiers: { + email: 'test-rETL-available@gmail.com', + }, + }, + metadata: generateMetadata(2), + }, + { + destination, + message: { + type: 'record', + action: 'delete', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '3', + rudderId: '3', + identifiers: { + email: 'test-rETL-available@gmail.com', + }, + }, + metadata: generateMetadata(3), + }, + { + destination, + message: { + type: 'record', + action: 'update', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '1', + rudderId: '1', + identifiers: { + email: 'test-rETL-unavailable@gmail.com', + }, + }, + metadata: generateMetadata(4), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '1', + rudderId: '1', + identifiers: { + email: 'test-rETL-available@gmail.com', + }, + }, + metadata: generateMetadata(5), + }, + { + destination, + message: { + type: 'record', + action: 'dummyAction', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '1', + rudderId: '1', + identifiers: { + email: 'test-rETL-available@gmail.com', + }, + }, + metadata: generateMetadata(6), + }, + { + destination, + message: { + type: 'record', + action: 'insert', + fields: { + external_id: 'rEtl_external_id', + }, + channel: 'sources', + context: { + sources: { + job_id: 'job-id', + version: 'local', + job_run_id: 'job_run_id', + task_run_id: 'job_run_id', + }, + }, + recordId: '1', + rudderId: '1', + identifiers: {}, + }, + metadata: generateMetadata(7), + }, + ], + destType: 'intercom_v2', +}; From becb4fa54e9093ed69779f54c36864cb9d28d321 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Fri, 15 Nov 2024 22:44:16 +0530 Subject: [PATCH 111/147] feat: iterable EUDC deleteUsers (#3881) --- src/v0/destinations/iterable/deleteUsers.js | 8 +++-- .../destinations/iterable/deleteUsers/data.ts | 36 +++++++++++++++++++ .../destinations/iterable/network.ts | 17 +++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/v0/destinations/iterable/deleteUsers.js b/src/v0/destinations/iterable/deleteUsers.js index 015a9de9a05..79c4c0affd0 100644 --- a/src/v0/destinations/iterable/deleteUsers.js +++ b/src/v0/destinations/iterable/deleteUsers.js @@ -6,13 +6,14 @@ const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); const { executeCommonValidations } = require('../../util/regulation-api'); const tags = require('../../util/tags'); const { JSON_MIME_TYPE } = require('../../util/constant'); +const { constructEndpoint } = require('./config'); -// Ref-> https://developers.intercom.com/intercom-api-reference/v1.3/reference/permanently-delete-a-user +// Ref-> https://support.iterable.com/hc/en-us/articles/360032290032-Deleting-Users const userDeletionHandler = async (userAttributes, config) => { if (!config) { throw new ConfigurationError('Config for deletion not present'); } - const { apiKey } = config; + const { apiKey, dataCenter } = config; if (!apiKey) { throw new ConfigurationError('api key for deletion not present'); } @@ -26,7 +27,8 @@ const userDeletionHandler = async (userAttributes, config) => { const failedUserDeletions = []; await Promise.all( validUserIds.map(async (uId) => { - const url = `https://api.iterable.com/api/users/byUserId/${uId}`; + const endpointCategory = { endpoint: `users/byUserId/${uId}` }; + const url = constructEndpoint(dataCenter, endpointCategory); const requestOptions = { headers: { 'Content-Type': JSON_MIME_TYPE, diff --git a/test/integrations/destinations/iterable/deleteUsers/data.ts b/test/integrations/destinations/iterable/deleteUsers/data.ts index 79d801f4eee..9e7eab1ee13 100644 --- a/test/integrations/destinations/iterable/deleteUsers/data.ts +++ b/test/integrations/destinations/iterable/deleteUsers/data.ts @@ -183,4 +183,40 @@ export const data = [ }, }, }, + { + name: destType, + description: 'Test 5: should pass when dataCenter is selected as EUDC', + feature: 'userDeletion', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destType: destType.toUpperCase(), + userAttributes: [ + { + userId: 'rudder7', + }, + ], + config: { + apiKey: 'dummyApiKey', + dataCenter: 'EUDC', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + statusCode: 200, + status: 'successful', + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/iterable/network.ts b/test/integrations/destinations/iterable/network.ts index 39544b26477..1cf26dfd4f4 100644 --- a/test/integrations/destinations/iterable/network.ts +++ b/test/integrations/destinations/iterable/network.ts @@ -105,5 +105,22 @@ const deleteNwData = [ status: 200, }, }, + { + httpReq: { + method: 'delete', + url: 'https://api.eu.iterable.com/api/users/byUserId/rudder7', + headers: { + api_key: 'dummyApiKey', + }, + }, + httpRes: { + data: { + msg: 'All users associated with rudder7 were successfully deleted', + code: 'Success', + params: null, + }, + status: 200, + }, + }, ]; export const networkCallsData = [...deleteNwData]; From c43f0bd057b111f42da3429771de269014b54ccc Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Sat, 16 Nov 2024 03:43:59 +0530 Subject: [PATCH 112/147] chore(shopify): seperate pixel server side events logic from legacy tracker implementation (#3849) * chore: initial commit, adding transformation and utils * chore: handle new qparam * chore: fix tests, qparams and mocks * chore: add testsx1 * chore: remove redundant id assigns and code * chore: fixing mocking, temp commit * chore: refactor and restructure test and transformations * chore: cleanup redundant testdata * chore: updates to facilitate utils mocking * chore: address events, add unit tests for new util functions * chore: update fxn name * chore: remove redis related check function in pixel transformation * chore: remove redundant switch case --------- Co-authored-by: Sai Sankeerth --- src/v0/sources/shopify/util.js | 23 +- src/v1/sources/shopify/transform.js | 20 +- .../serverSideTransform.js | 174 ++ .../serverSideUtils.test.js | 112 ++ .../webhookTransformations/serverSideUtlis.js | 45 + .../pixelTransform.js | 14 +- .../pixelTransform.redisCartToken.test.js | 16 +- .../pixelUtils.js | 6 +- .../pixelUtils.test.js | 5 +- test/integrations/component.test.ts | 1 + test/integrations/sources/shopify/data.ts | 14 +- test/integrations/sources/shopify/mocks.ts | 5 + .../shopify/v1ServerSideEventsTests.ts | 596 ------ .../CheckoutEventsTests.ts | 1687 +++++++++++++++++ .../webhookTestScenarios/GenericTrackTests.ts | 557 ++++++ .../webhookTestScenarios/IdentifyTests.ts | 256 +++ 16 files changed, 2890 insertions(+), 641 deletions(-) create mode 100644 src/v1/sources/shopify/webhookTransformations/serverSideTransform.js create mode 100644 src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js create mode 100644 src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js rename src/v1/sources/shopify/{ => webpixelTransformations}/pixelTransform.js (94%) rename src/v1/sources/shopify/{ => webpixelTransformations}/pixelTransform.redisCartToken.test.js (87%) rename src/v1/sources/shopify/{ => webpixelTransformations}/pixelUtils.js (97%) rename src/v1/sources/shopify/{ => webpixelTransformations}/pixelUtils.test.js (99%) create mode 100644 test/integrations/sources/shopify/mocks.ts delete mode 100644 test/integrations/sources/shopify/v1ServerSideEventsTests.ts create mode 100644 test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts create mode 100644 test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts create mode 100644 test/integrations/sources/shopify/webhookTestScenarios/IdentifyTests.ts diff --git a/src/v0/sources/shopify/util.js b/src/v0/sources/shopify/util.js index 981832363e4..b7e79e35a16 100644 --- a/src/v0/sources/shopify/util.js +++ b/src/v0/sources/shopify/util.js @@ -2,15 +2,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ const { v5 } = require('uuid'); const sha256 = require('sha256'); -const { TransformationError } = require('@rudderstack/integrations-lib'); +const { TransformationError, isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); const stats = require('../../../util/stats'); -const { - constructPayload, - extractCustomFields, - flattenJson, - generateUUID, - isDefinedAndNotNull, -} = require('../../util'); +const utils = require('../../util'); const { RedisDB } = require('../../../util/redis/redisConnector'); const { lineItemsMappingJSON, @@ -92,8 +86,8 @@ const getProductsListFromLineItems = (lineItems) => { } const products = []; lineItems.forEach((lineItem) => { - const product = constructPayload(lineItem, lineItemsMappingJSON); - extractCustomFields(lineItem, product, 'root', LINE_ITEM_EXCLUSION_FIELDS); + const product = utils.constructPayload(lineItem, lineItemsMappingJSON); + utils.extractCustomFields(lineItem, product, 'root', LINE_ITEM_EXCLUSION_FIELDS); product.variant = getVariantString(lineItem); products.push(product); }); @@ -103,14 +97,14 @@ const getProductsListFromLineItems = (lineItems) => { const createPropertiesForEcomEvent = (message) => { const { line_items: lineItems } = message; const productsList = getProductsListFromLineItems(lineItems); - const mappedPayload = constructPayload(message, productMappingJSON); - extractCustomFields(message, mappedPayload, 'root', PRODUCT_MAPPING_EXCLUSION_FIELDS); + const mappedPayload = utils.constructPayload(message, productMappingJSON); + utils.extractCustomFields(message, mappedPayload, 'root', PRODUCT_MAPPING_EXCLUSION_FIELDS); mappedPayload.products = productsList; return mappedPayload; }; const extractEmailFromPayload = (event) => { - const flattenedPayload = flattenJson(event); + const flattenedPayload = utils.flattenJson(event); let email; const regex_email = /\bemail\b/i; Object.entries(flattenedPayload).some(([key, value]) => { @@ -182,7 +176,7 @@ const getAnonymousIdAndSessionId = async (message, metricMetadata, redisData = n return { anonymousId, sessionId }; } return { - anonymousId: isDefinedAndNotNull(anonymousId) ? anonymousId : generateUUID(), + anonymousId: isDefinedAndNotNull(anonymousId) ? anonymousId : utils.generateUUID(), sessionId, }; } @@ -281,4 +275,5 @@ module.exports = { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, + getVariantString, }; diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index dee5a14a9df..5ebf4a34fc5 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -1,19 +1,27 @@ /* eslint-disable @typescript-eslint/naming-convention */ -const { processEventFromPixel } = require('./pixelTransform'); +const { processPixelWebEvents } = require('./webpixelTransformations/pixelTransform'); const { process: processWebhookEvents } = require('../../../v0/sources/shopify/transform'); +const { + process: processPixelWebhookEvents, +} = require('./webhookTransformations/serverSideTransform'); const process = async (inputEvent) => { const { event } = inputEvent; - // check on the source Config to identify the event is from the tracker-based (legacy) - // or the pixel-based (latest) implementation. + const { query_parameters } = event; + // check identify the event is from the web pixel based on the pixelEventLabel property. const { pixelEventLabel: pixelClientEventLabel } = event; if (pixelClientEventLabel) { // this is a event fired from the web pixel loaded on the browser // by the user interactions with the store. - const responseV2 = await processEventFromPixel(event); - return responseV2; + const pixelWebEventResponse = await processPixelWebEvents(event); + return pixelWebEventResponse; } - // this is for common logic for server-side events processing for both pixel and tracker apps. + if (query_parameters && query_parameters?.version?.[0] === 'pixel') { + // this is a server-side event from the webhook subscription made by the pixel app. + const pixelWebhookEventResponse = await processPixelWebhookEvents(event); + return pixelWebhookEventResponse; + } + // this is a server-side event from the webhook subscription made by the legacy tracker-based app. const response = await processWebhookEvents(event); return response; }; diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js new file mode 100644 index 00000000000..c31bc74bf15 --- /dev/null +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -0,0 +1,174 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const lodash = require('lodash'); +const get = require('get-value'); +// const { RedisError } = require('@rudderstack/integrations-lib'); +const stats = require('../../../../util/stats'); +const { + getShopifyTopic, + // createPropertiesForEcomEvent, + extractEmailFromPayload, + getAnonymousIdAndSessionId, + // getHashLineItems, +} = require('../../../../v0/sources/shopify/util'); +// const logger = require('../../../logger'); +const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../../v0/util'); +// const { RedisDB } = require('../../../util/redis/redisConnector'); +const Message = require('../../../../v0/sources/message'); +const { EventType } = require('../../../../constants'); +const { + INTEGERATION, + MAPPING_CATEGORIES, + IDENTIFY_TOPICS, + ECOM_TOPICS, + RUDDER_ECOM_MAP, + SUPPORTED_TRACK_EVENTS, + SHOPIFY_TRACK_MAP, + lineItemsMappingJSON, +} = require('../../../../v0/sources/shopify/config'); +const { + createPropertiesForEcomEventFromWebhook, + getProductsFromLineItems, +} = require('./serverSideUtlis'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +const identifyPayloadBuilder = (event) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.IDENTIFY); + message.setPropertiesV2(event, MAPPING_CATEGORIES[EventType.IDENTIFY]); + if (event.updated_at) { + // converting shopify updated_at timestamp to rudder timestamp format + message.setTimestamp(new Date(event.updated_at).toISOString()); + } + return message; +}; + +const ecomPayloadBuilder = (event, shopifyTopic) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(RUDDER_ECOM_MAP[shopifyTopic]); + + const properties = createPropertiesForEcomEventFromWebhook(event); + message.properties = removeUndefinedAndNullValues(properties); + // Map Customer details if present + const customerDetails = get(event, 'customer'); + if (customerDetails) { + message.setPropertiesV2(customerDetails, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + if (event.updated_at) { + message.setTimestamp(new Date(event.updated_at).toISOString()); + } + if (event.customer) { + message.setPropertiesV2(event.customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + if (event.shipping_address) { + message.setProperty('traits.shippingAddress', event.shipping_address); + } + if (event.billing_address) { + message.setProperty('traits.billingAddress', event.billing_address); + } + if (!message.userId && event.user_id) { + message.setProperty('userId', event.user_id); + } + return message; +}; + +const trackPayloadBuilder = (event, shopifyTopic) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(SHOPIFY_TRACK_MAP[shopifyTopic]); + // eslint-disable-next-line camelcase + const { line_items: lineItems } = event; + const productsList = getProductsFromLineItems(lineItems, lineItemsMappingJSON); + message.setProperty('properties.products', productsList); + return message; +}; + +const processEvent = async (inputEvent, metricMetadata) => { + let message; + const event = lodash.cloneDeep(inputEvent); + const shopifyTopic = getShopifyTopic(event); + delete event.query_parameters; + switch (shopifyTopic) { + case IDENTIFY_TOPICS.CUSTOMERS_CREATE: + case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: + message = identifyPayloadBuilder(event); + break; + case ECOM_TOPICS.ORDERS_CREATE: + case ECOM_TOPICS.ORDERS_UPDATE: + case ECOM_TOPICS.CHECKOUTS_CREATE: + case ECOM_TOPICS.CHECKOUTS_UPDATE: + message = ecomPayloadBuilder(event, shopifyTopic); + break; + default: + if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { + stats.increment('invalid_shopify_event', { + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + return NO_OPERATION_SUCCESS; + } + message = trackPayloadBuilder(event, shopifyTopic); + break; + } + + if (message.userId) { + message.userId = String(message.userId); + } + if (!get(message, 'traits.email')) { + const email = extractEmailFromPayload(event); + if (email) { + message.setProperty('traits.email', email); + } + } + if (message.type !== EventType.IDENTIFY) { + const { anonymousId } = await getAnonymousIdAndSessionId( + message, + { shopifyTopic, ...metricMetadata }, + null, + ); + if (isDefinedAndNotNull(anonymousId)) { + message.setProperty('anonymousId', anonymousId); + } + } + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }); + message.setProperty('context.topic', shopifyTopic); + // attaching cart, checkout and order tokens in context object + message.setProperty(`context.cart_token`, event.cart_token); + message.setProperty(`context.checkout_token`, event.checkout_token); + // raw shopify payload passed inside context object under shopifyDetails + message.setProperty('context.shopifyDetails', event); + if (shopifyTopic === 'orders_updated') { + message.setProperty(`context.order_token`, event.token); + } + message = removeUndefinedAndNullValues(message); + return message; +}; +const process = async (event) => { + const metricMetadata = { + writeKey: event.query_parameters?.writeKey?.[0], + source: 'SHOPIFY', + }; + const response = await processEvent(event, metricMetadata); + return response; +}; + +module.exports = { + process, + processEvent, + identifyPayloadBuilder, + ecomPayloadBuilder, + trackPayloadBuilder, +}; diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js new file mode 100644 index 00000000000..a611d1d8dc9 --- /dev/null +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js @@ -0,0 +1,112 @@ +const { + getProductsFromLineItems, + createPropertiesForEcomEventFromWebhook, +} = require('./serverSideUtlis'); + +const { constructPayload } = require('../../../../v0/util'); + +const { + lineItemsMappingJSON, + productMappingJSON, +} = require('../../../../v0/sources/shopify/config'); +const Message = require('../../../../v0/sources/message'); +jest.mock('../../../../v0/sources/message'); + +const LINEITEMS = [ + { + id: '41327142600817', + grams: 0, + presentment_title: 'The Collection Snowboard: Hydrogen', + product_id: 7234590408818, + quantity: 1, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + variant_id: 41327142600817, + variant_title: '', + variant_price: '600.00', + vendor: 'Hydrogen Vendor', + line_price: '600.00', + price: '600.00', + applied_discounts: [], + properties: {}, + }, + { + id: 14234727743601, + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Nitrogen', + price: '600.00', + product_exists: true, + product_id: 7234590408817, + properties: [], + quantity: 1, + sku: '', + title: 'The Collection Snowboard: Nitrogen', + total_discount: '0.00', + variant_id: 41327142600817, + vendor: 'Hydrogen Vendor', + }, +]; + +describe('serverSideUtils.js', () => { + beforeEach(() => { + Message.mockClear(); + }); + + describe('Test getProductsFromLineItems function', () => { + it('should return empty array if lineItems is empty', () => { + const lineItems = []; + const result = getProductsFromLineItems(lineItems, lineItemsMappingJSON); + expect(result).toEqual([]); + }); + + it('should return array of products', () => { + const mapping = {}; + const result = getProductsFromLineItems(LINEITEMS, lineItemsMappingJSON); + expect(result).toEqual([ + { brand: 'Hydrogen Vendor', price: '600.00', product_id: 7234590408818, quantity: 1 }, + { + brand: 'Hydrogen Vendor', + price: '600.00', + product_id: 7234590408817, + quantity: 1, + title: 'The Collection Snowboard: Nitrogen', + }, + ]); + }); + }); + + describe('Test createPropertiesForEcomEventFromWebhook function', () => { + it('should return empty array if lineItems is empty', () => { + const message = { + line_items: [], + type: 'track', + event: 'checkout created', + }; + const result = createPropertiesForEcomEventFromWebhook(message); + expect(result).toEqual([]); + }); + + it('should return array of products', () => { + const message = { + line_items: LINEITEMS, + type: 'track', + event: 'checkout updated', + }; + const result = createPropertiesForEcomEventFromWebhook(message); + expect(result).toEqual({ + products: [ + { brand: 'Hydrogen Vendor', price: '600.00', product_id: 7234590408818, quantity: 1 }, + { + brand: 'Hydrogen Vendor', + price: '600.00', + product_id: 7234590408817, + quantity: 1, + title: 'The Collection Snowboard: Nitrogen', + }, + ], + }); + }); + }); +}); diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js new file mode 100644 index 00000000000..eed03de71ff --- /dev/null +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -0,0 +1,45 @@ +const { constructPayload } = require('../../../../v0/util'); + +const { + lineItemsMappingJSON, + productMappingJSON, +} = require('../../../../v0/sources/shopify/config'); + +/** + * Returns an array of products from the lineItems array received from the webhook event + * @param {Array} lineItems + * @param {Object} mapping + * @returns {Array} products + */ +const getProductsFromLineItems = (lineItems, mapping) => { + if (!lineItems || lineItems.length === 0) { + return []; + } + const products = []; + lineItems.forEach((lineItem) => { + // const product = constructPayload(lineItem, lineItemsMappingJSON); + const product = constructPayload(lineItem, mapping); + products.push(product); + }); + return products; +}; + +/** + * Creates properties for the ecommerce webhook events received from the pixel based app + * @param {Object} message + * @returns {Object} properties + */ +const createPropertiesForEcomEventFromWebhook = (message) => { + const { line_items: lineItems } = message; + if (!lineItems || lineItems.length === 0) { + return []; + } + const mappedPayload = constructPayload(message, productMappingJSON); + mappedPayload.products = getProductsFromLineItems(lineItems, lineItemsMappingJSON); + return mappedPayload; +}; + +module.exports = { + createPropertiesForEcomEventFromWebhook, + getProductsFromLineItems, +}; diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/webpixelTransformations/pixelTransform.js similarity index 94% rename from src/v1/sources/shopify/pixelTransform.js rename to src/v1/sources/shopify/webpixelTransformations/pixelTransform.js index e308f626b48..b1d1c8b2fac 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelTransform.js @@ -2,10 +2,10 @@ // eslint-disable-next-line @typescript-eslint/naming-convention const _ = require('lodash'); const { isDefinedNotNullNotEmpty } = require('@rudderstack/integrations-lib'); -const stats = require('../../../util/stats'); -const logger = require('../../../logger'); -const { removeUndefinedAndNullValues } = require('../../../v0/util'); -const { RedisDB } = require('../../../util/redis/redisConnector'); +const stats = require('../../../../util/stats'); +const logger = require('../../../../logger'); +const { removeUndefinedAndNullValues } = require('../../../../v0/util'); +const { RedisDB } = require('../../../../util/redis/redisConnector'); const { pageViewedEventBuilder, cartViewedEventBuilder, @@ -20,7 +20,7 @@ const { INTEGERATION, PIXEL_EVENT_TOPICS, pixelEventToCartTokenLocationMapping, -} = require('./config'); +} = require('../config'); const NO_OPERATION_SUCCESS = { outputToSource: { @@ -152,13 +152,13 @@ function processPixelEvent(inputEvent) { return message; } -const processEventFromPixel = async (event) => { +const processPixelWebEvents = async (event) => { const pixelEvent = processPixelEvent(event); return removeUndefinedAndNullValues(pixelEvent); }; module.exports = { - processEventFromPixel, + processPixelWebEvents, handleCartTokenRedisOperations, extractCartToken, }; diff --git a/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js b/src/v1/sources/shopify/webpixelTransformations/pixelTransform.redisCartToken.test.js similarity index 87% rename from src/v1/sources/shopify/pixelTransform.redisCartToken.test.js rename to src/v1/sources/shopify/webpixelTransformations/pixelTransform.redisCartToken.test.js index 8f54efc3735..1e5cb94b19c 100644 --- a/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelTransform.redisCartToken.test.js @@ -1,25 +1,25 @@ const { extractCartToken, handleCartTokenRedisOperations } = require('./pixelTransform'); -const { RedisDB } = require('../../../util/redis/redisConnector'); -const stats = require('../../../util/stats'); -const logger = require('../../../logger'); -const { pixelEventToCartTokenLocationMapping } = require('./config'); +const { RedisDB } = require('../../../../util/redis/redisConnector'); +const stats = require('../../../../util/stats'); +const logger = require('../../../../logger'); +const { pixelEventToCartTokenLocationMapping } = require('../config'); -jest.mock('../../../util/redis/redisConnector', () => ({ +jest.mock('../../../../util/redis/redisConnector', () => ({ RedisDB: { setVal: jest.fn(), }, })); -jest.mock('../../../util/stats', () => ({ +jest.mock('../../../../util/stats', () => ({ increment: jest.fn(), })); -jest.mock('../../../logger', () => ({ +jest.mock('../../../../logger', () => ({ info: jest.fn(), error: jest.fn(), })); -jest.mock('./config', () => ({ +jest.mock('../config', () => ({ pixelEventToCartTokenLocationMapping: { cart_viewed: 'properties.cart_id' }, })); diff --git a/src/v1/sources/shopify/pixelUtils.js b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js similarity index 97% rename from src/v1/sources/shopify/pixelUtils.js rename to src/v1/sources/shopify/webpixelTransformations/pixelUtils.js index 9abef5c2f85..0c1007f311e 100644 --- a/src/v1/sources/shopify/pixelUtils.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js @@ -1,6 +1,6 @@ /* eslint-disable no-param-reassign */ -const Message = require('../../../v0/sources/message'); -const { EventType } = require('../../../constants'); +const Message = require('../../../../v0/sources/message'); +const { EventType } = require('../../../../constants'); const { INTEGERATION, PIXEL_EVENT_MAPPING, @@ -10,7 +10,7 @@ const { productViewedEventMappingJSON, productToCartEventMappingJSON, checkoutStartedCompletedEventMappingJSON, -} = require('./config'); +} = require('../config'); function getNestedValue(object, path) { const keys = path.split('.'); diff --git a/src/v1/sources/shopify/pixelUtils.test.js b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.test.js similarity index 99% rename from src/v1/sources/shopify/pixelUtils.test.js rename to src/v1/sources/shopify/webpixelTransformations/pixelUtils.test.js index 4bff8eada4c..e8f53a5f153 100644 --- a/src/v1/sources/shopify/pixelUtils.test.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.test.js @@ -8,10 +8,9 @@ const { checkoutStepEventBuilder, searchEventBuilder, } = require('./pixelUtils'); -const { EventType } = require('../../../constants'); -const Message = require('../../../v0/sources/message'); +const Message = require('../../../../v0/sources/message'); jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); -jest.mock('../../../v0/sources/message'); +jest.mock('../../../../v0/sources/message'); describe('utilV2.js', () => { beforeEach(() => { diff --git a/test/integrations/component.test.ts b/test/integrations/component.test.ts index daed7c9e1f1..baad6813dfb 100644 --- a/test/integrations/component.test.ts +++ b/test/integrations/component.test.ts @@ -41,6 +41,7 @@ command .option('-i, --index ', 'Enter Test index') .option('-g, --generate ', 'Enter "true" If you want to generate network file') .option('-id, --id ', 'Enter unique "Id" of the test case you want to run') + .option('-s, --source ', 'Enter Source Name') .parse(); const opts = command.opts(); diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index a2b27cbbccd..d4498e089c9 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,8 +1,10 @@ -import { skip } from 'node:test'; import { pixelCheckoutEventsTestScenarios } from './pixelTestScenarios/CheckoutEventsTests'; import { pixelCheckoutStepsScenarios } from './pixelTestScenarios/CheckoutStepsTests'; import { pixelEventsTestScenarios } from './pixelTestScenarios/ProductEventsTests'; -import { v1ServerSideEventsScenarios } from './v1ServerSideEventsTests'; +import { checkoutEventsTestScenarios } from './webhookTestScenarios/CheckoutEventsTests'; +import { genericTrackTestScenarios } from './webhookTestScenarios/GenericTrackTests'; +import { identityTestScenarios } from './webhookTestScenarios/IdentifyTests'; +import { mockFns } from './mocks'; const serverSideEventsScenarios = [ { @@ -1422,6 +1424,7 @@ const serverSideEventsScenarios = [ verifiedEmail: true, }, type: 'track', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', userId: '115310627314723950', }, ], @@ -1430,13 +1433,16 @@ const serverSideEventsScenarios = [ ], }, }, + mockFns, }, ]; export const data = [ + ...serverSideEventsScenarios, + ...checkoutEventsTestScenarios, + ...genericTrackTestScenarios, + ...identityTestScenarios, ...pixelCheckoutEventsTestScenarios, ...pixelCheckoutStepsScenarios, ...pixelEventsTestScenarios, - ...serverSideEventsScenarios, - ...v1ServerSideEventsScenarios, ]; diff --git a/test/integrations/sources/shopify/mocks.ts b/test/integrations/sources/shopify/mocks.ts new file mode 100644 index 00000000000..e1895e78124 --- /dev/null +++ b/test/integrations/sources/shopify/mocks.ts @@ -0,0 +1,5 @@ +import utils from '../../../../src/v0/util'; + +export const mockFns = (_) => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('5d3e2cb6-4011-5c9c-b7ee-11bc1e905097'); +}; diff --git a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts deleted file mode 100644 index 2c323cb370d..00000000000 --- a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts +++ /dev/null @@ -1,596 +0,0 @@ -// This file contains the test scenarios for the server-side events from the Shopify GraphQL API for -// the v1 transformation flow -import utils from '../../../../src/v0/util'; -const defaultMockFns = () => { - jest.spyOn(utils, 'generateUUID').mockReturnValue('5d3e2cb6-4011-5c9c-b7ee-11bc1e905097'); -}; -import { dummySourceConfig } from './constants'; - -export const v1ServerSideEventsScenarios = [ - { - name: 'shopify', - description: 'Track Call -> Checkout Updated event', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 35374569160817, - token: 'e89d4437003b6b8480f8bc7f8036a659', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - email: 'testuser101@gmail.com', - gateway: null, - buyer_accepts_marketing: false, - buyer_accepts_sms_marketing: false, - sms_marketing_phone: null, - created_at: '2024-09-16T03:50:15+00:00', - updated_at: '2024-09-17T03:29:02-04:00', - landing_site: '/', - note: '', - note_attributes: [], - referring_site: '', - shipping_lines: [ - { - code: 'Standard', - price: '6.90', - original_shop_price: '6.90', - original_shop_markup: '0.00', - source: 'shopify', - title: 'Standard', - presentment_title: 'Standard', - phone: null, - tax_lines: [], - custom_tax_lines: null, - markup: '0.00', - carrier_identifier: null, - carrier_service_id: null, - api_client_id: '580111', - delivery_option_group: { - token: '26492692a443ee35c30eb82073bacaa8', - type: 'one_time_purchase', - }, - delivery_expectation_range: null, - delivery_expectation_type: null, - id: null, - requested_fulfillment_service_id: null, - delivery_category: null, - validation_context: null, - applied_discounts: [], - }, - ], - shipping_address: { - first_name: 'testuser', - address1: 'oakwood bridge', - phone: null, - city: 'KLF', - zip: '85003', - province: 'Arizona', - country: 'United States', - last_name: 'dummy', - address2: 'Hedgetown', - company: null, - latitude: null, - longitude: null, - name: 'testuser dummy', - country_code: 'US', - province_code: 'AZ', - }, - taxes_included: false, - total_weight: 0, - currency: 'USD', - completed_at: null, - phone: null, - customer_locale: 'en-US', - line_items: [ - { - key: '41327143059569', - fulfillment_service: 'manual', - gift_card: false, - grams: 0, - presentment_title: 'The Multi-location Snowboard', - presentment_variant_title: '', - product_id: 7234590638193, - quantity: 1, - requires_shipping: true, - sku: '', - tax_lines: [], - taxable: true, - title: 'The Multi-location Snowboard', - variant_id: 41327143059569, - variant_title: '', - variant_price: '729.95', - vendor: 'pixel-testing-rs', - unit_price_measurement: { - measured_type: null, - quantity_value: null, - quantity_unit: null, - reference_value: null, - reference_unit: null, - }, - compare_at_price: null, - line_price: '729.95', - price: '729.95', - applied_discounts: [], - destination_location_id: null, - user_id: null, - rank: null, - origin_location_id: null, - properties: {}, - }, - ], - name: '#35374569160817', - abandoned_checkout_url: - 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', - discount_codes: [], - tax_lines: [], - presentment_currency: 'USD', - source_name: 'web', - total_line_items_price: '729.95', - total_tax: '0.00', - total_discounts: '0.00', - subtotal_price: '729.95', - total_price: '736.85', - total_duties: '0.00', - device_id: null, - user_id: null, - location_id: null, - source_identifier: null, - source_url: null, - source: null, - closed_at: null, - customer: { - id: 7188389789809, - email: 'testuser101@gmail.com', - accepts_marketing: false, - created_at: null, - updated_at: null, - first_name: 'testuser', - last_name: 'dummy', - orders_count: 0, - state: 'disabled', - total_spent: '0.00', - last_order_id: null, - note: null, - verified_email: true, - multipass_identifier: null, - tax_exempt: false, - phone: null, - tags: '', - currency: 'USD', - accepts_marketing_updated_at: null, - admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', - default_address: { - id: null, - customer_id: 7188389789809, - first_name: 'testuser', - last_name: 'dummy', - company: null, - address1: 'oakwood bridge', - address2: 'Hedgetown', - city: 'KLF', - province: 'Arizona', - country: 'United States', - zip: '85003', - phone: null, - name: 'testuser dummy', - province_code: 'AZ', - country_code: 'US', - country_name: 'United States', - default: true, - }, - last_order_name: null, - marketing_opt_in_level: null, - }, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - library: { - name: 'RudderStack Shopify Cloud', - version: '1.0.0', - }, - integration: { - name: 'SHOPIFY', - }, - topic: 'checkouts_update', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Updated', - properties: { - order_id: 35374569160817, - value: '736.85', - tax: '0.00', - currency: 'USD', - token: 'e89d4437003b6b8480f8bc7f8036a659', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - email: 'testuser101@gmail.com', - buyer_accepts_marketing: false, - buyer_accepts_sms_marketing: false, - created_at: '2024-09-16T03:50:15+00:00', - updated_at: '2024-09-17T03:29:02-04:00', - landing_site: '/', - note: '', - note_attributes: [], - referring_site: '', - shipping_lines: [ - { - code: 'Standard', - price: '6.90', - original_shop_price: '6.90', - original_shop_markup: '0.00', - source: 'shopify', - title: 'Standard', - presentment_title: 'Standard', - phone: null, - tax_lines: [], - custom_tax_lines: null, - markup: '0.00', - carrier_identifier: null, - carrier_service_id: null, - api_client_id: '580111', - delivery_option_group: { - token: '26492692a443ee35c30eb82073bacaa8', - type: 'one_time_purchase', - }, - delivery_expectation_range: null, - delivery_expectation_type: null, - id: null, - requested_fulfillment_service_id: null, - delivery_category: null, - validation_context: null, - applied_discounts: [], - }, - ], - taxes_included: false, - total_weight: 0, - customer_locale: 'en-US', - name: '#35374569160817', - abandoned_checkout_url: - 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', - discount_codes: [], - tax_lines: [], - presentment_currency: 'USD', - source_name: 'web', - total_line_items_price: '729.95', - total_discounts: '0.00', - subtotal_price: '729.95', - total_duties: '0.00', - products: [ - { - product_id: 7234590638193, - price: '729.95', - brand: 'pixel-testing-rs', - quantity: 1, - key: '41327143059569', - fulfillment_service: 'manual', - gift_card: false, - grams: 0, - presentment_title: 'The Multi-location Snowboard', - presentment_variant_title: '', - requires_shipping: true, - tax_lines: [], - taxable: true, - title: 'The Multi-location Snowboard', - unit_price_measurement: { - measured_type: null, - quantity_value: null, - quantity_unit: null, - reference_value: null, - reference_unit: null, - }, - compare_at_price: null, - line_price: '729.95', - applied_discounts: [], - destination_location_id: null, - user_id: null, - rank: null, - origin_location_id: null, - properties: {}, - variant: '41327143059569 729.95 ', - }, - ], - }, - userId: '7188389789809', - traits: { - email: 'testuser101@gmail.com', - firstName: 'testuser', - lastName: 'dummy', - address: { - id: null, - customer_id: 7188389789809, - first_name: 'testuser', - last_name: 'dummy', - company: null, - address1: 'oakwood bridge', - address2: 'Hedgetown', - city: 'KLF', - province: 'Arizona', - country: 'United States', - zip: '85003', - phone: null, - name: 'testuser dummy', - province_code: 'AZ', - country_code: 'US', - country_name: 'United States', - default: true, - }, - acceptsMarketing: false, - orderCount: 0, - state: 'disabled', - totalSpent: '0.00', - verifiedEmail: true, - taxExempt: false, - tags: '', - currency: 'USD', - adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', - shippingAddress: { - first_name: 'testuser', - address1: 'oakwood bridge', - phone: null, - city: 'KLF', - zip: '85003', - province: 'Arizona', - country: 'United States', - last_name: 'dummy', - address2: 'Hedgetown', - company: null, - latitude: null, - longitude: null, - name: 'testuser dummy', - country_code: 'US', - province_code: 'AZ', - }, - }, - timestamp: '2024-09-17T07:29:02.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', - }, - ], - }, - }, - ], - }, - }, - mockFns: () => { - defaultMockFns(); - }, - }, - { - name: 'shopify', - description: 'Track Call -> Cart Update event', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - line_items: [ - { - id: 41327143059569, - properties: null, - quantity: 3, - variant_id: 41327143059569, - key: '41327143059569:90562f18109e0e6484b0c297e7981b30', - discounted_price: '729.95', - discounts: [], - gift_card: false, - grams: 0, - line_price: '2189.85', - original_line_price: '2189.85', - original_price: '729.95', - price: '729.95', - product_id: 7234590638193, - sku: '', - taxable: true, - title: 'The Multi-location Snowboard', - total_discount: '0.00', - vendor: 'pixel-testing-rs', - discounted_price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - original_line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - total_discount_set: { - shop_money: { - amount: '0.0', - currency_code: 'USD', - }, - presentment_money: { - amount: '0.0', - currency_code: 'USD', - }, - }, - }, - ], - note: '', - updated_at: '2024-09-17T08:15:13.280Z', - created_at: '2024-09-16T03:50:15.478Z', - query_parameters: { - topic: ['carts_update'], - writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - library: { - name: 'RudderStack Shopify Cloud', - version: '1.0.0', - }, - integration: { - name: 'SHOPIFY', - }, - topic: 'carts_update', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Cart Update', - properties: { - id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - note: '', - updated_at: '2024-09-17T08:15:13.280Z', - created_at: '2024-09-16T03:50:15.478Z', - products: [ - { - product_id: 7234590638193, - price: '729.95', - brand: 'pixel-testing-rs', - quantity: 3, - id: 41327143059569, - properties: null, - key: '41327143059569:90562f18109e0e6484b0c297e7981b30', - discounted_price: '729.95', - discounts: [], - gift_card: false, - grams: 0, - line_price: '2189.85', - original_line_price: '2189.85', - original_price: '729.95', - taxable: true, - title: 'The Multi-location Snowboard', - total_discount: '0.00', - discounted_price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - original_line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - total_discount_set: { - shop_money: { - amount: '0.0', - currency_code: 'USD', - }, - presentment_money: { - amount: '0.0', - currency_code: 'USD', - }, - }, - variant: '41327143059569 ', - }, - ], - }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', - }, - ], - }, - }, - ], - }, - }, - mockFns: () => { - defaultMockFns(); - }, - }, -]; diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts new file mode 100644 index 00000000000..ade496efb79 --- /dev/null +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -0,0 +1,1687 @@ +// This file contains the test scenarios for the server-side events from the Shopify GraphQL API for +// the v1 transformation flow +import { mockFns } from '../mocks'; +import { dummySourceConfig } from '../constants'; + +export const checkoutEventsTestScenarios = [ + { + id: 'c001', + name: 'shopify', + description: 'Track Call -> Checkout Started event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 35550298931313, + token: '84ad78572dae52a8cbea7d55371afe89', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + email: null, + gateway: null, + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + sms_marketing_phone: null, + created_at: '2024-11-06T02:22:00+00:00', + updated_at: '2024-11-05T21:22:02-05:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [], + shipping_address: [], + taxes_included: false, + total_weight: 0, + currency: 'USD', + completed_at: null, + phone: null, + customer_locale: 'en-US', + line_items: [ + { + key: '41327142600817', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Collection Snowboard: Hydrogen', + presentment_variant_title: '', + product_id: 7234590408817, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + variant_id: 41327142600817, + variant_title: '', + variant_price: '600.00', + vendor: 'Hydrogen Vendor', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '600.00', + price: '600.00', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35550298931313', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ/recover?key=0385163be3875d3a2117e982d9cc3517&locale=en-US', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '600.00', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '600.00', + total_price: '600.00', + total_duties: '0.00', + device_id: null, + user_id: null, + location_id: null, + source_identifier: null, + source_url: null, + source: null, + closed_at: null, + query_parameters: { + topic: ['checkouts_create'], + version: ['pixel'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + }, + }, + source: dummySourceConfig, + query_parameters: { + topic: ['carts_update'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'checkouts_create', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + shopifyDetails: { + id: 35550298931313, + token: '84ad78572dae52a8cbea7d55371afe89', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + email: null, + gateway: null, + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + sms_marketing_phone: null, + created_at: '2024-11-06T02:22:00+00:00', + updated_at: '2024-11-05T21:22:02-05:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [], + shipping_address: [], + taxes_included: false, + total_weight: 0, + currency: 'USD', + completed_at: null, + phone: null, + customer_locale: 'en-US', + line_items: [ + { + key: '41327142600817', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Collection Snowboard: Hydrogen', + presentment_variant_title: '', + product_id: 7234590408817, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + variant_id: 41327142600817, + variant_title: '', + variant_price: '600.00', + vendor: 'Hydrogen Vendor', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '600.00', + price: '600.00', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35550298931313', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ/recover?key=0385163be3875d3a2117e982d9cc3517&locale=en-US', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '600.00', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '600.00', + total_price: '600.00', + total_duties: '0.00', + device_id: null, + user_id: null, + location_id: null, + source_identifier: null, + source_url: null, + source: null, + closed_at: null, + }, + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Started', + properties: { + order_id: 35550298931313, + value: '600.00', + tax: '0.00', + currency: 'USD', + products: [ + { + product_id: 7234590408817, + price: '600.00', + brand: 'Hydrogen Vendor', + quantity: 1, + }, + ], + }, + timestamp: '2024-11-06T02:22:02.000Z', + traits: { + shippingAddress: [], + }, + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, + { + id: 'c002', + name: 'shopify', + description: 'Track Call -> Checkout Updated event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + id: 35374569160817, + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + created_at: '2024-09-16T03:50:1500:00', + updated_at: '2024-09-17T03:29:02-04:00', + note: '', + note_attributes: [], + shipping_address: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + total_weight: 0, + currency: 'USD', + customer_locale: 'en-US', + line_items: [ + { + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + product_id: 7234590638193, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + variant_id: 41327143059569, + variant_title: '', + variant_price: '729.95', + vendor: 'pixel-testing-rs', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + presentment_currency: 'USD', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '729.95', + total_price: '736.85', + total_duties: '0.00', + customer: { + id: 7188389789809, + email: 'testuser101@gmail.com', + accepts_marketing: false, + created_at: null, + updated_at: null, + first_name: 'testuser', + last_name: 'dummy', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + tags: '', + currency: 'USD', + accepts_marketing_updated_at: null, + admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', + default_address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + last_order_name: null, + marketing_opt_in_level: null, + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + context: { + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + integration: { + name: 'SHOPIFY', + }, + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + shopifyDetails: { + id: 35374569160817, + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + created_at: '2024-09-16T03:50:1500:00', + updated_at: '2024-09-17T03:29:02-04:00', + note: '', + note_attributes: [], + shipping_address: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + total_weight: 0, + currency: 'USD', + customer_locale: 'en-US', + line_items: [ + { + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + product_id: 7234590638193, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + variant_id: 41327143059569, + variant_title: '', + variant_price: '729.95', + vendor: 'pixel-testing-rs', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + presentment_currency: 'USD', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '729.95', + total_price: '736.85', + total_duties: '0.00', + customer: { + id: 7188389789809, + email: 'testuser101@gmail.com', + accepts_marketing: false, + created_at: null, + updated_at: null, + first_name: 'testuser', + last_name: 'dummy', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + tags: '', + currency: 'USD', + accepts_marketing_updated_at: null, + admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', + default_address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + last_order_name: null, + marketing_opt_in_level: null, + }, + }, + topic: 'checkouts_update', + }, + event: 'Checkout Updated', + integrations: { + SHOPIFY: true, + }, + properties: { + currency: 'USD', + order_id: 35374569160817, + products: [ + { + brand: 'pixel-testing-rs', + price: '729.95', + product_id: 7234590638193, + quantity: 1, + }, + ], + tax: '0.00', + value: '736.85', + }, + timestamp: '2024-09-17T07:29:02.000Z', + traits: { + acceptsMarketing: false, + address: { + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + company: null, + country: 'United States', + country_code: 'US', + country_name: 'United States', + customer_id: 7188389789809, + default: true, + first_name: 'testuser', + id: null, + last_name: 'dummy', + name: 'testuser dummy', + phone: null, + province: 'Arizona', + province_code: 'AZ', + zip: '85003', + }, + adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', + currency: 'USD', + email: 'testuser101@gmail.com', + firstName: 'testuser', + lastName: 'dummy', + orderCount: 0, + shippingAddress: { + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + company: null, + country: 'United States', + country_code: 'US', + first_name: 'testuser', + last_name: 'dummy', + latitude: null, + longitude: null, + name: 'testuser dummy', + phone: null, + province: 'Arizona', + province_code: 'AZ', + zip: '85003', + }, + state: 'disabled', + tags: '', + taxExempt: false, + totalSpent: '0.00', + verifiedEmail: true, + }, + type: 'track', + userId: '7188389789809', + }, + ], + }, + }, + ], + }, + }, + }, + { + id: 'c003', + name: 'shopify', + description: 'Track Call -> Order Updated event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + app_id: 580111, + browser_ip: '139.5.255.205', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + confirmation_number: 'DPPARQ8UJ', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + current_total_discounts: '0.00', + current_total_discounts_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + current_total_price: '600.00', + current_total_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + current_total_tax: '0.00', + current_total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + customer_locale: 'en-US', + discount_codes: [], + email: 'henry@wfls.com', + estimated_taxes: false, + merchant_of_record_app_id: null, + name: '#1017', + note: null, + note_attributes: [], + number: 17, + order_number: 1017, + order_status_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['bogus'], + phone: null, + presentment_currency: 'USD', + source_identifier: '4d92cf60cc24a1bd95929e17ead9845f', + subtotal_price: '600.00', + subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + tax_lines: [], + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_discounts_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_line_items_price: '600.00', + total_line_items_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + total_price: '600.00', + total_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + total_shipping_price_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_tax: '0.00', + total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_weight: 0, + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + tags: '', + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + admin_graphql_api_id: 'gid://shopify/LineItem/14234727743601', + attributed_staffs: [], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 7234590408817, + properties: [], + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + tax_lines: [], + duties: [], + discount_allocations: [], + }, + ], + payment_terms: null, + refunds: [], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + query_parameters: { + topic: ['orders_updated'], + version: ['pixel'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'orders_updated', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + shopifyDetails: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + app_id: 580111, + browser_ip: '139.5.255.205', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + confirmation_number: 'DPPARQ8UJ', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + current_total_discounts: '0.00', + current_total_discounts_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + current_total_price: '600.00', + current_total_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + current_total_tax: '0.00', + current_total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + customer_locale: 'en-US', + discount_codes: [], + email: 'henry@wfls.com', + estimated_taxes: false, + merchant_of_record_app_id: null, + name: '#1017', + note: null, + note_attributes: [], + number: 17, + order_number: 1017, + order_status_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['bogus'], + phone: null, + presentment_currency: 'USD', + source_identifier: '4d92cf60cc24a1bd95929e17ead9845f', + subtotal_price: '600.00', + subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + tax_lines: [], + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_discounts_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_line_items_price: '600.00', + total_line_items_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + total_price: '600.00', + total_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + total_shipping_price_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_tax: '0.00', + total_tax_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + total_weight: 0, + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + tags: '', + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + admin_graphql_api_id: 'gid://shopify/LineItem/14234727743601', + attributed_staffs: [], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 7234590408817, + properties: [], + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + tax_lines: [], + duties: [], + discount_allocations: [], + }, + ], + payment_terms: null, + refunds: [], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + }, + order_token: '676613a0027fc8240e16d67fdc9f5ac8', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Order Updated', + properties: { + order_id: 5778367414385, + value: '600.00', + tax: '0.00', + currency: 'USD', + products: [ + { + product_id: 7234590408817, + title: 'The Collection Snowboard: Hydrogen', + price: '600.00', + brand: 'Hydrogen Vendor', + quantity: 1, + }, + ], + }, + userId: '7358220173425', + traits: { + email: 'henry@wfls.com', + firstName: 'yodi', + lastName: 'waffles', + address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + state: 'disabled', + verifiedEmail: true, + taxExempt: false, + tags: '', + currency: 'USD', + taxExemptions: [], + adminGraphqlApiId: 'gid://shopify/Customer/7358220173425', + shippingAddress: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + billingAddress: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + }, + timestamp: '2024-11-06T02:54:50.000Z', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, + { + id: 'c004', + name: 'shopify', + description: 'Track Call -> Order Created event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + app_id: 580111, + browser_ip: '139.5.255.205', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + confirmation_number: 'DPPARQ8UJ', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_total_discounts: '0.00', + current_total_price: '600.00', + current_total_tax: '0.00', + email: 'henry@wfls.com', + name: '#1017', + order_number: 1017, + order_status_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', + phone: null, + presentment_currency: 'USD', + subtotal_price: '600.00', + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_line_items_price: '600.00', + total_outstanding: '0.00', + total_price: '600.00', + total_tax: '0.00', + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + phone: null, + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + product_id: 7234590408817, + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + }, + ], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + query_parameters: { + topic: ['orders_create'], + version: ['pixel'], + writeKey: ['2mw9SN679HngnZkCHT4oSVVBVmb'], + }, + }, + source: dummySourceConfig, + query_parameters: { + topic: ['carts_update'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'orders_create', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + shopifyDetails: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + app_id: 580111, + browser_ip: '139.5.255.205', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + confirmation_number: 'DPPARQ8UJ', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_total_discounts: '0.00', + current_total_price: '600.00', + current_total_tax: '0.00', + email: 'henry@wfls.com', + name: '#1017', + order_number: 1017, + order_status_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', + phone: null, + presentment_currency: 'USD', + subtotal_price: '600.00', + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_line_items_price: '600.00', + total_outstanding: '0.00', + total_price: '600.00', + total_tax: '0.00', + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + phone: null, + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + product_id: 7234590408817, + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + }, + ], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + }, + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Order Created', + properties: { + order_id: 5778367414385, + value: '600.00', + tax: '0.00', + currency: 'USD', + products: [ + { + product_id: 7234590408817, + title: 'The Collection Snowboard: Hydrogen', + price: '600.00', + brand: 'Hydrogen Vendor', + quantity: 1, + }, + ], + }, + userId: '7358220173425', + traits: { + email: 'henry@wfls.com', + firstName: 'yodi', + lastName: 'waffles', + address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + state: 'disabled', + currency: 'USD', + taxExemptions: [], + adminGraphqlApiId: 'gid://shopify/Customer/7358220173425', + shippingAddress: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + billingAddress: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + }, + timestamp: '2024-11-06T02:54:50.000Z', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, +].map((d1) => ({ ...d1, mockFns })); diff --git a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts new file mode 100644 index 00000000000..f04fd7e08ee --- /dev/null +++ b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts @@ -0,0 +1,557 @@ +// This file contains the test scenarios for the server-side events from the Shopify GraphQL API for +// the v1 transformation flow +import { mockFns } from '../mocks'; +import { dummySourceConfig } from '../constants'; + +export const genericTrackTestScenarios = [ + { + id: 'c005', + name: 'shopify', + description: 'Track Call -> Cart Update event with no line items from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + query_parameters: { + topic: ['carts_update'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + line_items: [], + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + context: { + integration: { + name: 'SHOPIFY', + }, + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + shopifyDetails: { + created_at: '2024-09-16T03:50:15.478Z', + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + line_items: [], + note: '', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + updated_at: '2024-09-17T08:15:13.280Z', + }, + topic: 'carts_update', + }, + event: 'Cart Update', + integrations: { + SHOPIFY: true, + }, + properties: { + products: [], + }, + type: 'track', + }, + ], + }, + }, + ], + }, + }, + }, + { + id: 'c006', + name: 'shopify', + description: 'Track Call -> Unsupported event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 35550298931313, + query_parameters: { + topic: ['unsupported_event'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + outputToSource: { + body: 'T0s=', + contentType: 'text/plain', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'c007', + name: 'shopify', + description: 'Track Call -> generic event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_total_additional_fees_set: null, + current_total_discounts: '0.00', + current_total_duties_set: null, + current_total_price: '600.00', + current_total_tax: '0.00', + email: 'henry@wfls.com', + merchant_of_record_app_id: null, + name: '#1017', + note: null, + note_attributes: [], + order_number: 1017, + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['bogus'], + phone: null, + po_number: null, + presentment_currency: 'USD', + processed_at: '2024-11-05T21:54:48-05:00', + reference: '4d92cf60cc24a1bd95929e17ead9845f', + referring_site: '', + source_identifier: '4d92cf60cc24a1bd95929e17ead9845f', + subtotal_price: '600.00', + subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_line_items_price: '600.00', + total_outstanding: '0.00', + total_price: '600.00', + total_tax: '0.00', + total_weight: 0, + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + tags: '', + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + admin_graphql_api_id: 'gid://shopify/LineItem/14234727743601', + attributed_staffs: [], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 7234590408817, + properties: [], + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + tax_lines: [], + duties: [], + discount_allocations: [], + }, + ], + refunds: [], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + query_parameters: { + topic: ['orders_paid'], + version: ['pixel'], + writeKey: ['2mw9SN679HngnZkCHT4oSVVBVmb'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'orders_paid', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + shopifyDetails: { + id: 5778367414385, + admin_graphql_api_id: 'gid://shopify/Order/5778367414385', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSkJaTUVRSjgzNUJUN1BTNjEzRFdRUFFQ', + checkout_id: 35550298931313, + checkout_token: '84ad78572dae52a8cbea7d55371afe89', + contact_email: 'henry@wfls.com', + created_at: '2024-11-05T21:54:49-05:00', + currency: 'USD', + current_subtotal_price: '600.00', + current_total_additional_fees_set: null, + current_total_discounts: '0.00', + current_total_duties_set: null, + current_total_price: '600.00', + current_total_tax: '0.00', + email: 'henry@wfls.com', + merchant_of_record_app_id: null, + name: '#1017', + note: null, + note_attributes: [], + order_number: 1017, + original_total_additional_fees_set: null, + original_total_duties_set: null, + payment_gateway_names: ['bogus'], + phone: null, + po_number: null, + presentment_currency: 'USD', + processed_at: '2024-11-05T21:54:48-05:00', + reference: '4d92cf60cc24a1bd95929e17ead9845f', + referring_site: '', + source_identifier: '4d92cf60cc24a1bd95929e17ead9845f', + subtotal_price: '600.00', + subtotal_price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + token: '676613a0027fc8240e16d67fdc9f5ac8', + total_discounts: '0.00', + total_line_items_price: '600.00', + total_outstanding: '0.00', + total_price: '600.00', + total_tax: '0.00', + total_weight: 0, + updated_at: '2024-11-05T21:54:50-05:00', + user_id: null, + billing_address: { + first_name: 'yodi', + address1: 'Yuma Proving Ground', + phone: null, + city: 'Yuma Proving Ground', + zip: '85365', + province: 'Arizona', + country: 'United States', + last_name: 'waffles', + address2: 'suite 001', + company: null, + latitude: 33.0177811, + longitude: -114.2525392, + name: 'yodi waffles', + country_code: 'US', + province_code: 'AZ', + }, + customer: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + state: 'disabled', + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + tags: '', + currency: 'USD', + tax_exemptions: [], + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + line_items: [ + { + id: 14234727743601, + admin_graphql_api_id: 'gid://shopify/LineItem/14234727743601', + attributed_staffs: [], + current_quantity: 1, + fulfillable_quantity: 1, + fulfillment_service: 'manual', + fulfillment_status: null, + gift_card: false, + grams: 0, + name: 'The Collection Snowboard: Hydrogen', + price: '600.00', + price_set: { + shop_money: { + amount: '600.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '600.00', + currency_code: 'USD', + }, + }, + product_exists: true, + product_id: 7234590408817, + properties: [], + quantity: 1, + requires_shipping: true, + sku: '', + taxable: true, + title: 'The Collection Snowboard: Hydrogen', + total_discount: '0.00', + total_discount_set: { + shop_money: { + amount: '0.00', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.00', + currency_code: 'USD', + }, + }, + variant_id: 41327142600817, + variant_inventory_management: 'shopify', + variant_title: null, + vendor: 'Hydrogen Vendor', + tax_lines: [], + duties: [], + discount_allocations: [], + }, + ], + refunds: [], + shipping_address: { + first_name: 'henry', + address1: 'Yuimaru Kitchen', + phone: null, + city: 'Johnson City', + zip: '37604', + province: 'Tennessee', + country: 'United States', + last_name: 'waffles', + address2: '6', + company: null, + latitude: 36.3528845, + longitude: -82.4006335, + name: 'henry waffles', + country_code: 'US', + province_code: 'TN', + }, + }, + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Order Paid', + properties: { + products: [ + { + product_id: 7234590408817, + title: 'The Collection Snowboard: Hydrogen', + price: '600.00', + brand: 'Hydrogen Vendor', + quantity: 1, + }, + ], + }, + traits: { + email: 'henry@wfls.com', + }, + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, +].map((d2) => ({ ...d2, mockFns })); diff --git a/test/integrations/sources/shopify/webhookTestScenarios/IdentifyTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/IdentifyTests.ts new file mode 100644 index 00000000000..b03f5635b6a --- /dev/null +++ b/test/integrations/sources/shopify/webhookTestScenarios/IdentifyTests.ts @@ -0,0 +1,256 @@ +import { mockFns } from '../mocks'; +import { dummySourceConfig } from '../constants'; + +export const identityTestScenarios = [ + { + id: 'c008', + name: 'shopify', + description: 'Identify Call -> Customer update event from Pixel app', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + tags: '', + last_order_name: null, + currency: 'USD', + phone: null, + addresses: [ + { + id: 8715246895217, + customer_id: 7358220173425, + first_name: 'yodi', + last_name: 'waffles', + company: null, + address1: 'Yuma Proving Ground', + address2: 'suite 001', + city: 'Yuma Proving Ground', + province: 'Arizona', + country: 'United States', + zip: '85365', + phone: null, + name: 'yodi waffles', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: false, + }, + ], + tax_exemptions: [], + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + query_parameters: { + topic: ['customers_update'], + version: ['pixel'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + }, + }, + source: dummySourceConfig, + query_parameters: { + topic: ['carts_update'], + writeKey: ['2mw9SN679HngnXXXHT4oSVVBVmb'], + version: ['pixel'], + }, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + eventOrigin: 'server', + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'customers_update', + shopifyDetails: { + id: 7358220173425, + email: 'henry@wfls.com', + created_at: '2024-10-23T16:03:11-04:00', + updated_at: '2024-11-05T21:54:49-05:00', + first_name: 'yodi', + last_name: 'waffles', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + tags: '', + last_order_name: null, + currency: 'USD', + phone: null, + addresses: [ + { + id: 8715246895217, + customer_id: 7358220173425, + first_name: 'yodi', + last_name: 'waffles', + company: null, + address1: 'Yuma Proving Ground', + address2: 'suite 001', + city: 'Yuma Proving Ground', + province: 'Arizona', + country: 'United States', + zip: '85365', + phone: null, + name: 'yodi waffles', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: false, + }, + ], + tax_exemptions: [], + email_marketing_consent: { + state: 'not_subscribed', + opt_in_level: 'single_opt_in', + consent_updated_at: null, + }, + sms_marketing_consent: null, + admin_graphql_api_id: 'gid://shopify/Customer/7358220173425', + default_address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + }, + }, + integrations: { + SHOPIFY: true, + }, + type: 'identify', + userId: '7358220173425', + traits: { + email: 'henry@wfls.com', + firstName: 'yodi', + lastName: 'waffles', + addressList: [ + { + id: 8715246895217, + customer_id: 7358220173425, + first_name: 'yodi', + last_name: 'waffles', + company: null, + address1: 'Yuma Proving Ground', + address2: 'suite 001', + city: 'Yuma Proving Ground', + province: 'Arizona', + country: 'United States', + zip: '85365', + phone: null, + name: 'yodi waffles', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: false, + }, + ], + address: { + id: 8715246862449, + customer_id: 7358220173425, + first_name: 'henry', + last_name: 'waffles', + company: null, + address1: 'Yuimaru Kitchen', + address2: '6', + city: 'Johnson City', + province: 'Tennessee', + country: 'United States', + zip: '37604', + phone: null, + name: 'henry waffles', + province_code: 'TN', + country_code: 'US', + country_name: 'United States', + default: true, + }, + orderCount: 0, + state: 'disabled', + totalSpent: '0.00', + verifiedEmail: true, + taxExempt: false, + tags: '', + currency: 'USD', + taxExemptions: [], + adminGraphqlApiId: 'gid://shopify/Customer/7358220173425', + }, + timestamp: '2024-11-06T02:54:49.000Z', + }, + ], + }, + }, + ], + }, + }, + }, +].map((d3) => ({ ...d3, mockFns })); From a80f87486dc93b423e4fe6efbee6f4cb8330ba02 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:50:00 +0530 Subject: [PATCH 113/147] fix: adding uuid transformation for airship (#3884) * fix: adding uuid transformation for airship * fix: adding doc refs --- package-lock.json | 5 +++-- package.json | 2 +- src/v0/destinations/airship/transform.js | 4 ++++ src/v0/destinations/airship/utils.js | 12 ++++++++++++ .../destinations/airship/processor/data.ts | 6 +++--- 5 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 src/v0/destinations/airship/utils.js diff --git a/package-lock.json b/package-lock.json index 0422078f21e..dd490e88c6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,7 @@ "truncate-utf8-bytes": "^1.0.2", "ua-parser-js": "^1.0.37", "unset-value": "^2.0.1", - "uuid": "^9.0.0", + "uuid": "^9.0.1", "valid-url": "^1.0.9", "zod": "^3.22.4" }, @@ -21872,11 +21872,12 @@ }, "node_modules/uuid": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 907c340cbfb..75a618574c9 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "truncate-utf8-bytes": "^1.0.2", "ua-parser-js": "^1.0.37", "unset-value": "^2.0.1", - "uuid": "^9.0.0", + "uuid": "^9.0.1", "valid-url": "^1.0.9", "zod": "^3.22.4" }, diff --git a/src/v0/destinations/airship/transform.js b/src/v0/destinations/airship/transform.js index 091c9b7f392..dc8543fbc59 100644 --- a/src/v0/destinations/airship/transform.js +++ b/src/v0/destinations/airship/transform.js @@ -24,6 +24,7 @@ const { simpleProcessRouterDest, } = require('../../util'); const { JSON_MIME_TYPE } = require('../../util/constant'); +const { transformSessionId } = require('./utils'); const DEFAULT_ACCEPT_HEADER = 'application/vnd.urbanairship+json; version=3'; @@ -128,6 +129,9 @@ const trackResponseBuilder = async (message, { Config }) => { name = name.toLowerCase(); const payload = constructPayload(message, trackMapping); + if (isDefinedAndNotNullAndNotEmpty(payload.session_id)) { + payload.session_id = transformSessionId(payload.session_id); + } let properties = {}; properties = extractCustomFields(message, properties, ['properties'], AIRSHIP_TRACK_EXCLUSION); if (!isEmptyObject(properties)) { diff --git a/src/v0/destinations/airship/utils.js b/src/v0/destinations/airship/utils.js new file mode 100644 index 00000000000..0ef637245f1 --- /dev/null +++ b/src/v0/destinations/airship/utils.js @@ -0,0 +1,12 @@ +const { v5 } = require('uuid'); + +// ref : https://docs.airship.com/api/ua/#operation-api-custom-events-post +const transformSessionId = (rawSessionId) => { + const NAMESPACE = v5.DNS; + const uuidV5 = v5(rawSessionId, NAMESPACE); + return uuidV5; +}; + +module.exports = { + transformSessionId, +}; diff --git a/test/integrations/destinations/airship/processor/data.ts b/test/integrations/destinations/airship/processor/data.ts index 3a6c5394cb5..a72495d23df 100644 --- a/test/integrations/destinations/airship/processor/data.ts +++ b/test/integrations/destinations/airship/processor/data.ts @@ -2296,7 +2296,7 @@ export const data = [ }, { name: 'airship', - description: 'Test 22', + description: 'Test 22 : session id gets converted to v5 uuid format', feature: 'processor', module: 'destination', version: 'v0', @@ -2321,7 +2321,7 @@ export const data = [ ip: '0.0.0.0', os: { name: '', version: '' }, screen: { density: 2 }, - sessionId: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', + sessionId: '1731403898', }, type: 'track', messageId: '84e26acc-56a5-4835-8233-591137fca468', @@ -2365,7 +2365,7 @@ export const data = [ user: { named_user_id: 'testuserId1' }, body: { name: 'product_clicked', - session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', + session_id: 'd5627eac-795d-5005-9bb4-2c7c0af6cab0', }, }, JSON_ARRAY: {}, From 0aeaa391b025fc68de6e3d63a6721f067c5be318 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Mon, 18 Nov 2024 13:01:26 +0530 Subject: [PATCH 114/147] fix: revert gaec changes (#3885) --- .../transform.js | 35 +--- .../processor/data.ts | 190 ------------------ .../router/data.ts | 189 ----------------- 3 files changed, 5 insertions(+), 409 deletions(-) diff --git a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js index 497d4f294f4..0badf492419 100644 --- a/src/v0/destinations/google_adwords_enhanced_conversions/transform.js +++ b/src/v0/destinations/google_adwords_enhanced_conversions/transform.js @@ -2,11 +2,7 @@ const get = require('get-value'); const { cloneDeep, isNumber } = require('lodash'); -const { - InstrumentationError, - ConfigurationError, - isDefinedAndNotNull, -} = require('@rudderstack/integrations-lib'); +const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const isString = require('lodash/isString'); const { constructPayload, @@ -15,7 +11,6 @@ const { removeHyphens, simpleProcessRouterDest, getAccessToken, - isDefined, } = require('../../util'); const { trackMapping, BASE_ENDPOINT } = require('./config'); @@ -43,15 +38,6 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { const { event } = message; const { subAccount } = Config; let { customerId, loginCustomerId } = Config; - const { configData } = Config; - - if (isDefinedAndNotNull(configData)) { - const configDetails = JSON.parse(configData); - customerId = configDetails.customerId; - if (isDefined(configDetails.loginCustomerId)) { - loginCustomerId = configDetails.loginCustomerId; - } - } if (isNumber(customerId)) { customerId = customerId.toString(); @@ -84,29 +70,18 @@ const responseBuilder = async (metadata, message, { Config }, payload) => { response.headers['login-customer-id'] = filteredLoginCustomerId; } - if (loginCustomerId) { - const filteredLoginCustomerId = removeHyphens(loginCustomerId); - response.headers['login-customer-id'] = filteredLoginCustomerId; - } - return response; }; const processTrackEvent = async (metadata, message, destination) => { - let flag = 0; + let flag = false; const { Config } = destination; const { event } = message; const { listOfConversions } = Config; - if (listOfConversions && listOfConversions.length > 0) { - if (typeof listOfConversions[0] === 'string') { - if (listOfConversions.includes(event)) { - flag = 1; - } - } else if (listOfConversions.some((i) => i.conversions === event)) { - flag = 1; - } + if (listOfConversions.some((i) => i.conversions === event)) { + flag = true; } - if (event === undefined || event === '' || flag === 0) { + if (event === undefined || event === '' || !flag) { throw new ConfigurationError( `Conversion named "${event}" was not specified in the RudderStack destination configuration`, ); diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts index fcdb6f15cae..1d20e887e98 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/processor/data.ts @@ -1720,194 +1720,4 @@ export const data = [ }, }, }, - { - name: 'google_adwords_enhanced_conversions', - description: 'Success test with configDetails', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - metadata: { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - }, - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - listOfConversions: ['Page View', 'Product Added'], - authStatus: 'active', - configData: '{"customerId": "1234567890", "loginCustomerId": ""}', - }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { - phone: '912382193', - firstName: 'John', - lastName: 'Gomes', - city: 'London', - state: 'UK', - countryCode: 'us', - streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', - }, - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - ip: '0.0.0.0', - os: { - name: '', - version: '', - }, - screen: { - density: 2, - }, - }, - event: 'Page View', - type: 'track', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - adjustedValue: '10', - currency: 'INR', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - partialFailure: true, - campaignId: '1', - templateId: '0', - order_id: 10000, - total: 1000, - products: [ - { - product_id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - price: '19', - position: '1', - category: 'cars', - url: 'https://www.example.com/product/path', - image_url: 'https://www.example.com/product/path.jpg', - quantity: '2', - }, - { - product_id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - price: '192', - quantity: 22, - position: '12', - category: 'Cars2', - url: 'https://www.example.com/product/path2', - image_url: 'https://www.example.com/product/path.jpg2', - }, - ], - }, - integrations: { - All: true, - }, - name: 'ApplicationLoaded', - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: `https://googleads.googleapis.com/${API_VERSION}/customers/1234567890:uploadConversionAdjustments`, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - }, - params: { - event: 'Page View', - customerId: '1234567890', - }, - body: { - JSON: { - conversionAdjustments: [ - { - gclidDateTimePair: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - }, - restatementValue: { - adjustedValue: 10, - currencyCode: 'INR', - }, - orderId: '10000', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - userIdentifiers: [ - { - hashedPhoneNumber: - '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', - }, - { - addressInfo: { - hashedFirstName: - 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', - hashedLastName: - '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - state: 'UK', - city: 'London', - countryCode: 'us', - hashedStreetAddress: - '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', - }, - }, - ], - adjustmentType: 'ENHANCEMENT', - }, - ], - partialFailure: true, - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: '', - }, - metadata: { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - }, - statusCode: 200, - }, - ], - }, - }, - }, ]; diff --git a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts index fe0acf79647..5ac05b5a530 100644 --- a/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_enhanced_conversions/router/data.ts @@ -1,5 +1,3 @@ -import { API_VERSION } from '../../../../../src/v0/destinations/google_adwords_enhanced_conversions/config'; - const events = [ { metadata: { @@ -413,100 +411,6 @@ const events = [ sentAt: '2019-10-14T11:15:53.296Z', }, }, - { - metadata: { - secret: { - access_token: 'abcd1234', - refresh_token: 'efgh5678', - developer_token: 'ijkl91011', - }, - jobId: 6, - userId: 'u1', - }, - destination: { - Config: { - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', - customerId: '1234567890', - subAccount: true, - listOfConversions: [{ conversions: 'Page View' }, { conversions: 'Product Added' }], - authStatus: 'active', - }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { - phone: '912382193', - firstName: 'John', - lastName: 'Gomes', - city: 'London', - state: 'UK', - streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, - customerID: {}, - subaccountID: 11, - }, - event: 'Page View', - type: 'track', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - gclid: 'gclid1234', - conversionDateTime: '2022-01-01 12:32:45-08:00', - adjustedValue: '10', - currency: 'INR', - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - partialFailure: true, - campaignId: '1', - templateId: '0', - order_id: 10000, - total: 1000, - products: [ - { - product_id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - price: '19', - position: '1', - category: 'cars', - url: 'https://www.example.com/product/path', - image_url: 'https://www.example.com/product/path.jpg', - quantity: '2', - }, - { - product_id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - price: '192', - quantity: 22, - position: '12', - category: 'Cars2', - url: 'https://www.example.com/product/path2', - image_url: 'https://www.example.com/product/path.jpg2', - }, - ], - }, - integrations: { All: true }, - name: 'ApplicationLoaded', - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, { metadata: { secret: { @@ -1012,99 +916,6 @@ export const data = [ module: 'destination', }, }, - { - batched: false, - batchedRequest: { - body: { - FORM: {}, - JSON: { - conversionAdjustments: [ - { - adjustmentDateTime: '2022-01-01 12:32:45-08:00', - adjustmentType: 'ENHANCEMENT', - gclidDateTimePair: { - conversionDateTime: '2022-01-01 12:32:45-08:00', - gclid: 'gclid1234', - }, - orderId: '10000', - restatementValue: { - adjustedValue: 10, - currencyCode: 'INR', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - userIdentifiers: [ - { - hashedPhoneNumber: - '04387707e6cbed8c4538c81cc570ed9252d579469f36c273839b26d784e4bdbe', - }, - { - addressInfo: { - city: 'London', - hashedFirstName: - 'a8cfcd74832004951b4408cdb0a5dbcd8c7e52d43f7fe244bf720582e05241da', - hashedLastName: - '1c574b17eefa532b6d61c963550a82d2d3dfca4a7fb69e183374cfafd5328ee4', - hashedStreetAddress: - '9a4d2e50828448f137f119a3ebdbbbab8d6731234a67595fdbfeb2a2315dd550', - state: 'UK', - }, - }, - ], - }, - ], - partialFailure: true, - }, - JSON_ARRAY: {}, - XML: {}, - }, - endpoint: - 'https://googleads.googleapis.com/v17/customers/1234567890:uploadConversionAdjustments', - files: {}, - headers: { - Authorization: 'Bearer abcd1234', - 'Content-Type': 'application/json', - 'developer-token': 'ijkl91011', - 'login-customer-id': '65656565', - }, - method: 'POST', - params: { - customerId: '1234567890', - event: 'Page View', - }, - type: 'REST', - version: '1', - }, - destination: { - Config: { - authStatus: 'active', - configData: '{"customerId":"1234567890", "loginCustomerId":"65656565"}', - customerId: '1234567890', - listOfConversions: [ - { - conversions: 'Page View', - }, - { - conversions: 'Product Added', - }, - ], - rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', - subAccount: true, - }, - }, - metadata: [ - { - jobId: 6, - secret: { - access_token: 'abcd1234', - developer_token: 'ijkl91011', - refresh_token: 'efgh5678', - }, - userId: 'u1', - }, - ], - statusCode: 200, - }, { batched: false, destination: { From f3ff4092d455508dd3354ffb22d345fa97f4d1f2 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:52:34 +0530 Subject: [PATCH 115/147] feat: onboard linkedin audience destination (#3857) * feat: onboard linkedin audience destination * chore: resolve conflicts * chore: add test cases * chore: fix lint errors * refactor: linkedin audiences proc workflow --------- Co-authored-by: Dilip Kola --- .../destinations/linkedin_audience/config.ts | 10 + .../linkedin_audience/procWorkflow.yaml | 89 +++ .../linkedin_audience/rtWorkflow.yaml | 40 ++ .../destinations/linkedin_audience/utils.ts | 87 +++ src/features.ts | 1 + .../linkedin_audience/processor/business.ts | 520 ++++++++++++++++++ .../linkedin_audience/processor/data.ts | 3 + .../linkedin_audience/processor/validation.ts | 396 +++++++++++++ .../linkedin_audience/router/data.ts | 384 +++++++++++++ test/integrations/testUtils.ts | 24 + 10 files changed, 1554 insertions(+) create mode 100644 src/cdk/v2/destinations/linkedin_audience/config.ts create mode 100644 src/cdk/v2/destinations/linkedin_audience/procWorkflow.yaml create mode 100644 src/cdk/v2/destinations/linkedin_audience/rtWorkflow.yaml create mode 100644 src/cdk/v2/destinations/linkedin_audience/utils.ts create mode 100644 test/integrations/destinations/linkedin_audience/processor/business.ts create mode 100644 test/integrations/destinations/linkedin_audience/processor/data.ts create mode 100644 test/integrations/destinations/linkedin_audience/processor/validation.ts create mode 100644 test/integrations/destinations/linkedin_audience/router/data.ts diff --git a/src/cdk/v2/destinations/linkedin_audience/config.ts b/src/cdk/v2/destinations/linkedin_audience/config.ts new file mode 100644 index 00000000000..86ea94425a5 --- /dev/null +++ b/src/cdk/v2/destinations/linkedin_audience/config.ts @@ -0,0 +1,10 @@ +export const SUPPORTED_EVENT_TYPE = 'record'; +export const ACTION_TYPES = ['insert', 'delete']; +export const BASE_ENDPOINT = 'https://api.linkedin.com/rest'; +export const USER_ENDPOINT = '/dmpSegments/audienceId/users'; +export const COMPANY_ENDPOINT = '/dmpSegments/audienceId/companies'; +export const FIELD_MAP = { + sha256Email: 'SHA256_EMAIL', + sha512Email: 'SHA512_EMAIL', + googleAid: 'GOOGLE_AID', +}; diff --git a/src/cdk/v2/destinations/linkedin_audience/procWorkflow.yaml b/src/cdk/v2/destinations/linkedin_audience/procWorkflow.yaml new file mode 100644 index 00000000000..f3f4ce07726 --- /dev/null +++ b/src/cdk/v2/destinations/linkedin_audience/procWorkflow.yaml @@ -0,0 +1,89 @@ +bindings: + - path: ./config + exportAll: true + - path: ./utils + exportAll: true + - name: defaultRequestConfig + path: ../../../../v0/util + +steps: + - name: validateInput + description: Validate input, if all the required fields are available or not. + template: | + const config = .connection.config.destination; + const secret = .metadata.secret; + let messageType = .message.type; + $.assertConfig(config.audienceId, "Audience Id is not present. Aborting"); + $.assertConfig(secret.accessToken, "Access Token is not present. Aborting"); + $.assertConfig(config.audienceType, "audienceType is not present. Aborting"); + $.assert(messageType, "Message Type is not present. Aborting message."); + $.assert(messageType.toLowerCase() === $.SUPPORTED_EVENT_TYPE, `Event type ${.message.type.toLowerCase()} is not supported. Aborting message.`); + $.assert(.message.fields, "`fields` is not present. Aborting message."); + $.assert(.message.identifiers, "`identifiers` is not present inside properties. Aborting message."); + $.assert($.containsAll([.message.action], $.ACTION_TYPES), "Unsupported action type. Aborting message.") + + - name: getConfigs + description: This step fetches the configs from different places and combines them. + template: | + const config = .connection.config.destination; + { + audienceType: config.audienceType, + audienceId: config.audienceId, + accessToken: .metadata.secret.accessToken, + isHashRequired: config.isHashRequired, + } + + - name: prepareUserTypeBasePayload + condition: $.outputs.getConfigs.audienceType === 'user' + steps: + - name: prepareUserIds + description: Prepare user ids for user audience type + template: | + const identifiers = $.outputs.getConfigs.isHashRequired === true ? + $.hashIdentifiers(.message.identifiers) : + .message.identifiers; + $.prepareUserIds(identifiers) + + - name: preparePayload + description: Prepare base payload for user audiences + template: | + const payload = { + 'elements': [ + { + 'action': $.generateActionType(.message.action), + 'userIds': $.outputs.prepareUserTypeBasePayload.prepareUserIds, + ....message.fields + } + ] + } + payload; + + - name: prepareCompanyTypeBasePayload + description: Prepare base payload for company audiences + condition: $.outputs.getConfigs.audienceType === 'company' + template: | + const payload = { + 'elements': [ + { + 'action': $.generateActionType(.message.action), + ....message.identifiers, + ....message.fields + } + ] + } + payload; + + - name: buildResponseForProcessTransformation + description: build response depending upon batch size + template: | + const response = $.defaultRequestConfig(); + response.body.JSON = {...$.outputs.prepareUserTypeBasePayload, ...$.outputs.prepareCompanyTypeBasePayload}; + response.endpoint = $.generateEndpoint($.outputs.getConfigs.audienceType, $.outputs.getConfigs.audienceId); + response.headers = { + "Authorization": "Bearer " + $.outputs.getConfigs.accessToken, + "Content-Type": "application/json", + "X-RestLi-Method": "BATCH_CREATE", + "X-Restli-Protocol-Version": "2.0.0", + "LinkedIn-Version": "202409" + }; + response; diff --git a/src/cdk/v2/destinations/linkedin_audience/rtWorkflow.yaml b/src/cdk/v2/destinations/linkedin_audience/rtWorkflow.yaml new file mode 100644 index 00000000000..fe16ab786a5 --- /dev/null +++ b/src/cdk/v2/destinations/linkedin_audience/rtWorkflow.yaml @@ -0,0 +1,40 @@ +bindings: + - path: ./utils + - name: handleRtTfSingleEventError + path: ../../../../v0/util/index + +steps: + - name: validateInput + template: | + $.assert(Array.isArray(^) && ^.length > 0, "Invalid event array") + + - name: transform + externalWorkflow: + path: ./procWorkflow.yaml + bindings: + - name: batchMode + value: true + loopOverInput: true + + - name: successfulEvents + template: | + $.outputs.transform#idx.output.({ + "message": .[], + "destination": ^ [idx].destination, + "metadata": ^ [idx].metadata + })[] + + - name: failedEvents + template: | + $.outputs.transform#idx.error.( + $.handleRtTfSingleEventError(^[idx], .originalError ?? ., {}) + )[] + + - name: batchSuccessfulEvents + description: Batches the successfulEvents + template: | + $.batchResponseBuilder($.outputs.successfulEvents); + + - name: finalPayload + template: | + [...$.outputs.batchSuccessfulEvents, ...$.outputs.failedEvents] diff --git a/src/cdk/v2/destinations/linkedin_audience/utils.ts b/src/cdk/v2/destinations/linkedin_audience/utils.ts new file mode 100644 index 00000000000..12f5a0572b8 --- /dev/null +++ b/src/cdk/v2/destinations/linkedin_audience/utils.ts @@ -0,0 +1,87 @@ +import lodash from 'lodash'; +import { hashToSha256 } from '@rudderstack/integrations-lib'; +import { createHash } from 'crypto'; +import { BASE_ENDPOINT, COMPANY_ENDPOINT, FIELD_MAP, USER_ENDPOINT } from './config'; + +export function hashIdentifiers(identifiers: string[]): Record { + const hashedIdentifiers = {}; + Object.keys(identifiers).forEach((key) => { + if (key === 'sha256Email') { + hashedIdentifiers[key] = hashToSha256(identifiers[key]); + } else if (key === 'sha512Email') { + hashedIdentifiers[key] = createHash('sha512').update(identifiers[key]).digest('hex'); + } else { + hashedIdentifiers[key] = identifiers[key]; + } + }); + return hashedIdentifiers; +} + +export function prepareUserIds( + identifiers: Record, +): { idType: string; idValue: string }[] { + const userIds: { idType: string; idValue: string }[] = []; + Object.keys(identifiers).forEach((key) => { + userIds.push({ idType: FIELD_MAP[key], idValue: identifiers[key] }); + }); + return userIds; +} + +export function generateEndpoint(audienceType: string, audienceId: string) { + if (audienceType === 'user') { + return BASE_ENDPOINT + USER_ENDPOINT.replace('audienceId', audienceId); + } + return BASE_ENDPOINT + COMPANY_ENDPOINT.replace('audienceId', audienceId); +} + +export function batchResponseBuilder(successfulEvents) { + const chunkOnActionType = lodash.groupBy( + successfulEvents, + (event) => event.message[0].body.JSON.elements[0].action, + ); + const result: any = []; + Object.keys(chunkOnActionType).forEach((actionType) => { + const firstEvent = chunkOnActionType[actionType][0]; + const { method, endpoint, headers, type, version } = firstEvent.message[0]; + const batchEvent = { + batchedRequest: { + body: { + JSON: { elements: firstEvent.message[0].body.JSON.elements }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version, + type, + method, + endpoint, + headers, + params: {}, + files: {}, + }, + metadata: [firstEvent.metadata], + batched: true, + statusCode: 200, + destination: firstEvent.destination, + }; + firstEvent.metadata = [firstEvent.metadata]; + chunkOnActionType[actionType].forEach((element, index) => { + if (index !== 0) { + batchEvent.batchedRequest.body.JSON.elements.push(element.message[0].body.JSON.elements[0]); + batchEvent.metadata.push(element.metadata); + } + }); + result.push(batchEvent); + }); + return result; +} + +export const generateActionType = (actionType: string): string => { + if (actionType === 'insert') { + return 'ADD'; + } + if (actionType === 'delete') { + return 'REMOVE'; + } + return actionType; +}; diff --git a/src/features.ts b/src/features.ts index 9f60d444836..4ff419a7fe2 100644 --- a/src/features.ts +++ b/src/features.ts @@ -92,6 +92,7 @@ const defaultFeaturesConfig: FeaturesConfig = { HTTP: true, AMAZON_AUDIENCE: true, INTERCOM_V2: true, + LINKEDIN_AUDIENCE: true, }, regulations: [ 'BRAZE', diff --git a/test/integrations/destinations/linkedin_audience/processor/business.ts b/test/integrations/destinations/linkedin_audience/processor/business.ts new file mode 100644 index 00000000000..28cb6a9a97b --- /dev/null +++ b/test/integrations/destinations/linkedin_audience/processor/business.ts @@ -0,0 +1,520 @@ +import { ProcessorTestData } from '../../../testTypes'; +import { generateMetadata, generateRecordPayload } from '../../../testUtils'; + +export const businessTestData: ProcessorTestData[] = [ + { + id: 'linkedin_audience-business-test-1', + name: 'linkedin_audience', + description: 'Record call : non string values provided as email', + scenario: 'Business', + successCriteria: 'should fail with 400 status code and error message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 12345, + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'The "string" argument must be of type string. Received type number (12345): Workflow: procWorkflow, Step: prepareUserTypeBasePayload, ChildStep: prepareUserIds, OriginalError: The "string" argument must be of type string. Received type number (12345)', + metadata: generateMetadata(1), + statTags: { + destType: 'LINKEDIN_AUDIENCE', + destinationId: 'default-destinationId', + errorCategory: 'transformation', + feature: 'processor', + implementation: 'cdkV2', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + statusCode: 500, + }, + ], + }, + }, + }, + { + id: 'linkedin_audience-business-test-2', + name: 'linkedin_audience', + description: 'Record call : Valid event without any field mappings', + scenario: 'Business', + successCriteria: 'should pass with 200 status code and transformed message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: {}, + identifiers: { + sha256Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + output: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/32589526/users', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'linkedin_audience-business-test-2', + name: 'linkedin_audience', + description: 'Record call : customer provided hashed value and isHashRequired is false', + scenario: 'Business', + successCriteria: 'should pass with 200 status code and transformed message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: {}, + identifiers: { + sha256Email: '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + sha512Email: + '631372c5eafe80f3fe1b5d067f6a1870f1f04a0f0c0d9298eeaa20b9e54224da9588e3164d2ec6e2a5545a5299ed7df563e4a60315e6782dfa7db4de6b1c5326', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: false, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + output: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + }, + { + idType: 'SHA512_EMAIL', + idValue: + '631372c5eafe80f3fe1b5d067f6a1870f1f04a0f0c0d9298eeaa20b9e54224da9588e3164d2ec6e2a5545a5299ed7df563e4a60315e6782dfa7db4de6b1c5326', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/32589526/users', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'linkedin_audience-business-test-2', + name: 'linkedin_audience', + description: 'Record call : event with company audience details', + scenario: 'Business', + successCriteria: 'should pass with 200 status code and transformed message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: { + city: 'Dhaka', + state: 'Dhaka', + industries: 'Information Technology', + postalCode: '123456', + }, + identifiers: { + companyName: 'Rudderstack', + organizationUrn: 'urn:li:organization:456', + companyWebsiteDomain: 'rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'company', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'city', + to: 'city', + }, + { + from: 'state', + to: 'state', + }, + { + from: 'domain', + to: 'industries', + }, + { + from: 'psCode', + to: 'postalCode', + }, + ], + identifierMappings: [ + { + from: 'name', + to: 'companyName', + }, + { + from: 'urn', + to: 'organizationUrn', + }, + { + from: 'Website Domain', + to: 'companyWebsiteDomain', + }, + ], + isHashRequired: false, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + output: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + city: 'Dhaka', + companyName: 'Rudderstack', + companyWebsiteDomain: 'rudderstack.com', + industries: 'Information Technology', + organizationUrn: 'urn:li:organization:456', + postalCode: '123456', + state: 'Dhaka', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/32589526/companies', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/linkedin_audience/processor/data.ts b/test/integrations/destinations/linkedin_audience/processor/data.ts new file mode 100644 index 00000000000..233a9dcf861 --- /dev/null +++ b/test/integrations/destinations/linkedin_audience/processor/data.ts @@ -0,0 +1,3 @@ +import { businessTestData } from './business'; +import { validationTestData } from './validation'; +export const data = [...validationTestData, ...businessTestData]; diff --git a/test/integrations/destinations/linkedin_audience/processor/validation.ts b/test/integrations/destinations/linkedin_audience/processor/validation.ts new file mode 100644 index 00000000000..3ad37b2f4de --- /dev/null +++ b/test/integrations/destinations/linkedin_audience/processor/validation.ts @@ -0,0 +1,396 @@ +import { ProcessorTestData } from '../../../testTypes'; +import { generateMetadata, generateRecordPayload } from '../../../testUtils'; + +export const validationTestData: ProcessorTestData[] = [ + { + id: 'linkedin_audience-validation-test-1', + name: 'linkedin_audience', + description: 'Record call : event is valid with all required elements', + scenario: 'Validation', + successCriteria: 'should pass with 200 status code and transformed message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 'random@rudderstack.com', + sha512Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + output: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + company: 'Rudderlabs', + country: 'Dhaka', + firstName: 'Test', + lastName: 'User', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + }, + { + idType: 'SHA512_EMAIL', + idValue: + '631372c5eafe80f3fe1b5d067f6a1870f1f04a0f0c0d9298eeaa20b9e54224da9588e3164d2ec6e2a5545a5299ed7df563e4a60315e6782dfa7db4de6b1c5326', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/32589526/users', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'linkedin_audience-validation-test-2', + name: 'linkedin_audience', + description: 'Record call : event is not valid with all required elements', + scenario: 'Validation', + successCriteria: 'should fail with 400 status code and error message', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 'random@rudderstack.com', + sha512Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'Audience Id is not present. Aborting: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: Audience Id is not present. Aborting', + metadata: generateMetadata(1), + statTags: { + destType: 'LINKEDIN_AUDIENCE', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'cdkV2', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + statusCode: 400, + }, + ], + }, + }, + }, + { + id: 'linkedin_audience-validation-test-3', + name: 'linkedin_audience', + description: 'Record call : isHashRequired is not provided', + scenario: 'Validation', + successCriteria: + 'should succeed with 200 status code and transformed message with provided values of identifiers', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 'random@rudderstack.com', + sha512Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 1234, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + }, + source: {}, + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: generateMetadata(1), + output: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + company: 'Rudderlabs', + country: 'Dhaka', + firstName: 'Test', + lastName: 'User', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: 'random@rudderstack.com', + }, + { + idType: 'SHA512_EMAIL', + idValue: 'random@rudderstack.com', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/1234/users', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + userId: '', + version: '1', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/linkedin_audience/router/data.ts b/test/integrations/destinations/linkedin_audience/router/data.ts new file mode 100644 index 00000000000..c76d3e84c6f --- /dev/null +++ b/test/integrations/destinations/linkedin_audience/router/data.ts @@ -0,0 +1,384 @@ +import { generateMetadata, generateRecordPayload } from '../../../testUtils'; + +export const data = [ + { + name: 'linkedin_audience', + description: 'Test 0', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 'random@rudderstack.com', + sha512Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(1), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + { + message: generateRecordPayload({ + fields: {}, + identifiers: { + sha256Email: 'random@rudderstack.com', + }, + action: 'insert', + }), + metadata: generateMetadata(2), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + { + message: generateRecordPayload({ + fields: { + firstName: 'Test', + lastName: 'User', + country: 'Dhaka', + company: 'Rudderlabs', + }, + identifiers: { + sha256Email: 12345, + }, + action: 'insert', + }), + metadata: generateMetadata(3), + destination: { + ID: '123', + Name: 'Linkedin Audience', + DestinationDefinition: { + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + DisplayName: 'Linkedin Audience', + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + Enabled: true, + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + Transformations: [], + }, + connection: { + sourceId: 'randomSourceId', + destinationId: 'randomDestinationId', + enabled: true, + config: { + destination: { + accountId: 512315509, + audienceId: 32589526, + audienceType: 'user', + createAudience: 'no', + eventType: 'record', + fieldMappings: [ + { + from: 'name', + to: 'firstName', + }, + { + from: 'name', + to: 'lastName', + }, + ], + identifierMappings: [ + { + from: 'email', + to: 'sha256Email', + }, + { + from: 'email', + to: 'sha512Email', + }, + ], + isHashRequired: true, + }, + source: {}, + }, + }, + }, + ], + destType: 'linkedin_audience', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batched: true, + batchedRequest: { + body: { + FORM: {}, + JSON: { + elements: [ + { + action: 'ADD', + company: 'Rudderlabs', + country: 'Dhaka', + firstName: 'Test', + lastName: 'User', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + }, + { + idType: 'SHA512_EMAIL', + idValue: + '631372c5eafe80f3fe1b5d067f6a1870f1f04a0f0c0d9298eeaa20b9e54224da9588e3164d2ec6e2a5545a5299ed7df563e4a60315e6782dfa7db4de6b1c5326', + }, + ], + }, + { + action: 'ADD', + userIds: [ + { + idType: 'SHA256_EMAIL', + idValue: + '52ac4b9ef8f745e007c19fac81ddb0a3f50b20029f6699ca1406225fc217f392', + }, + ], + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: 'https://api.linkedin.com/rest/dmpSegments/32589526/users', + files: {}, + headers: { + Authorization: 'Bearer default-accessToken', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202409', + 'X-RestLi-Method': 'BATCH_CREATE', + 'X-Restli-Protocol-Version': '2.0.0', + }, + method: 'POST', + params: {}, + type: 'REST', + version: '1', + }, + destination: { + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + DisplayName: 'Linkedin Audience', + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + }, + Enabled: true, + ID: '123', + Name: 'Linkedin Audience', + Transformations: [], + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + }, + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 1, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 2, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + ], + statusCode: 200, + }, + { + batched: false, + destination: { + Config: { + connectionMode: 'cloud', + rudderAccountId: '2nmIV6FMXvyyqRM9Ifj8V92yElu', + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + DisplayName: 'Linkedin Audience', + ID: '2njmJIfG6JH3guvFHSjLQNiIYh5', + Name: 'LINKEDIN_AUDIENCE', + }, + Enabled: true, + ID: '123', + Name: 'Linkedin Audience', + Transformations: [], + WorkspaceID: '2lepjs3uWK6ac2WLukJjOrbcTfC', + }, + error: 'The "string" argument must be of type string. Received type number (12345)', + metadata: [ + { + attemptNum: 1, + destinationId: 'default-destinationId', + dontBatch: false, + jobId: 3, + secret: { + accessToken: 'default-accessToken', + }, + sourceId: 'default-sourceId', + userId: 'default-userId', + workspaceId: 'default-workspaceId', + }, + ], + statTags: { + destType: 'LINKEDIN_AUDIENCE', + destinationId: 'default-destinationId', + errorCategory: 'transformation', + feature: 'router', + implementation: 'cdkV2', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + statusCode: 500, + }, + ], + }, + }, + }, + }, +]; diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index 4eda20a9011..7e6e6b9acbb 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -237,6 +237,30 @@ export const generateTrackPayload: any = (parametersOverride: any) => { return removeUndefinedAndNullValues(payload); }; +export const generateRecordPayload: any = (parametersOverride: any) => { + const payload = { + type: 'record', + action: parametersOverride.action || 'insert', + fields: parametersOverride.fields || {}, + channel: 'sources', + context: { + sources: { + job_id: 'randomJobId', + version: 'local', + job_run_id: 'jobRunId', + task_run_id: 'taskRunId', + }, + }, + recordId: '3', + rudderId: 'randomRudderId', + messageId: 'randomMessageId', + receivedAt: '2024-11-08T10:30:41.618+05:30', + request_ip: '[::1]', + identifiers: parametersOverride.identifiers || {}, + }; + return removeUndefinedAndNullValues(payload); +}; + export const generateSimplifiedTrackPayload: any = (parametersOverride: any) => { return removeUndefinedAndNullValues({ type: 'track', From d57f48e989d18d469bea0de94293bc685300945b Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:58:49 +0530 Subject: [PATCH 116/147] fix: handling invalid timestamp for adjust source (#3866) * fix: handling invalid timestamp for adjust source * fix: small change in logic * fix: unnecessary line removal * fix: unnecessary line removal * fix: review comment addressed * fix: review comment addressed * chore: add edge testcase - update error messages * fix: testcase error message --------- Co-authored-by: Sai Sankeerth --- src/v0/sources/adjust/transform.js | 4 +- src/v0/sources/adjust/utils.js | 27 ++++++++++++ src/v0/sources/adjust/utils.test.js | 37 +++++++++++++++++ test/integrations/sources/adjust/data.ts | 53 ++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/v0/sources/adjust/utils.js create mode 100644 src/v0/sources/adjust/utils.test.js diff --git a/src/v0/sources/adjust/transform.js b/src/v0/sources/adjust/transform.js index 9da90751b7c..f68e87d4764 100644 --- a/src/v0/sources/adjust/transform.js +++ b/src/v0/sources/adjust/transform.js @@ -7,6 +7,7 @@ const Message = require('../message'); const { CommonUtils } = require('../../../util/common'); const { excludedFieldList } = require('./config'); const { extractCustomFields, generateUUID } = require('../../util'); +const { convertToISODate } = require('./utils'); // ref : https://help.adjust.com/en/article/global-callbacks#general-recommended-placeholders // import mapping json using JSON.parse to preserve object key order @@ -43,11 +44,10 @@ const processEvent = (inputEvent) => { message.properties = { ...message.properties, ...customProperties }; if (formattedPayload.created_at) { - const ts = new Date(formattedPayload.created_at * 1000).toISOString(); + const ts = convertToISODate(formattedPayload.created_at); message.setProperty('originalTimestamp', ts); message.setProperty('timestamp', ts); } - // adjust does not has the concept of user but we need to set some random anonymousId in order to make the server accept the message message.anonymousId = generateUUID(); return message; diff --git a/src/v0/sources/adjust/utils.js b/src/v0/sources/adjust/utils.js new file mode 100644 index 00000000000..73ec696e342 --- /dev/null +++ b/src/v0/sources/adjust/utils.js @@ -0,0 +1,27 @@ +const { TransformationError } = require('@rudderstack/integrations-lib'); + +const convertToISODate = (rawTimestamp) => { + if (typeof rawTimestamp !== 'number' && typeof rawTimestamp !== 'string') { + throw new TransformationError( + `Invalid timestamp type: expected number or string, received ${typeof rawTimestamp}`, + ); + } + + const createdAt = Number(rawTimestamp); + + if (Number.isNaN(createdAt)) { + throw new TransformationError(`Failed to parse timestamp: "${rawTimestamp}"`); + } + + const date = new Date(createdAt * 1000); + + if (Number.isNaN(date.getTime())) { + throw new TransformationError(`Failed to create valid date for timestamp "${rawTimestamp}"`); + } + + return date.toISOString(); +}; + +module.exports = { + convertToISODate, +}; diff --git a/src/v0/sources/adjust/utils.test.js b/src/v0/sources/adjust/utils.test.js new file mode 100644 index 00000000000..f5a0caa832b --- /dev/null +++ b/src/v0/sources/adjust/utils.test.js @@ -0,0 +1,37 @@ +const { convertToISODate } = require('./utils'); +const { TransformationError } = require('@rudderstack/integrations-lib'); + +describe('convertToISODate', () => { + // Converts valid numeric timestamp to ISO date string + it('should return ISO date string when given a valid numeric timestamp', () => { + const timestamp = 1633072800; // Example timestamp for 2021-10-01T00:00:00.000Z + const result = convertToISODate(timestamp); + expect(result).toBe('2021-10-01T07:20:00.000Z'); + }); + + // Throws error for non-numeric string input + it('should throw TransformationError when given a non-numeric string', () => { + const invalidTimestamp = 'invalid'; + expect(() => convertToISODate(invalidTimestamp)).toThrow(TransformationError); + }); + + // Converts valid numeric string timestamp to ISO date string + it('should convert valid numeric string timestamp to ISO date string', () => { + const rawTimestamp = '1633072800'; // Corresponds to 2021-10-01T00:00:00.000Z + const result = convertToISODate(rawTimestamp); + expect(result).toBe('2021-10-01T07:20:00.000Z'); + }); + + // Throws error for non-number and non-string input + it('should throw error for non-number and non-string input', () => { + expect(() => convertToISODate({})).toThrow(TransformationError); + expect(() => convertToISODate([])).toThrow(TransformationError); + expect(() => convertToISODate(null)).toThrow(TransformationError); + expect(() => convertToISODate(undefined)).toThrow(TransformationError); + }); + + it('should throw error for timestamp that results in invalid date when multiplied', () => { + const hugeTimestamp = 999999999999999; // This will become invalid when multiplied by 1000 + expect(() => convertToISODate(hugeTimestamp)).toThrow(TransformationError); + }); +}); diff --git a/test/integrations/sources/adjust/data.ts b/test/integrations/sources/adjust/data.ts index e57feb45d43..107bb444c43 100644 --- a/test/integrations/sources/adjust/data.ts +++ b/test/integrations/sources/adjust/data.ts @@ -125,4 +125,57 @@ export const data = [ defaultMockFns(); }, }, + { + name: 'adjust', + description: 'Simple track call with wrong created at', + module: 'source', + version: 'v0', + skipGo: 'FIXME', + input: { + request: { + body: [ + { + id: 'adjust', + query_parameters: { + gps_adid: ['38400000-8cf0-11bd-b23e-10b96e40000d'], + adid: ['18546f6171f67e29d1cb983322ad1329'], + tracker_token: ['abc'], + custom: ['custom'], + tracker_name: ['dummy'], + created_at: ['test'], + event_name: ['Click'], + }, + updated_at: '2023-02-10T12:16:07.251Z', + created_at: 'test', + }, + ], + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Failed to parse timestamp: "test"', + statTags: { + destinationId: 'Non determinable', + errorCategory: 'transformation', + implementation: 'native', + module: 'source', + workspaceId: 'Non determinable', + }, + statusCode: 400, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, ]; From 85202781de3464bd46fe910159d2b143cd4209e8 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:03:33 +0530 Subject: [PATCH 117/147] feat: update pinterest_tag single product events with new mapping (#3858) * feat: update pinterest_tag single product events with new mapping * chore: use toString function from integrations-lib * chore: update integrations-lib library --- package-lock.json | 9 +++-- package.json | 2 +- .../pinterest_tag/procWorkflow.yaml | 40 +++++++++++-------- .../data_scenarios/cdk_v2/failure.json | 8 ++++ .../data_scenarios/cdk_v2/success.json | 12 ++++++ .../proc/batch_input_multiplex.json | 12 ++++++ .../proc/multiplex_partial_failure.json | 8 ++++ .../destination/proc/multiplex_success.json | 8 ++++ .../destination/router/failure_test.json | 8 ++++ .../pinterest_tag/processor/data.ts | 11 +++-- .../destinations/pinterest_tag/router/data.ts | 2 +- .../destinations/pinterest_tag/step/data.ts | 7 ++-- 12 files changed, 94 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index dd490e88c6a..d10997f1439 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@koa/router": "^12.0.0", "@ndhoule/extend": "^2.0.0", "@pyroscope/nodejs": "^0.2.9", - "@rudderstack/integrations-lib": "^0.2.12", + "@rudderstack/integrations-lib": "^0.2.13", "@rudderstack/json-template-engine": "^0.18.0", "@rudderstack/workflow-engine": "^0.8.13", "@shopify/jest-koa-mocks": "^5.1.1", @@ -6602,9 +6602,10 @@ } }, "node_modules/@rudderstack/integrations-lib": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@rudderstack/integrations-lib/-/integrations-lib-0.2.12.tgz", - "integrity": "sha512-xy+T9SHFkSeVDd4svGOyrTtIGljZ/l4qUh5o5EQWk3dTStzaV9mKnbXLsG62kEO3aTmCVg+VYr4OPwZY2+6rxQ==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@rudderstack/integrations-lib/-/integrations-lib-0.2.13.tgz", + "integrity": "sha512-MBI+OQpnYAuOzRlbGCnUX6oVfQsYA7daZ8z07WmqQYQtWFOfd2yFbaxKclu+R/a8W7+jBo4gvbW+ScEW6h+Mgg==", + "license": "MIT", "dependencies": { "axios": "^1.4.0", "axios-mock-adapter": "^1.22.0", diff --git a/package.json b/package.json index 75a618574c9..92ac9f0fb9b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@koa/router": "^12.0.0", "@ndhoule/extend": "^2.0.0", "@pyroscope/nodejs": "^0.2.9", - "@rudderstack/integrations-lib": "^0.2.12", + "@rudderstack/integrations-lib": "^0.2.13", "@rudderstack/json-template-engine": "^0.18.0", "@rudderstack/workflow-engine": "^0.8.13", "@shopify/jest-koa-mocks": "^5.1.1", diff --git a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml index 64d391c8882..aebb7b06675 100644 --- a/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml +++ b/src/cdk/v2/destinations/pinterest_tag/procWorkflow.yaml @@ -11,6 +11,8 @@ bindings: path: ../../../../v0/util - name: validateEventName path: ../../../../v0/util + - path: '@rudderstack/integrations-lib' + steps: - name: checkIfProcessed condition: .message.statusCode @@ -67,9 +69,9 @@ steps: "event_id": $.getOneByPaths(., ^.destination.Config.deduplicationKey) ?? .messageId, "app_id": ^.destination.Config.appId, "advertiser_id": ^.destination.Config.advertiserId, - "partner_name": .properties.partnerName, - "device_carrier": .context.network.carrier, - "wifi": .context.network.wifi + "partner_name": .properties.partnerName ? $.convertToString(.properties.partnerName) : undefined, + "device_carrier": .properties.partnerName ? $.convertToString(.context.network.carrier) : undefined, + "wifi": .context.network.wifi ? Boolean(.context.network.wifi) : undefined }); $.outputs.apiVersion === {{$.API_VERSION.v5}} ? commonFields = commonFields{~["advertiser_id"]}; $.removeUndefinedValues(commonFields) @@ -107,7 +109,7 @@ steps: "client_user_agent": .context.userAgent, "external_id": {{{{$.getGenericPaths("userId")}}}}, "click_id": .properties.clickId, - "partner_id": .traits.partnerId ?? .context.traits.partnerId + "partner_id": .traits.partnerId ?? .context.traits.partnerId ? $.convertToString(.traits.partnerId ?? .context.traits.partnerId) : undefined }); !.destination.Config.sendExternalId ? userFields = userFields{~["external_id"]} : null; userFields = $.removeUndefinedAndNullAndEmptyValues(userFields); @@ -127,17 +129,17 @@ steps: template: | const customFields = .message.().({ "currency": .properties.currency, - "value": .properties.value !== undefined ? String(.properties.value) : - .properties.total !== undefined ? String(.properties.total) : - .properties.revenue !== undefined ? String(.properties.revenue) : undefined, + "value": .properties.value !== undefined ? $.convertToString(.properties.value) : + .properties.total !== undefined ? $.convertToString(.properties.total) : + .properties.revenue !== undefined ? $.convertToString(.properties.revenue) : undefined, "num_items": .properties.numOfItems && Number(.properties.numOfItems), "order_id": .properties.order_id, "search_string": .properties.query, "opt_out_type": .properties.optOutType, - "content_name": .properties.contentName, - "content_category": .properties.contentCategory, - "content_brand": .properties.contentBrand, - "np": .properties.np + "content_name": .properties.contentName ? $.convertToString(.properties.contentName) : undefined, + "content_category": .properties.contentCategory ? $.convertToString(.properties.contentCategory) : undefined, + "content_brand": .properties.contentBrand ? $.convertToString(.properties.contentBrand) : undefined, + "np": .properties.np ? $.convertToString(.properties.np) : undefined }); $.removeUndefinedValues(customFields) @@ -151,11 +153,11 @@ steps: "content_ids": products.(.product_id ?? .sku ?? .id)[], "contents": .message.properties@prop.products.({ "quantity": Number(.quantity ?? prop.quantity ?? 1), - "item_price": String(.price ?? prop.price), - "item_name": String(.name), - "id": .product_id ?? .sku, - "item_category": .category, - "item_brand": .brand + "item_price": $.convertToString(.price ?? prop.price), + "item_name": $.convertToString(.name), + "id": .product_id ?? .sku ? $.convertToString(.product_id ?? .sku) : undefined, + "item_category": .category ? $.convertToString(.category) : undefined, + "item_brand": .brand ? $.convertToString(.brand) : undefined })[] } else: @@ -167,7 +169,11 @@ steps: "content_ids": (props.product_id ?? props.sku ?? props.id)[], "contents": { "quantity": Number(props.quantity) || 1, - "item_price": String(props.price) + "item_price": props.price ? $.convertToString(props.price), + "item_name": props.name ? $.convertToString(props.name), + "id": props.product_id ?? props.sku ? $.convertToString(props.product_id ?? props.sku) : undefined, + "item_category": props.category ? $.convertToString(props.category) : undefined, + "item_brand": props.brand ? $.convertToString(props.brand) : undefined }[] }; - name: combineAllEcomFields diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 1635a3f0dbf..154d24481dc 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -556,6 +556,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -679,6 +683,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index ced7433a282..88f430dd7c2 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -556,6 +556,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -634,6 +638,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -712,6 +720,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3ce7c150918..3deb7d4b8ba 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -388,6 +388,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -466,6 +470,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -544,6 +552,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index 0e467c26d0b..a2652855d56 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -388,6 +388,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -466,6 +470,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index 66b6c870a9e..ba4d5266f30 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -207,6 +207,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -285,6 +289,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 9e36da50cb8..197456f66af 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -754,6 +754,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } @@ -781,6 +785,10 @@ "content_ids": ["123"], "contents": [ { + "id": "123", + "item_brand": "Gamepro", + "item_category": "Games", + "item_name": "Game", "quantity": 11, "item_price": "13.49" } diff --git a/test/integrations/destinations/pinterest_tag/processor/data.ts b/test/integrations/destinations/pinterest_tag/processor/data.ts index b856d247d71..4982444346c 100644 --- a/test/integrations/destinations/pinterest_tag/processor/data.ts +++ b/test/integrations/destinations/pinterest_tag/processor/data.ts @@ -482,7 +482,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [{ id: '123', quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2405,7 +2405,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [{ quantity: 1, item_price: 'undefined' }], + contents: [{ id: '1234', quantity: 1 }], }, }, JSON_ARRAY: {}, @@ -2666,7 +2666,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1 }], + contents: [{ quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3486,7 +3486,7 @@ export const data = [ timestamp: '2020-08-14T05:30:30.118Z', properties: { tax: 2, - total: 27.5, + total: [27.5, 123], coupon: 'hasbros', revenue: 48, currency: 'USD', @@ -3562,11 +3562,10 @@ export const data = [ contents: [ { quantity: 1, - item_price: 'undefined', }, ], currency: 'USD', - value: '27.5', + value: '[27.5,123]', order_id: '50314b8e9bcf000000000000', }, event_name: 'custom event', diff --git a/test/integrations/destinations/pinterest_tag/router/data.ts b/test/integrations/destinations/pinterest_tag/router/data.ts index c9ab29a45a9..4049f7663a8 100644 --- a/test/integrations/destinations/pinterest_tag/router/data.ts +++ b/test/integrations/destinations/pinterest_tag/router/data.ts @@ -815,7 +815,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [{ id: '123', quantity: 2, item_price: '25' }], }, }, { diff --git a/test/integrations/destinations/pinterest_tag/step/data.ts b/test/integrations/destinations/pinterest_tag/step/data.ts index b607e3c9faf..71f12c735ca 100644 --- a/test/integrations/destinations/pinterest_tag/step/data.ts +++ b/test/integrations/destinations/pinterest_tag/step/data.ts @@ -468,7 +468,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 2, content_ids: ['123'], - contents: [{ quantity: 2, item_price: '25' }], + contents: [{ id: '123', quantity: 2, item_price: '25' }], }, }, JSON_ARRAY: {}, @@ -2420,7 +2420,7 @@ export const data = [ order_id: '50314b8e9bcf000000000000', num_items: 0, content_ids: ['1234'], - contents: [{ quantity: 1, item_price: 'undefined' }], + contents: [{ id: '1234', quantity: 1 }], }, }, JSON_ARRAY: {}, @@ -2685,7 +2685,7 @@ export const data = [ advertiser_id: '123456', app_id: '429047995', custom_data: { - contents: [{ item_price: 'undefined', quantity: 1 }], + contents: [{ quantity: 1 }], currency: 'USD', num_items: 0, order_id: '50314b8e9bcf000000000000', @@ -3606,7 +3606,6 @@ export const data = [ contents: [ { quantity: 1, - item_price: 'undefined', }, ], }, From 74fab0ebe9c4e197a5b66129ca999e6e362ac7a8 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Date: Mon, 18 Nov 2024 14:20:45 +0530 Subject: [PATCH 118/147] chore: test case cleanup (#3888) --- test/integrations/destinations/active_campaign/router/data.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integrations/destinations/active_campaign/router/data.ts b/test/integrations/destinations/active_campaign/router/data.ts index f65a65d9bc5..a73140c161c 100644 --- a/test/integrations/destinations/active_campaign/router/data.ts +++ b/test/integrations/destinations/active_campaign/router/data.ts @@ -258,7 +258,7 @@ export const data = [ path: 'path', title: 'title', search: 'search', - tab_url: 'https://simple-tenet.github.io/rudderstack-sample-site/', + tab_url: 'https://abc.com/sample-site/', referrer: 'referrer', initial_referrer: '$direct', referring_domain: '', @@ -288,7 +288,7 @@ export const data = [ path: 'path', title: 'title', search: 'search', - tab_url: 'https://simple-tenet.github.io/rudderstack-sample-site/', + tab_url: 'https://abc.com/sample-site/', referrer: 'referrer', initial_referrer: '$direct', referring_domain: '', From 79e597907eee126b4187e4534b2aa2253d1431da Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:49:18 +0530 Subject: [PATCH 119/147] fix: adding logger for undefined source event (#3879) * fix: adding logger for undefined source event * fix: review comment addressed * chore: enrich metadata, update error msg in logger * chore: code review updates --------- Co-authored-by: Sai Sankeerth --- src/controllers/source.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/controllers/source.ts b/src/controllers/source.ts index 8b6d2d70f84..3d9fa4f4a45 100644 --- a/src/controllers/source.ts +++ b/src/controllers/source.ts @@ -11,6 +11,11 @@ export class SourceController { const requestMetadata = MiscService.getRequestMetadata(ctx); const events = ctx.request.body as object[]; const { version, source }: { version: string; source: string } = ctx.params; + const enrichedMetadata = { + ...requestMetadata, + source, + version, + }; const integrationService = ServiceSelector.getNativeSourceService(); try { @@ -28,6 +33,7 @@ export class SourceController { ); ctx.body = resplist; } catch (err: any) { + logger.error(err?.message || 'error in source transformation', enrichedMetadata); const metaTO = integrationService.getTags(); const resp = SourcePostTransformationService.handleFailureEventsSource(err, metaTO); ctx.body = [resp]; From f3b0300323722680737b99c60595986bacd07f7d Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 18 Nov 2024 09:46:29 +0000 Subject: [PATCH 120/147] chore(release): 1.85.0 --- CHANGELOG.md | 24 ++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3c5528ff65..260da5bd736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.85.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.84.0...v1.85.0) (2024-11-18) + + +### Features + +* added support to eu/us2 datacenter for gainsight px destination ([#3871](https://github.com/rudderlabs/rudder-transformer/issues/3871)) ([12ac3de](https://github.com/rudderlabs/rudder-transformer/commit/12ac3de6e7cc91a6cd52c33bc342f74bbaa8a631)) +* iterable EUDC ([#3828](https://github.com/rudderlabs/rudder-transformer/issues/3828)) ([1c134f8](https://github.com/rudderlabs/rudder-transformer/commit/1c134f84601aaea78581078137cb9955de576f9e)) +* iterable EUDC deleteUsers ([#3881](https://github.com/rudderlabs/rudder-transformer/issues/3881)) ([becb4fa](https://github.com/rudderlabs/rudder-transformer/commit/becb4fa54e9093ed69779f54c36864cb9d28d321)) +* moved userSchema to connection config in GARL vdmv2 ([#3870](https://github.com/rudderlabs/rudder-transformer/issues/3870)) ([640a11e](https://github.com/rudderlabs/rudder-transformer/commit/640a11eb3dca5735fed3ad9ad5bd058974b069d6)) +* now getting consent related fields from connection config from retl for GARL ([#3877](https://github.com/rudderlabs/rudder-transformer/issues/3877)) ([51bbc02](https://github.com/rudderlabs/rudder-transformer/commit/51bbc02d5b00ce1b8fe8c91b4a7041e926bae9bd)) +* onboard linkedin audience destination ([#3857](https://github.com/rudderlabs/rudder-transformer/issues/3857)) ([f3ff409](https://github.com/rudderlabs/rudder-transformer/commit/f3ff4092d455508dd3354ffb22d345fa97f4d1f2)) +* onboarding intercom v2 retl support ([#3843](https://github.com/rudderlabs/rudder-transformer/issues/3843)) ([3d7db73](https://github.com/rudderlabs/rudder-transformer/commit/3d7db7366e30df31c37cc473e344da82b49ed885)) +* sources v2 spec support along with adapters ([04c0694](https://github.com/rudderlabs/rudder-transformer/commit/04c069486bdd3c101906fa6c621e983090fcab25)) +* sources v2 spec support along with adapters ([#3810](https://github.com/rudderlabs/rudder-transformer/issues/3810)) ([c51cfbb](https://github.com/rudderlabs/rudder-transformer/commit/c51cfbb4664a8531dce23b2d06fe40997f95697e)) +* update pinterest_tag single product events with new mapping ([#3858](https://github.com/rudderlabs/rudder-transformer/issues/3858)) ([8520278](https://github.com/rudderlabs/rudder-transformer/commit/85202781de3464bd46fe910159d2b143cd4209e8)) + + +### Bug Fixes + +* adding logger for undefined source event ([#3879](https://github.com/rudderlabs/rudder-transformer/issues/3879)) ([79e5979](https://github.com/rudderlabs/rudder-transformer/commit/79e597907eee126b4187e4534b2aa2253d1431da)) +* adding uuid transformation for airship ([#3884](https://github.com/rudderlabs/rudder-transformer/issues/3884)) ([a80f874](https://github.com/rudderlabs/rudder-transformer/commit/a80f87486dc93b423e4fe6efbee6f4cb8330ba02)) +* handling invalid timestamp for adjust source ([#3866](https://github.com/rudderlabs/rudder-transformer/issues/3866)) ([d57f48e](https://github.com/rudderlabs/rudder-transformer/commit/d57f48e989d18d469bea0de94293bc685300945b)) +* revert gaec changes ([#3885](https://github.com/rudderlabs/rudder-transformer/issues/3885)) ([0aeaa39](https://github.com/rudderlabs/rudder-transformer/commit/0aeaa391b025fc68de6e3d63a6721f067c5be318)) + ## [1.84.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.2...v1.84.0) (2024-11-11) diff --git a/package-lock.json b/package-lock.json index d10997f1439..804bed84cef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.85.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.85.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 92ac9f0fb9b..db80c9b1596 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.85.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 53d2bef38ad5d7bc5504111ec797b3c3973546dd Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Wed, 20 Nov 2024 03:28:06 +0530 Subject: [PATCH 121/147] feat: add support for getting anonymousId by note attributes array --- .../serverSideTransform.js | 19 +++---------- .../webhookTransformations/serverSideUtlis.js | 27 ++++++++++++++++++- .../integrations/sources/shopify/constants.ts | 15 +++++++++++ .../CheckoutEventsTests.ts | 27 ++++++++++--------- .../webhookTestScenarios/GenericTrackTests.ts | 12 +++++---- 5 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index c31bc74bf15..4f91b0e6c1d 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -1,18 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ const lodash = require('lodash'); const get = require('get-value'); -// const { RedisError } = require('@rudderstack/integrations-lib'); const stats = require('../../../../util/stats'); -const { - getShopifyTopic, - // createPropertiesForEcomEvent, - extractEmailFromPayload, - getAnonymousIdAndSessionId, - // getHashLineItems, -} = require('../../../../v0/sources/shopify/util'); -// const logger = require('../../../logger'); +const { getShopifyTopic, extractEmailFromPayload } = require('../../../../v0/sources/shopify/util'); const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../../v0/util'); -// const { RedisDB } = require('../../../util/redis/redisConnector'); const Message = require('../../../../v0/sources/message'); const { EventType } = require('../../../../constants'); const { @@ -28,6 +19,7 @@ const { const { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const NO_OPERATION_SUCCESS = { @@ -128,12 +120,9 @@ const processEvent = async (inputEvent, metricMetadata) => { message.setProperty('traits.email', email); } } + // attach anonymousId if the event is track event using note_attributes if (message.type !== EventType.IDENTIFY) { - const { anonymousId } = await getAnonymousIdAndSessionId( - message, - { shopifyTopic, ...metricMetadata }, - null, - ); + const anonymousId = await getAnonymousIdFromAttributes(event); if (isDefinedAndNotNull(anonymousId)) { message.setProperty('anonymousId', anonymousId); } diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index eed03de71ff..0c38dd1d105 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -1,5 +1,6 @@ +const { isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); +const { v5 } = require('uuid'); const { constructPayload } = require('../../../../v0/util'); - const { lineItemsMappingJSON, productMappingJSON, @@ -39,7 +40,31 @@ const createPropertiesForEcomEventFromWebhook = (message) => { return mappedPayload; }; +/** + * Returns the anonymousId from the noteAttributes array in the webhook event + * @param {Object} event + * @returns {String} anonymousId + */ +const getAnonymousIdFromAttributes = async (event) => { + let anonymousId = null; + let cartToken = null; + const noteAttributes = event.note_attributes; + if (isDefinedAndNotNull(event) && isDefinedAndNotNull(noteAttributes)) { + const rudderAnonymousIdObject = noteAttributes.find( + (attr) => attr.name === 'rudderAnonymousId', + ); + anonymousId = rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; + const cartTokenObject = noteAttributes.find((attr) => attr.name === 'cartToken'); + cartToken = cartTokenObject ? cartTokenObject.value : null; + if (!isDefinedAndNotNull(anonymousId) && isDefinedAndNotNull(cartToken)) { + anonymousId = v5(cartToken, v5.URL); + } + } + return anonymousId; +}; + module.exports = { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, }; diff --git a/test/integrations/sources/shopify/constants.ts b/test/integrations/sources/shopify/constants.ts index f9df3058416..af53a3180e8 100644 --- a/test/integrations/sources/shopify/constants.ts +++ b/test/integrations/sources/shopify/constants.ts @@ -83,6 +83,21 @@ export const dummyContext = { }, }; +export const note_attributes = [ + { + name: 'cartId', + value: '9c623f099fc8819aa4d6a958b65dfe7d', + }, + { + name: 'cartToken', + value: 'Z2NwLXVzLWVhc3QxOjAxSkQzNUFXVEI4VkVUNUpTTk1LSzBCMzlF', + }, + { + name: 'rudderAnonymousId', + value: '50ead33e-d763-4854-b0ab-765859ef05cb', + }, +]; + export const responseDummyContext = { document: { location: { diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index ade496efb79..a154ccb890c 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -1,7 +1,6 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow -import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const checkoutEventsTestScenarios = [ { @@ -27,7 +26,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -145,7 +144,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -237,7 +236,7 @@ export const checkoutEventsTestScenarios = [ traits: { shippingAddress: [], }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -269,7 +268,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -396,7 +395,7 @@ export const checkoutEventsTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', integration: { @@ -415,7 +414,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -680,7 +679,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -988,7 +987,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -1289,7 +1288,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1326,6 +1325,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1486,6 +1486,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1675,7 +1676,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1684,4 +1685,4 @@ export const checkoutEventsTestScenarios = [ }, }, }, -].map((d1) => ({ ...d1, mockFns })); +]; diff --git a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts index f04fd7e08ee..d68d0a8f59c 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts @@ -1,7 +1,7 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const genericTrackTestScenarios = [ { @@ -24,6 +24,7 @@ export const genericTrackTestScenarios = [ token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, updated_at: '2024-09-17T08:15:13.280Z', created_at: '2024-09-16T03:50:15.478Z', }, @@ -43,7 +44,7 @@ export const genericTrackTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { integration: { name: 'SHOPIFY', @@ -58,6 +59,7 @@ export const genericTrackTestScenarios = [ id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', updated_at: '2024-09-17T08:15:13.280Z', }, @@ -149,7 +151,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -363,7 +365,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -545,7 +547,7 @@ export const genericTrackTestScenarios = [ traits: { email: 'henry@wfls.com', }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, From e6077b285035e3842509c62df919d288ed28f5df Mon Sep 17 00:00:00 2001 From: Vinay Teki Date: Wed, 20 Nov 2024 15:59:06 +0530 Subject: [PATCH 122/147] chore: github action for unchanged commits fixed --- .github/workflows/verify.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4bd66285bd8..604ff1eaeee 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -35,8 +35,8 @@ jobs: - name: Filter JS/TS Files run: | - echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' > changed_files.txt - if [ ! -s changed_files.txt ]; then + changed_files=$(echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' || true) + if [ -z "$changed_files" ]; then echo "No JS/TS files to format or lint." exit 0 fi From ca71a318e4d8d098116fe539964b699254f58617 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Thu, 21 Nov 2024 14:49:15 +0530 Subject: [PATCH 123/147] fix: braze subscription batch size (#3897) --- src/v0/destinations/braze/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v0/destinations/braze/config.js b/src/v0/destinations/braze/config.js index 2bbade2754d..8ccabbdb0a8 100644 --- a/src/v0/destinations/braze/config.js +++ b/src/v0/destinations/braze/config.js @@ -36,7 +36,7 @@ const IDENTIFY_BRAZE_MAX_REQ_COUNT = 50; // https://www.braze.com/docs/api/endpoints/user_data/post_user_delete/ const ALIAS_BRAZE_MAX_REQ_COUNT = 50; -const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 50; +const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 25; const DEL_MAX_BATCH_SIZE = 50; const DESTINATION = 'braze'; From bb0b9dc1e5a56e8141c6cb56e89835ba61ee7761 Mon Sep 17 00:00:00 2001 From: shrouti1507 <60211312+shrouti1507@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:25:48 +0530 Subject: [PATCH 124/147] fix: stringifying session ID for airship (#3896) * fix: stringifying session ID for airship * fix: test case numbering fix * fix: adding more test cases * fix: review comment addressed * fix: edit error message * chore: refactored code * chore: handled stringifcation in convertToUuid * fix: adding test cases * fix: small edit * fix: code review addressed --------- Co-authored-by: krishnachaitanya --- .../airship/data/airshipTrackConfig.json | 5 +- src/v0/destinations/airship/transform.js | 12 +- src/v0/destinations/airship/utils.js | 12 - src/v0/util/index.js | 25 ++ src/v0/util/index.test.js | 64 +++++ .../destinations/airship/processor/data.ts | 263 +++++++++++++++++- 6 files changed, 366 insertions(+), 15 deletions(-) delete mode 100644 src/v0/destinations/airship/utils.js diff --git a/src/v0/destinations/airship/data/airshipTrackConfig.json b/src/v0/destinations/airship/data/airshipTrackConfig.json index 1f280f756b4..4b09fdb9434 100644 --- a/src/v0/destinations/airship/data/airshipTrackConfig.json +++ b/src/v0/destinations/airship/data/airshipTrackConfig.json @@ -22,7 +22,10 @@ { "destKey": "session_id", "sourceKeys": ["properties.sessionId", "context.sessionId"], - "required": false + "required": false, + "metadata": { + "type": "toString" + } }, { "destKey": "transaction", diff --git a/src/v0/destinations/airship/transform.js b/src/v0/destinations/airship/transform.js index dc8543fbc59..fcf18daa7ed 100644 --- a/src/v0/destinations/airship/transform.js +++ b/src/v0/destinations/airship/transform.js @@ -22,12 +22,20 @@ const { extractCustomFields, isEmptyObject, simpleProcessRouterDest, + convertToUuid, } = require('../../util'); const { JSON_MIME_TYPE } = require('../../util/constant'); -const { transformSessionId } = require('./utils'); const DEFAULT_ACCEPT_HEADER = 'application/vnd.urbanairship+json; version=3'; +const transformSessionId = (rawSessionId) => { + try { + return convertToUuid(rawSessionId); + } catch (error) { + throw new InstrumentationError(`Failed to transform session ID: ${error.message}`); + } +}; + const identifyResponseBuilder = (message, { Config }) => { const tagPayload = constructPayload(message, identifyMapping); const { apiKey, dataCenter } = Config; @@ -129,6 +137,8 @@ const trackResponseBuilder = async (message, { Config }) => { name = name.toLowerCase(); const payload = constructPayload(message, trackMapping); + + // ref : https://docs.airship.com/api/ua/#operation-api-custom-events-post if (isDefinedAndNotNullAndNotEmpty(payload.session_id)) { payload.session_id = transformSessionId(payload.session_id); } diff --git a/src/v0/destinations/airship/utils.js b/src/v0/destinations/airship/utils.js deleted file mode 100644 index 0ef637245f1..00000000000 --- a/src/v0/destinations/airship/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -const { v5 } = require('uuid'); - -// ref : https://docs.airship.com/api/ua/#operation-api-custom-events-post -const transformSessionId = (rawSessionId) => { - const NAMESPACE = v5.DNS; - const uuidV5 = v5(rawSessionId, NAMESPACE); - return uuidV5; -}; - -module.exports = { - transformSessionId, -}; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index 1676498fdb9..ad08be448ed 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -16,6 +16,7 @@ const uaParser = require('ua-parser-js'); const moment = require('moment-timezone'); const sha256 = require('sha256'); const crypto = require('crypto'); +const { v5 } = require('uuid'); const { InstrumentationError, BaseError, @@ -2330,6 +2331,29 @@ const isEventSentByVDMV1Flow = (event) => event?.message?.context?.mappedToDesti const isEventSentByVDMV2Flow = (event) => event?.connection?.config?.destination?.schemaVersion === VDM_V2_SCHEMA_VERSION; + +const convertToUuid = (input) => { + const NAMESPACE = v5.DNS; + + if (!isDefinedAndNotNull(input)) { + throw new InstrumentationError('Input is undefined or null.'); + } + + try { + // Stringify and trim the input + const trimmedInput = String(input).trim(); + + // Check for empty input after trimming + if (!trimmedInput) { + throw new InstrumentationError('Input is empty or invalid.'); + } + // Generate and return UUID + return v5(trimmedInput, NAMESPACE); + } catch (error) { + const errorMessage = `Failed to transform input to uuid: ${error.message}`; + throw new InstrumentationError(errorMessage); + } +}; // ======================================================================== // EXPORTS // ======================================================================== @@ -2456,4 +2480,5 @@ module.exports = { getRelativePathFromURL, removeEmptyKey, isAxiosError, + convertToUuid, }; diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 0b05b6f2d69..cfdfefddee3 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -2,6 +2,7 @@ const { InstrumentationError } = require('@rudderstack/integrations-lib'); const utilities = require('.'); const { getFuncTestData } = require('../../../test/testHelper'); const { FilteredEventsError } = require('./errorTypes'); +const { v5 } = require('uuid'); const { hasCircularReference, flattenJson, @@ -11,6 +12,7 @@ const { groupRouterTransformEvents, isAxiosError, removeHyphens, + convertToUuid, } = require('./index'); const exp = require('constants'); @@ -985,3 +987,65 @@ describe('removeHyphens', () => { }); }); }); + +describe('convertToUuid', () => { + const NAMESPACE = v5.DNS; + + test('should generate UUID for valid string input', () => { + const input = 'testInput'; + const expectedUuid = '7ba1e88f-acf9-5528-9c1c-0c897ed80e1e'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should generate UUID for valid numeric input', () => { + const input = 123456; + const expectedUuid = 'a52b2702-9bcf-5701-852a-2f4edc640fe1'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should trim spaces and generate UUID', () => { + const input = ' testInput '; + const expectedUuid = '7ba1e88f-acf9-5528-9c1c-0c897ed80e1e'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should throw an error for empty input', () => { + const input = ''; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is empty or invalid.'); + }); + + test('to throw an error for null input', () => { + const input = null; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is undefined or null'); + }); + + test('to throw an error for undefined input', () => { + const input = undefined; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is undefined or null'); + }); + + test('should throw an error for input that is whitespace only', () => { + const input = ' '; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is empty or invalid.'); + }); + + test('should handle long string input gracefully', () => { + const input = 'a'.repeat(1000); + const expectedUuid = v5(input, NAMESPACE); + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('any invalid input if stringified does not throw error', () => { + const input = {}; + const result = convertToUuid(input); + expect(result).toBe('672ca00c-37f4-5d71-b8c3-6ae0848080ec'); + }); +}); diff --git a/test/integrations/destinations/airship/processor/data.ts b/test/integrations/destinations/airship/processor/data.ts index a72495d23df..3c6d827ce6c 100644 --- a/test/integrations/destinations/airship/processor/data.ts +++ b/test/integrations/destinations/airship/processor/data.ts @@ -2296,7 +2296,7 @@ export const data = [ }, { name: 'airship', - description: 'Test 22 : session id gets converted to v5 uuid format', + description: 'Test 22 : session id from Web SDK gets converted to v5 uuid format', feature: 'processor', module: 'destination', version: 'v0', @@ -2381,6 +2381,267 @@ export const data = [ }, }, }, + { + name: 'airship', + description: 'Test 23 : session id from mobile SDK gets converted to v5 uuid format', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + sessionId: 1731403898, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: {}, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + session_id: 'd5627eac-795d-5005-9bb4-2c7c0af6cab0', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'airship', + description: 'Test 24 : session id null gets ignored', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: { + sessionId: null, + }, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'airship', + description: 'Test 24 : session id undefined gets ignored', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: { + sessionId: undefined, + }, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, ].map((tc) => ({ ...tc, mockFns: (_) => { From cf28f14eb261f873ca32e5bdca98c13e825a8ed1 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 21 Nov 2024 10:08:47 +0000 Subject: [PATCH 125/147] chore(release): 1.85.1 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 260da5bd736..bb1779fd3a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.85.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.0...v1.85.1) (2024-11-21) + + +### Bug Fixes + +* braze subscription batch size ([#3897](https://github.com/rudderlabs/rudder-transformer/issues/3897)) ([ca71a31](https://github.com/rudderlabs/rudder-transformer/commit/ca71a318e4d8d098116fe539964b699254f58617)) +* stringifying session ID for airship ([#3896](https://github.com/rudderlabs/rudder-transformer/issues/3896)) ([bb0b9dc](https://github.com/rudderlabs/rudder-transformer/commit/bb0b9dc1e5a56e8141c6cb56e89835ba61ee7761)) + ## [1.85.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.84.0...v1.85.0) (2024-11-18) diff --git a/package-lock.json b/package-lock.json index 804bed84cef..40033e278be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.85.0", + "version": "1.85.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.85.0", + "version": "1.85.1", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index db80c9b1596..e0b17a4f47f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.85.0", + "version": "1.85.1", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 864a9aaf5f7373b2d7b1a1290a3c69511355be09 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Thu, 21 Nov 2024 15:59:12 +0530 Subject: [PATCH 126/147] fix: test (#3899) --- src/v0/destinations/braze/braze.util.test.js | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 71052f8d776..0ee0ec2ebfe 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -972,7 +972,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(8); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -981,10 +981,12 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.attributes.length).toBe(25); // Second batch contains remaining 25 attributes expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(25); // Second batch contains remaining 25 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(25); // Second batch contains remaining 25 purchases - expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 25 subscription group - expect(result[0].batchedRequest[4].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates + expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(25); // First batch contains 50 subscription group + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // First batch contains 50 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[7].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates }); test('processBatch handles more than 75 attributes, events, and purchases with non uniform distribution', () => { @@ -1093,7 +1095,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response expect(result[0].metadata.length).toBe(490); // Check the total length is same as input jobs (120 + 160 + 100 + 70 +40) - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(7); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -1103,9 +1105,10 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(45); // Second batch contains remaining 45 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(75); // Second batch contains remaining 75 purchases expect(result[0].batchedRequest[2].body.JSON.purchases.length).toBe(10); // Third batch contains remaining 10 purchases - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(20); // First batch contains 20 subscription group - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(20); // Third batch contains 20 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates }); test('check success and failure scenarios both for processBatch', () => { From 49a6f189d15322e37b0e4efcd573b4b29fa8d147 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Thu, 21 Nov 2024 17:22:04 +0530 Subject: [PATCH 127/147] chore: braze batch (#3900) --- src/v0/destinations/braze/braze.util.test.js | 21 +++++++++----------- src/v0/destinations/braze/config.js | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 0ee0ec2ebfe..985f2434d50 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -972,7 +972,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response - expect(result[0].batchedRequest.length).toBe(8); // Two batched requests + expect(result[0].batchedRequest.length).toBe(6); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -981,12 +981,10 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.attributes.length).toBe(25); // Second batch contains remaining 25 attributes expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(25); // Second batch contains remaining 25 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(25); // Second batch contains remaining 25 purchases - expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(25); // First batch contains 50 subscription group - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); - expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // First batch contains 50 subscription group - expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group - expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates - expect(result[0].batchedRequest[7].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates + expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); + expect(result[0].batchedRequest[4].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates }); test('processBatch handles more than 75 attributes, events, and purchases with non uniform distribution', () => { @@ -1095,7 +1093,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response expect(result[0].metadata.length).toBe(490); // Check the total length is same as input jobs (120 + 160 + 100 + 70 +40) - expect(result[0].batchedRequest.length).toBe(7); // Two batched requests + expect(result[0].batchedRequest.length).toBe(6); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -1105,10 +1103,9 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(45); // Second batch contains remaining 45 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(75); // Second batch contains remaining 75 purchases expect(result[0].batchedRequest[2].body.JSON.purchases.length).toBe(10); // Third batch contains remaining 10 purchases - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group - expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group - expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(20); // Third batch contains 20 subscription group - expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(20); // Second batch contains 20 subscription group + expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(40); // First batch contains 40 merge_updates }); test('check success and failure scenarios both for processBatch', () => { diff --git a/src/v0/destinations/braze/config.js b/src/v0/destinations/braze/config.js index 8ccabbdb0a8..2bbade2754d 100644 --- a/src/v0/destinations/braze/config.js +++ b/src/v0/destinations/braze/config.js @@ -36,7 +36,7 @@ const IDENTIFY_BRAZE_MAX_REQ_COUNT = 50; // https://www.braze.com/docs/api/endpoints/user_data/post_user_delete/ const ALIAS_BRAZE_MAX_REQ_COUNT = 50; -const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 25; +const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 50; const DEL_MAX_BATCH_SIZE = 50; const DESTINATION = 'braze'; From a0d4efcb165e61c27a96a2d436cd3af625522842 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 22 Nov 2024 01:09:32 +0530 Subject: [PATCH 128/147] chore: allow only anonymousId set from note attributes --- .../shopify/webhookTransformations/serverSideUtlis.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 0c38dd1d105..1ac60f967d0 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -1,5 +1,4 @@ const { isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); -const { v5 } = require('uuid'); const { constructPayload } = require('../../../../v0/util'); const { lineItemsMappingJSON, @@ -47,18 +46,12 @@ const createPropertiesForEcomEventFromWebhook = (message) => { */ const getAnonymousIdFromAttributes = async (event) => { let anonymousId = null; - let cartToken = null; const noteAttributes = event.note_attributes; if (isDefinedAndNotNull(event) && isDefinedAndNotNull(noteAttributes)) { const rudderAnonymousIdObject = noteAttributes.find( (attr) => attr.name === 'rudderAnonymousId', ); anonymousId = rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; - const cartTokenObject = noteAttributes.find((attr) => attr.name === 'cartToken'); - cartToken = cartTokenObject ? cartTokenObject.value : null; - if (!isDefinedAndNotNull(anonymousId) && isDefinedAndNotNull(cartToken)) { - anonymousId = v5(cartToken, v5.URL); - } } return anonymousId; }; From 83c8f52d76739b46f558c2d8682f4b831f9c701a Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:23:00 +0530 Subject: [PATCH 129/147] chore: add unit tests --- .../serverSideUtils.test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js index a611d1d8dc9..4a2839103b9 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js @@ -1,6 +1,7 @@ const { getProductsFromLineItems, createPropertiesForEcomEventFromWebhook, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const { constructPayload } = require('../../../../v0/util'); @@ -109,4 +110,21 @@ describe('serverSideUtils.js', () => { }); }); }); + + describe('getAnonymousIdFromAttributes', () => { + // Handles empty note_attributes array gracefully + it('should return null when note_attributes is an empty array', async () => { + const event = { note_attributes: [] }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toBeNull(); + }); + + it('get anonymousId from noteAttributes', async () => { + const event = { + note_attributes: [{ name: 'rudderAnonymousId', value: '123456' }], + }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toEqual('123456'); + }); + }); }); From 70fa123a771914d6fc1387e7e6ebc0b2e4db4d5d Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:32:08 +0530 Subject: [PATCH 130/147] chore: address initialization comment --- .../sources/shopify/webhookTransformations/serverSideUtlis.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 1ac60f967d0..0afbf302770 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -46,8 +46,8 @@ const createPropertiesForEcomEventFromWebhook = (message) => { */ const getAnonymousIdFromAttributes = async (event) => { let anonymousId = null; - const noteAttributes = event.note_attributes; - if (isDefinedAndNotNull(event) && isDefinedAndNotNull(noteAttributes)) { + if (isDefinedAndNotNull(event) && isDefinedAndNotNull(event.note_attributes)) { + const noteAttributes = event.note_attributes; const rudderAnonymousIdObject = noteAttributes.find( (attr) => attr.name === 'rudderAnonymousId', ); From 481d149c9b2786dd2360f3ee0ab220660d461178 Mon Sep 17 00:00:00 2001 From: Sankeerth Date: Tue, 3 Dec 2024 09:12:00 +0530 Subject: [PATCH 131/147] chore: update default case handling in facebook destinations (#3908) * chore: update default case handling in facebook destinations * fix: update default handling for some error codes - used error_user_msg field as error message - when no error is seen, handled error by stringifying - update test-cases --------- Co-authored-by: Sai Sankeerth --- src/v0/util/facebookUtils/networkHandler.js | 38 +++++----- .../facebook_pixel/dataDelivery/business.ts | 4 +- .../facebook_pixel/dataDelivery/data.ts | 70 +++++++++++++++++-- .../facebook_pixel/dataDelivery/oauth.ts | 4 +- .../facebook_pixel/dataDelivery/other.ts | 10 +-- .../destinations/facebook_pixel/network.ts | 26 +++++++ .../destinations/fb/dataDelivery/data.ts | 3 +- .../destinations/fb/dataDelivery/other.ts | 4 +- test/integrations/destinations/fb/network.ts | 1 + .../fb_custom_audience/dataDelivery/data.ts | 2 + .../fb_custom_audience/network.ts | 2 + 11 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/v0/util/facebookUtils/networkHandler.js b/src/v0/util/facebookUtils/networkHandler.js index fbb7899efeb..46ac59a07af 100644 --- a/src/v0/util/facebookUtils/networkHandler.js +++ b/src/v0/util/facebookUtils/networkHandler.js @@ -85,7 +85,10 @@ const errorDetailsMap = { "Object with ID 'PIXEL_ID' / 'DATASET_ID' / 'AUDIENCE_ID' does not exist, cannot be loaded due to missing permissions, or does not support this operation", ) .build(), - default: new ErrorDetailsExtractorBuilder().setStatus(400).setMessageField('message').build(), + default: new ErrorDetailsExtractorBuilder() + .setStatus(400) + .setMessageField('error_user_msg') + .build(), }, 1: { // An unknown error occurred. @@ -107,9 +110,7 @@ const errorDetailsMap = { .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessage( - 'The session has been invalidated because the user changed their password or Facebook has changed the session for security reasons', - ) + .setMessageField('error_user_msg') .build(), 463: new ErrorDetailsExtractorBuilder() @@ -117,56 +118,56 @@ const errorDetailsMap = { .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessageField('message') + .setMessageField('error_user_msg') .build(), default: new ErrorDetailsExtractorBuilder() .setStatus(400) .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessage('Invalid OAuth 2.0 access token') + .setMessageField('error_user_msg') .build(), }, 3: { default: new ErrorDetailsExtractorBuilder() .setStatus(400) - .setMessage('Capability or permissions issue.') + .setMessageField('error_user_msg') .build(), }, 2: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Temporary issue due to downtime.') + .setMessageField('error_user_msg') .build(), }, 341: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Application limit reached: Temporary issue due to downtime or throttling') + .setMessageField('error_user_msg') .build(), }, 368: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Temporarily blocked for policies violations.') + .setMessageField('error_user_msg') .build(), }, 5000: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Unknown Error Code') + .setMessageField('error_user_msg') .build(), }, 4: { default: new ErrorDetailsExtractorBuilder() .setStatus(429) - .setMessage('API Too Many Calls') + .setMessageField('error_user_msg') .build(), }, 17: { default: new ErrorDetailsExtractorBuilder() .setStatus(429) - .setMessage('API User Too Many Calls') + .setMessageField('error_user_msg') .build(), }, // facebook custom audience related error codes @@ -176,9 +177,7 @@ const errorDetailsMap = { 294: { default: new ErrorDetailsExtractorBuilder() .setStatus(400) - .setMessage( - 'Missing permission. Please make sure you have ads_management permission and the application is included in the allowlist', - ) + .setMessageField('error_user_msg') .build(), }, 1487301: { @@ -214,7 +213,10 @@ const errorDetailsMap = { .build(), }, 200: { - default: new ErrorDetailsExtractorBuilder().setStatus(403).setMessageField('message').build(), + default: new ErrorDetailsExtractorBuilder() + .setStatus(403) + .setMessageField('error_user_msg') + .build(), }, 21009: { default: new ErrorDetailsExtractorBuilder().setStatus(500).setMessageField('message').build(), @@ -236,9 +238,11 @@ const getStatus = (error) => { const isErrorDetailEmpty = isEmpty(errorDetail); if (isErrorDetailEmpty) { // Unhandled error response + const errorMessage = get(error?.error || error, 'error_user_msg'); return { status: errorStatus, stats: { [TAG_NAMES.META]: METADATA.UNHANDLED_STATUS_CODE }, + errorMessage: errorMessage || JSON.stringify(error), }; } errorStatus = errorDetail.status; diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts index 1b425ac5fa5..2b4af61ac3e 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts @@ -42,7 +42,7 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ body: { output: { status: 400, - message: 'Invalid OAuth 2.0 access token', + message: 'The access token could not be decrypted', statTags: { ...statTags, errorCategory: 'dataValidation', @@ -51,7 +51,7 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ }, response: [ { - error: 'Invalid OAuth 2.0 access token', + error: 'The access token could not be decrypted', statusCode: 400, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts index 3366e62c5ae..0e004c11832 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts @@ -45,12 +45,13 @@ export const v0TestData = [ body: { output: { status: 400, - message: 'Invalid OAuth 2.0 access token', + message: 'The access token could not be decrypted', destinationResponse: { error: { code: 190, fbtrace_id: 'fbpixel_trace_id', message: 'The access token could not be decrypted', + error_user_msg: 'The access token could not be decrypted', type: 'OAuthException', }, status: 500, @@ -202,7 +203,7 @@ export const v0TestData = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', destinationResponse: { error: { message: 'User request limit reached', @@ -414,7 +415,7 @@ export const v0TestData = [ body: { output: { status: 400, - message: 'Capability or permissions issue.', + message: 'Some error in permission', destinationResponse: { error: { message: 'Some error in permission', @@ -466,7 +467,8 @@ export const v0TestData = [ body: { output: { status: 500, - message: 'Unhandled random error', + message: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', destinationResponse: { error: { message: 'Unhandled random error', @@ -488,6 +490,66 @@ export const v0TestData = [ }, }, + { + name: 'facebook_pixel', + description: 'Test 10: should handle error with code: 100 & subcode: 2804009', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + body: { + XML: {}, + FORM: testFormData, + JSON: {}, + JSON_ARRAY: {}, + }, + type: 'REST', + files: {}, + method: 'POST', + userId: '', + headers: {}, + version: '1', + endpoint: `https://graph.facebook.com/${VERSION}/12345678912804009/events?access_token=2804009_valid_access_token`, + params: { + destination: 'facebook_pixel', + }, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 400, + body: { + output: { + status: 400, + message: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + destinationResponse: { + error: { + message: 'Invalid parameter', + type: 'OAuthException', + code: 100, + error_user_msg: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + error_user_title: 'Missing Value for Purchase Event', + error_subcode: 2804009, + is_transient: false, + fbtrace_id: 'AP4G-xxxxxxxx', + }, + status: 400, + }, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, { name: 'facebook_pixel', description: 'Test 9: should handle error with code: 21009', diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts index c6d938c627b..bb4fd582f06 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts @@ -28,11 +28,11 @@ export const oauthScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 400, - message: 'Capability or permissions issue.', + message: 'Some error in permission', statTags, response: [ { - error: 'Capability or permissions issue.', + error: 'Some error in permission', statusCode: 400, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts index e25cc8e07c4..154c6f75ad9 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts @@ -31,14 +31,14 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', statTags: { ...statTags, errorType: 'throttled', }, response: [ { - error: 'API User Too Many Calls', + error: 'User request limit reached', statusCode: 429, metadata: generateMetadata(1), }, @@ -72,7 +72,8 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 500, - message: 'Unhandled random error', + message: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', statTags: { ...statTags, errorType: 'retryable', @@ -80,7 +81,8 @@ export const otherScenariosV1: ProxyV1TestData[] = [ }, response: [ { - error: 'Unhandled random error', + error: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', statusCode: 500, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/network.ts b/test/integrations/destinations/facebook_pixel/network.ts index 411d36cf19a..a6ff50623b1 100644 --- a/test/integrations/destinations/facebook_pixel/network.ts +++ b/test/integrations/destinations/facebook_pixel/network.ts @@ -15,6 +15,7 @@ export const networkCallsData = [ data: { error: { message: 'The access token could not be decrypted', + error_user_msg: 'The access token could not be decrypted', type: 'OAuthException', code: 190, fbtrace_id: 'fbpixel_trace_id', @@ -208,4 +209,29 @@ export const networkCallsData = [ statusText: 'OK', }, }, + { + httpReq: { + url: `https://graph.facebook.com/${VERSION}/12345678912804009/events?access_token=2804009_valid_access_token`, + data: getFormData(testFormData).toString(), + params: { destination: 'facebook_pixel' }, + headers: { 'User-Agent': 'RudderLabs' }, + method: 'POST', + }, + httpRes: { + status: 400, + data: { + error: { + code: 100, + error_subcode: 2804009, + error_user_msg: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + error_user_title: 'Missing Value for Purchase Event', + fbtrace_id: 'AP4G-xxxxxxxx', + is_transient: false, + message: 'Invalid parameter', + type: 'OAuthException', + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/fb/dataDelivery/data.ts b/test/integrations/destinations/fb/dataDelivery/data.ts index 9ee19af265c..dfa5dbc65e3 100644 --- a/test/integrations/destinations/fb/dataDelivery/data.ts +++ b/test/integrations/destinations/fb/dataDelivery/data.ts @@ -59,6 +59,7 @@ export const existingTestData = [ message: 'Invalid OAuth 2.0 access token', destinationResponse: { error: { + error_user_msg: 'Invalid OAuth 2.0 access token', code: 190, fbtrace_id: 'fbpixel_trace_id', message: 'The access token could not be decrypted', @@ -274,7 +275,7 @@ export const existingTestData = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', destinationResponse: { error: { message: 'User request limit reached', diff --git a/test/integrations/destinations/fb/dataDelivery/other.ts b/test/integrations/destinations/fb/dataDelivery/other.ts index 9ac3f14fb54..36d3e45f53a 100644 --- a/test/integrations/destinations/fb/dataDelivery/other.ts +++ b/test/integrations/destinations/fb/dataDelivery/other.ts @@ -31,14 +31,14 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', statTags: { ...statTags, errorType: 'throttled', }, response: [ { - error: 'API User Too Many Calls', + error: 'User request limit reached', statusCode: 429, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/fb/network.ts b/test/integrations/destinations/fb/network.ts index 31bbaf0b6ee..1aed48136ca 100644 --- a/test/integrations/destinations/fb/network.ts +++ b/test/integrations/destinations/fb/network.ts @@ -30,6 +30,7 @@ export const networkCallsData = [ data: { error: { message: 'The access token could not be decrypted', + error_user_msg: 'Invalid OAuth 2.0 access token', type: 'OAuthException', code: 190, fbtrace_id: 'fbpixel_trace_id', diff --git a/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts b/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts index b41c656d9f9..cd440aaa37c 100644 --- a/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts +++ b/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts @@ -623,6 +623,8 @@ export const existingTestData = [ fbtrace_id: 'A3b8C6PpI-kdIOwPwV4PANi', message: 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', + error_user_msg: + 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', type: 'OAuthException', }, status: 400, diff --git a/test/integrations/destinations/fb_custom_audience/network.ts b/test/integrations/destinations/fb_custom_audience/network.ts index 369c27afa96..ba14d537ad6 100644 --- a/test/integrations/destinations/fb_custom_audience/network.ts +++ b/test/integrations/destinations/fb_custom_audience/network.ts @@ -514,6 +514,8 @@ export const networkCallsData = [ error: { message: 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', + error_user_msg: + 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', type: 'OAuthException', code: 190, error_subcode: 463, From 3eb5c551f6551e8da9451787159d5616114aa1c8 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:50:06 +0530 Subject: [PATCH 132/147] chore: update function as per review suggestion --- .../webhookTransformations/serverSideUtlis.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 0afbf302770..59a1ddc04f5 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -45,15 +45,14 @@ const createPropertiesForEcomEventFromWebhook = (message) => { * @returns {String} anonymousId */ const getAnonymousIdFromAttributes = async (event) => { - let anonymousId = null; - if (isDefinedAndNotNull(event) && isDefinedAndNotNull(event.note_attributes)) { - const noteAttributes = event.note_attributes; - const rudderAnonymousIdObject = noteAttributes.find( - (attr) => attr.name === 'rudderAnonymousId', - ); - anonymousId = rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; + if (!isDefinedAndNotNull(event) || !isDefinedAndNotNull(event.note_attributes)) { + return null; // Return early if event or note_attributes is invalid } - return anonymousId; + + const noteAttributes = event.note_attributes; + const rudderAnonymousIdObject = noteAttributes.find((attr) => attr.name === 'rudderAnonymousId'); + + return rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; }; module.exports = { From b3f7140cd9444e74955bf91200dc7c3150ce335e Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 6 Dec 2024 00:32:04 +0530 Subject: [PATCH 133/147] chore: fix sonar issues --- .../shopify/webhookTransformations/serverSideTransform.js | 2 +- .../sources/shopify/webhookTransformations/serverSideUtlis.js | 3 +-- src/v1/sources/shopify/webpixelTransformations/pixelUtils.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index 4f91b0e6c1d..292a980a93b 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -122,7 +122,7 @@ const processEvent = async (inputEvent, metricMetadata) => { } // attach anonymousId if the event is track event using note_attributes if (message.type !== EventType.IDENTIFY) { - const anonymousId = await getAnonymousIdFromAttributes(event); + const anonymousId = getAnonymousIdFromAttributes(event); if (isDefinedAndNotNull(anonymousId)) { message.setProperty('anonymousId', anonymousId); } diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 59a1ddc04f5..951fa479e4f 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -17,7 +17,6 @@ const getProductsFromLineItems = (lineItems, mapping) => { } const products = []; lineItems.forEach((lineItem) => { - // const product = constructPayload(lineItem, lineItemsMappingJSON); const product = constructPayload(lineItem, mapping); products.push(product); }); @@ -44,7 +43,7 @@ const createPropertiesForEcomEventFromWebhook = (message) => { * @param {Object} event * @returns {String} anonymousId */ -const getAnonymousIdFromAttributes = async (event) => { +const getAnonymousIdFromAttributes = (event) => { if (!isDefinedAndNotNull(event) || !isDefinedAndNotNull(event.note_attributes)) { return null; // Return early if event or note_attributes is invalid } diff --git a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js index 0c1007f311e..46ae59e0cf8 100644 --- a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js @@ -14,7 +14,7 @@ const { function getNestedValue(object, path) { const keys = path.split('.'); - return keys.reduce((nestedObject, key) => nestedObject && nestedObject[key], object); + return keys.reduce((nestedObject, key) => nestedObject?.[key], object); } function setNestedValue(object, path, value) { From 4a77eda2caf133526a911a239e84e2764a88448d Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:15:35 +0530 Subject: [PATCH 134/147] chore: update repo name for staging deployment also (#3916) --- .github/workflows/prepare-for-staging-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/prepare-for-staging-deploy.yml b/.github/workflows/prepare-for-staging-deploy.yml index 8eeafc376ee..cdf27f78327 100644 --- a/.github/workflows/prepare-for-staging-deploy.yml +++ b/.github/workflows/prepare-for-staging-deploy.yml @@ -78,6 +78,7 @@ jobs: runs-on: ubuntu-latest needs: [generate-tag-names, build-transformer-image, build-user-transformer-image] env: + TF_IMAGE_REPOSITORY: rudderstack/rudder-transformer TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name }} UT_TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name_ut }} steps: @@ -113,6 +114,7 @@ jobs: git checkout -b $BRANCH_NAME cd helm-charts/shared-services/per-az/environment/staging + yq eval -i ".rudder-transformer.image.repository=\"$TF_IMAGE_REPOSITORY\"" staging.yaml yq eval -i ".rudder-transformer.image.tag=\"$TAG_NAME\"" staging.yaml yq eval -i ".user-transformer.image.tag=\"$TAG_NAME\"" staging.yaml git add staging.yaml From f44f1488acb05bb5096e5f9d7bade06f76f55d13 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Fri, 6 Dec 2024 14:05:11 +0530 Subject: [PATCH 135/147] chore: add metrics for mailjet (#3917) --- src/util/prometheus.js | 6 ++++++ src/v0/destinations/mailjet/transform.js | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/util/prometheus.js b/src/util/prometheus.js index c8dd55068be..a4c12e4ea89 100644 --- a/src/util/prometheus.js +++ b/src/util/prometheus.js @@ -520,6 +520,12 @@ class Prometheus { type: 'counter', labelNames: ['destination_id'], }, + { + name: 'mailjet_packing_size', + help: 'mailjet_packing_size', + type: 'gauge', + labelNames: ['group'], + }, { name: 'hs_batch_size', help: 'hs_batch_size', diff --git a/src/v0/destinations/mailjet/transform.js b/src/v0/destinations/mailjet/transform.js index 78b4f766d1d..0a742b4cf74 100644 --- a/src/v0/destinations/mailjet/transform.js +++ b/src/v0/destinations/mailjet/transform.js @@ -1,5 +1,6 @@ const lodash = require('lodash'); const { TransformationError, InstrumentationError } = require('@rudderstack/integrations-lib'); +const stats = require('../../../util/stats'); const { getSuccessRespEvents, defaultRequestConfig, @@ -105,6 +106,9 @@ const batchEvents = (successRespList) => { const eventChunks = lodash.chunk(eventGroups[combination], MAX_BATCH_SIZE); // eventChunks = [[e1,e2,e3,..batchSize],[e1,e2,e3,..batchSize]..] eventChunks.forEach((chunk) => { + stats.gauge('mailjet_packing_size', chunk.length, { + group: combination, + }); const batchEventResponse = generateBatchedPaylaodForArray(chunk, combination); batchedResponseList.push( getSuccessRespEvents( From 313710ca725538e5ffe357216d9c88e444f995c8 Mon Sep 17 00:00:00 2001 From: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:04:06 +0530 Subject: [PATCH 136/147] fix: remove redundant ids and userIdentifier when gbraid or wbraid are there (#3910) * fix: remove redundant ids and userIdentifier when gbraid or wbraid are there * chore: address comment * chore: fix sonar cloud issue * chore: fix sonar cloud issue * chore: decrease Cognitive Complexity from 17 to the 15 * chore: fix lint error * chore: specify head commit hash for checkout temporarily * chore: fix fetch depth * chore: fix fetch depth to 0 * chore: reset commit sha --------- Co-authored-by: Sai Kumar Battinoju --- .../dt-test-and-report-code-coverage.yml | 2 +- .../transform.js | 4 + .../utils.js | 62 +++- .../utils.test.js | 4 +- .../processor/data.ts | 287 ++++++++++++++++-- .../router/data.ts | 2 - 6 files changed, 315 insertions(+), 46 deletions(-) diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 2c768988823..12bd9ac78be 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -33,7 +33,7 @@ jobs: - name: Checkout uses: actions/checkout@v4.2.1 with: - fetch-depth: 1 + fetch-depth: 0 - name: Setup Node uses: actions/setup-node@v4.0.4 diff --git a/src/v0/destinations/google_adwords_offline_conversions/transform.js b/src/v0/destinations/google_adwords_offline_conversions/transform.js index 76b12587cdc..2648f03e8a3 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/transform.js +++ b/src/v0/destinations/google_adwords_offline_conversions/transform.js @@ -18,6 +18,7 @@ const { getClickConversionPayloadAndEndpoint, getConsentsDataFromIntegrationObj, getCallConversionPayload, + updateConversion, } = require('./utils'); const helper = require('./helper'); @@ -48,6 +49,9 @@ const getConversions = (message, metadata, { Config }, event, conversionType) => filteredCustomerId, eventLevelConsentsData, ); + convertedPayload.payload.conversions[0] = updateConversion( + convertedPayload.payload.conversions[0], + ); payload = convertedPayload.payload; endpoint = convertedPayload.endpoint; } else if (conversionType === 'store') { diff --git a/src/v0/destinations/google_adwords_offline_conversions/utils.js b/src/v0/destinations/google_adwords_offline_conversions/utils.js index 89fe609df9c..2d47095eea7 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/utils.js +++ b/src/v0/destinations/google_adwords_offline_conversions/utils.js @@ -317,6 +317,35 @@ const getStoreConversionPayload = (message, Config, event) => { return payload; }; +const hasClickId = (conversion) => { + const { gbraid, wbraid, gclid } = conversion; + return gclid || wbraid || gbraid; +}; +const populateUserIdentifier = ({ email, phone, properties, payload, UserIdentifierSource }) => { + const copiedPayload = cloneDeep(payload); + // userIdentifierSource + // if userIdentifierSource doesn't exist in properties + // then it is taken from the webapp config + if (!properties.userIdentifierSource && UserIdentifierSource !== 'none') { + set( + copiedPayload, + 'conversions[0].userIdentifiers[0].userIdentifierSource', + UserIdentifierSource, + ); + // one of email or phone must be provided when none of gclid, wbraid and gbraid provided + } + if (!email && !phone) { + if (!hasClickId(copiedPayload.conversions[0])) { + throw new InstrumentationError( + `Either an email address or a phone number is required for user identification when none of gclid, wbraid, or gbraid is provided.`, + ); + } else { + // we are deleting userIdentifiers if any one of gclid, wbraid and gbraid is there but email or phone is not present + delete copiedPayload.conversions[0].userIdentifiers; + } + } + return copiedPayload; +}; const getClickConversionPayloadAndEndpoint = ( message, Config, @@ -335,7 +364,7 @@ const getClickConversionPayloadAndEndpoint = ( updatedClickMapping = removeHashToSha256TypeFromMappingJson(updatedClickMapping); } - const payload = constructPayload(message, updatedClickMapping); + let payload = constructPayload(message, updatedClickMapping); const endpoint = CLICK_CONVERSION.replace(':customerId', filteredCustomerId); @@ -353,17 +382,8 @@ const getClickConversionPayloadAndEndpoint = ( set(payload, 'conversions[0].cartData.items', itemList); } - // userIdentifierSource - // if userIdentifierSource doesn't exist in properties - // then it is taken from the webapp config - if (!properties.userIdentifierSource && UserIdentifierSource !== 'none') { - set(payload, 'conversions[0].userIdentifiers[0].userIdentifierSource', UserIdentifierSource); + payload = populateUserIdentifier({ email, phone, properties, payload, UserIdentifierSource }); - // one of email or phone must be provided - if (!email && !phone) { - throw new InstrumentationError(`Either of email or phone is required for user identifier`); - } - } // either of email or phone should be passed // defaultUserIdentifier depends on the webapp configuration // Ref - https://developers.google.com/google-ads/api/rest/reference/rest/v11/customers/uploadClickConversions#ClickConversion @@ -411,6 +431,25 @@ const getConsentsDataFromIntegrationObj = (message) => { return integrationObj?.consents || {}; }; +/** + * remove redundant ids + * @param {*} conversionCopy + */ +const updateConversion = (conversion) => { + const conversionCopy = cloneDeep(conversion); + if (conversionCopy.gclid) { + delete conversionCopy.wbraid; + delete conversionCopy.gbraid; + } + if (conversionCopy.wbraid && conversionCopy.gbraid) { + throw new InstrumentationError(`You can't use both wbraid and gbraid.`); + } + if (conversionCopy.wbraid || conversionCopy.gbraid) { + delete conversionCopy.userIdentifiers; + } + return conversionCopy; +}; + module.exports = { validateDestinationConfig, generateItemListFromProducts, @@ -423,4 +462,5 @@ module.exports = { getExisitingUserIdentifier, getConsentsDataFromIntegrationObj, getCallConversionPayload, + updateConversion, }; diff --git a/src/v0/destinations/google_adwords_offline_conversions/utils.test.js b/src/v0/destinations/google_adwords_offline_conversions/utils.test.js index 2d1863413c9..b6c66537829 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/utils.test.js +++ b/src/v0/destinations/google_adwords_offline_conversions/utils.test.js @@ -244,7 +244,9 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => { }; expect(() => getClickConversionPayloadAndEndpoint(fittingPayload, config, '9625812972'), - ).toThrow('Either of email or phone is required for user identifier'); + ).toThrow( + 'Either an email address or a phone number is required for user identification when none of gclid, wbraid, or gbraid is provided.', + ); }); it('finaliseConsent', () => { diff --git a/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts index ab3e19dc2f1..3ecae2b92dd 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts @@ -231,8 +231,6 @@ export const data = [ JSON: { conversions: [ { - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -528,8 +526,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -821,8 +817,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -1911,7 +1905,6 @@ export const data = [ userId: '12345', properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -1935,7 +1928,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -2052,7 +2044,6 @@ export const data = [ ], properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -2076,7 +2067,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -2093,7 +2083,6 @@ export const data = [ adUserData: 'UNSPECIFIED', }, gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -2110,15 +2099,7 @@ export const data = [ }, ], }, - userIdentifiers: [ - { - userIdentifierSource: 'FIRST_PARTY', - hashedPhoneNumber: - '04e1dabb7c1348b72bfa87da179c9697c69af74827649266a5da8cdbb367abcd', - }, - ], conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: 1, currencyCode: 'GBP', @@ -2169,7 +2150,6 @@ export const data = [ ], properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -2193,7 +2173,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -3751,20 +3730,73 @@ export const data = [ metadata: { secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, }, - statusCode: 400, - error: 'Either of email or phone is required for user identifier', - statTags: { - errorCategory: 'dataValidation', - errorType: 'instrumentation', - destType: 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS', - module: 'destination', - implementation: 'native', - feature: 'processor', + output: { + body: { + FORM: {}, + JSON: { + conversions: [ + { + cartData: { + items: [ + { + productId: '123445', + quantity: 123, + }, + ], + }, + consent: { + adPersonalization: 'UNSPECIFIED', + adUserData: 'UNSPECIFIED', + }, + conversionDateTime: '2022-01-01 12:32:45-08:00', + conversionEnvironment: 'WEB', + gclid: 'gclid', + }, + ], + partialFailure: true, + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: + 'https://googleads.googleapis.com/v16/customers/9625812972:uploadClickConversions', + files: {}, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '8617859087', + }, + method: 'POST', + params: { + customVariables: [ + { + from: 'value', + to: 'revenue', + }, + { + from: 'total', + to: 'cost', + }, + ], + customerId: '9625812972', + event: 'Sign-up - click', + properties: { + conversionDateTime: '2022-01-01 12:32:45-08:00', + gclid: 'gclid', + product_id: '123445', + quantity: 123, + }, + }, + type: 'REST', + userId: '', + version: '1', }, + statusCode: 200, }, ], }, @@ -5704,4 +5736,197 @@ export const data = [ }, mockFns: timestampMock, }, + { + name: 'google_adwords_offline_conversions', + description: 'Test 28 : when both gbraid and wbraid are available', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + device: { + id: '0572f78fa49c648e', + name: 'generic_x86_arm', + type: 'Android', + model: 'AOSP on IA Emulator', + manufacturer: 'Google', + adTrackingEnabled: true, + advertisingId: '44c97318-9040-4361-8bc7-4eb30f665ca8', + }, + traits: { + phone: 'alex@example.com', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'England', + countryCode: 'GB', + postalCode: 'EC3M', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + }, + event: 'Promotion Clicked', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gbraid: 'gbraid', + wbraid: 'wbraid', + externalAttributionCredit: 10, + externalAttributionModel: 'externalAttributionModel', + conversionCustomVariable: 'conversionCustomVariable', + value: 'value', + merchantId: '9876merchantId', + feedCountryCode: 'feedCountryCode', + feedLanguageCode: 'feedLanguageCode', + localTransactionCost: 20, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + quantity: '2', + price: '50', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + }, + ], + userIdentifierSource: 'FIRST_PARTY', + conversionEnvironment: 'WEB', + conversionValue: '1', + currency: 'GBP', + orderId: 'PL-123QR', + }, + integrations: { + All: true, + }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + }, + destination: { + Config: { + customerId: '962-581-2972', + subAccount: false, + eventsToOfflineConversionsTypeMapping: [ + { + from: 'Sign up completed', + to: 'click', + }, + { + from: 'Download', + to: 'call', + }, + { + from: 'Promotion Clicked', + to: 'click', + }, + { + from: 'Product Searched', + to: 'call', + }, + ], + eventsToConversionsNamesMapping: [ + { + from: 'Sign up completed', + to: 'Sign-up - click', + }, + { + from: 'Download', + to: 'Page view', + }, + { + from: 'Promotion Clicked', + to: 'Sign-up - click', + }, + { + from: 'Product Searched', + to: 'search', + }, + ], + customVariables: [ + { + from: 'value', + to: 'revenue', + }, + { + from: 'total', + to: 'cost', + }, + ], + UserIdentifierSource: 'THIRD_PARTY', + conversionEnvironment: 'WEB', + hashUserIdentifier: true, + defaultUserIdentifier: 'email', + validateOnly: false, + rudderAccountId: '2EOknn1JNH7WK1MfNku4fGYKkRK', + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: "You can't use both wbraid and gbraid.", + metadata: { + secret: { + access_token: 'abcd1234', + developer_token: 'ijkl91011', + refresh_token: 'efgh5678', + }, + }, + statTags: { + destType: 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + mockFns: timestampMock, + }, ]; diff --git a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts index 9d1ba220c86..82c8e9b3ff1 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts @@ -738,8 +738,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', From 12621c8eee641f5a03a997e95ed016cff0eefde7 Mon Sep 17 00:00:00 2001 From: Akash Chetty Date: Mon, 9 Dec 2024 10:36:42 +0530 Subject: [PATCH 137/147] fix: skipping users events for snowpipe streaming (#3836) --- .../snowpipe_streaming/transform.js | 27 +- src/warehouse/config/ReservedKeywords.json | 93 ++++ src/warehouse/index.js | 18 +- src/warehouse/v1/util.js | 4 +- test/__tests__/data/warehouse/events.js | 501 ++++++++++++++++++ .../warehouse/integration_options_events.js | 166 +++++- .../integrations/jsonpaths/legacy/aliases.js | 73 +++ .../integrations/jsonpaths/legacy/extract.js | 45 ++ .../integrations/jsonpaths/legacy/groups.js | 73 +++ .../jsonpaths/legacy/identifies.js | 89 ++++ .../integrations/jsonpaths/legacy/pages.js | 69 +++ .../integrations/jsonpaths/legacy/screens.js | 69 +++ .../integrations/jsonpaths/legacy/tracks.js | 151 ++++++ .../integrations/jsonpaths/new/aliases.js | 70 +++ .../integrations/jsonpaths/new/extract.js | 45 ++ .../integrations/jsonpaths/new/groups.js | 70 +++ .../integrations/jsonpaths/new/identifies.js | 89 ++++ .../integrations/jsonpaths/new/pages.js | 66 +++ .../integrations/jsonpaths/new/screens.js | 66 +++ .../integrations/jsonpaths/new/tracks.js | 151 ++++++ test/__tests__/data/warehouse/names.js | 39 ++ test/__tests__/warehouse.test.js | 285 +++++----- 22 files changed, 2120 insertions(+), 139 deletions(-) diff --git a/src/v0/destinations/snowpipe_streaming/transform.js b/src/v0/destinations/snowpipe_streaming/transform.js index 3b0a6e1a931..36fe19ceff5 100644 --- a/src/v0/destinations/snowpipe_streaming/transform.js +++ b/src/v0/destinations/snowpipe_streaming/transform.js @@ -1 +1,26 @@ -module.exports = require('../snowflake/transform'); +const transform = require('../snowflake/transform'); +const { processWarehouseMessage } = require('../../../warehouse'); + +const provider = 'snowpipe_streaming'; + +function process(event) { + const whSchemaVersion = event.request.query.whSchemaVersion || 'v1'; + const whStoreEvent = event.destination.Config.storeFullEvent === true; + const destJsonPaths = event.destination?.Config?.jsonPaths || ''; + return processWarehouseMessage(event.message, { + metadata: event.metadata, + whSchemaVersion, + whStoreEvent, + getDataTypeOverride: transform.getDataTypeOverride, + provider, + sourceCategory: event.metadata ? event.metadata.sourceCategory : null, + destJsonPaths, + destConfig: event.destination?.Config, + }); +} + +module.exports = { + provider, + process, + getDataTypeOverride: transform.getDataTypeOverride, +}; diff --git a/src/warehouse/config/ReservedKeywords.json b/src/warehouse/config/ReservedKeywords.json index 3c383d24bf6..53b8738e1dc 100644 --- a/src/warehouse/config/ReservedKeywords.json +++ b/src/warehouse/config/ReservedKeywords.json @@ -1519,6 +1519,99 @@ "WHERE": true, "WITH": true }, + "SNOWPIPE_STREAMING": { + "ACCOUNT": true, + "ALL": true, + "ALTER": true, + "AND": true, + "ANY": true, + "AS": true, + "BETWEEN": true, + "BY": true, + "CASE": true, + "CAST": true, + "CHECK": true, + "COLUMN": true, + "CONNECT": true, + "CONNECTION": true, + "CONSTRAINT": true, + "CREATE": true, + "CROSS": true, + "CURRENT": true, + "CURRENT_DATE": true, + "CURRENT_TIME": true, + "CURRENT_TIMESTAMP": true, + "CURRENT_USER": true, + "DATABASE": true, + "DELETE": true, + "DISTINCT": true, + "DROP": true, + "ELSE": true, + "EXISTS": true, + "FALSE": true, + "FOLLOWING": true, + "FOR": true, + "FROM": true, + "FULL": true, + "GRANT": true, + "GROUP": true, + "GSCLUSTER": true, + "HAVING": true, + "ILIKE": true, + "IN": true, + "INCREMENT": true, + "INNER": true, + "INSERT": true, + "INTERSECT": true, + "INTO": true, + "IS": true, + "ISSUE": true, + "JOIN": true, + "LATERAL": true, + "LEFT": true, + "LIKE": true, + "LOCALTIME": true, + "LOCALTIMESTAMP": true, + "MINUS": true, + "NATURAL": true, + "NOT": true, + "NULL": true, + "OF": true, + "ON": true, + "OR": true, + "ORDER": true, + "ORGANIZATION": true, + "QUALIFY": true, + "REGEXP": true, + "REVOKE": true, + "RIGHT": true, + "RLIKE": true, + "ROW": true, + "ROWS": true, + "SAMPLE": true, + "SCHEMA": true, + "SELECT": true, + "SET": true, + "SOME": true, + "START": true, + "TABLE": true, + "TABLESAMPLE": true, + "THEN": true, + "TO": true, + "TRIGGER": true, + "TRUE": true, + "TRY_CAST": true, + "UNION": true, + "UNIQUE": true, + "UPDATE": true, + "USING": true, + "VALUES": true, + "VIEW": true, + "WHEN": true, + "WHENEVER": true, + "WHERE": true, + "WITH": true + }, "CLICKHOUSE": {}, "S3_DATALAKE": { "ALL": true, diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 3491a257da0..ea663c9b2fc 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -349,7 +349,10 @@ function stringLikeObjectToString(obj) { */ function getColumns(options, event, columnTypes) { const columns = {}; - const uuidTS = options.provider === 'snowflake' ? 'UUID_TS' : 'uuid_ts'; + const uuidTS = + options.provider === 'snowflake' || options.provider === 'snowpipe_streaming' + ? 'UUID_TS' + : 'uuid_ts'; columns[uuidTS] = 'datetime'; // add loaded_at for bq to be segment compatible if (options.provider === 'bq') { @@ -377,6 +380,7 @@ function getColumns(options, event, columnTypes) { const fullEventColumnTypeByProvider = { snowflake: 'json', + snowpipe_streaming: 'json', rs: 'text', bq: 'string', postgres: 'json', @@ -613,6 +617,15 @@ function enhanceContextWithSourceDestInfo(message, metadata) { message.context = context; } +function shouldSkipUsersTable(options) { + return ( + options.provider === 'snowpipe_streaming' || + options.destConfig?.skipUsersTable || + options.integrationOptions?.skipUsersTable || + false + ); +} + function processWarehouseMessage(message, options) { const utils = getVersionedUtils(options.whSchemaVersion); options.utils = utils; @@ -638,8 +651,7 @@ function processWarehouseMessage(message, options) { const eventType = message.type?.toLowerCase(); const skipTracksTable = options.destConfig?.skipTracksTable || options.integrationOptions.skipTracksTable || false; - const skipUsersTable = - options.destConfig?.skipUsersTable || options.integrationOptions.skipUsersTable || false; + const skipUsersTable = shouldSkipUsersTable(options); const skipReservedKeywordsEscaping = options.integrationOptions.skipReservedKeywordsEscaping || false; diff --git a/src/warehouse/v1/util.js b/src/warehouse/v1/util.js index d1289bc674f..95dd59b0300 100644 --- a/src/warehouse/v1/util.js +++ b/src/warehouse/v1/util.js @@ -11,7 +11,7 @@ function safeTableName(options, name = '') { if (tableName === '') { throw new TransformationError('Table name cannot be empty.'); } - if (provider === 'snowflake') { + if (provider === 'snowflake' || provider === 'snowpipe_streaming') { tableName = tableName.toUpperCase(); } else if (provider === 'postgres') { tableName = tableName.substr(0, 63); @@ -41,7 +41,7 @@ function safeColumnName(options, name = '') { if (columnName === '') { throw new TransformationError('Column name cannot be empty.'); } - if (provider === 'snowflake') { + if (provider === 'snowflake' || provider === 'snowpipe_streaming') { columnName = columnName.toUpperCase(); } else if (provider === 'postgres') { columnName = columnName.substr(0, 63); diff --git a/test/__tests__/data/warehouse/events.js b/test/__tests__/data/warehouse/events.js index bca6f776be4..99343e43e19 100644 --- a/test/__tests__/data/warehouse/events.js +++ b/test/__tests__/data/warehouse/events.js @@ -368,6 +368,146 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "TRACKS", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "button clicked", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + EVENT: "button_clicked" + } + }, + { + metadata: { + table: "BUTTON_CLICKED", + columns: { + UUID_TS: "datetime", + CURRENCY: "string", + REVENUE: "int", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CURRENCY: "USD", + REVENUE: 50, + STACK_HISTORY_ERROR_DETAILS: [ + { + "message": "Cannot set headers after they are sent to the client", + "toString": "[function]" + } + ], + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "button clicked", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + EVENT: "button_clicked", + } + } + ], s3_datalake: [ { metadata: { @@ -845,6 +985,78 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "IDENTIFIES", + columns: { + UUID_TS: "datetime", + CITY: "string", + COUNTRY: "string", + EMAIL: "string", + FIRSTNAME: "string", + LASTNAME: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CITY: "Disney", + COUNTRY: "UK", + EMAIL: "mickey@disney.com", + FIRSTNAME: "Mickey", + LASTNAME: "Mouse", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "2536eda4-d638-4c93-8014-8ffe3f083214", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.363Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.362Z", + CHANNEL: "web" + } + }, + ], s3_datalake: [ { metadata: { @@ -1170,6 +1382,66 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "PAGES", + columns: { + UUID_TS: "datetime", + PATH: "string", + URL: "string", + NAME: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_USER_AGENT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + PATH: "/tests/html/index2.html", + URL: "http://localhost/tests/html/index2.html", + NAME: "sample title", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "dd266c67-9199-4a52-ba32-f46ddde67312", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.359Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.358Z", + CHANNEL: "web" + } + } + ], s3_datalake: [ { metadata: { @@ -1424,6 +1696,67 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "SCREENS", + columns: { + UUID_TS: "datetime", + PATH: "string", + CATEGORY: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + TIMESTAMP: "datetime", + CHANNEL: "string", + NAME: "string" + } + }, + data: { + PATH: "/abc", + CATEGORY: "test-category", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.0", + CONTEXT_TRAITS_EMAIL: "test@rudderstack.com", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.0", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", + CONTEXT_LOCALE: "en-US", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + ID: "5e10d13a-bf9a-44bf-b884-43a9e591ea71", + ANONYMOUS_ID: "00000000000000000000000000", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2019-10-14T11:15:53.296Z", + ORIGINAL_TIMESTAMP: "2019-10-14T11:15:18.299Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + CHANNEL: "web", + NAME: "ApplicationLoaded" + } + } + ], s3_datalake: [ { metadata: { @@ -1687,6 +2020,73 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "GROUPS", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_LOCALE: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_OS_ID: "string", + CONTEXT_OS_MANUFACTURER: "string", + CONTEXT_OS_MODEL: "string", + CONTEXT_OS_TYPE: "string", + CONTEXT_SCREEN_DENSITY: "int", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + GROUP_ID: "string", + SENT_AT: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + TIMESTAMP: "datetime", + CHANNEL: "string" + } + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.0", + CONTEXT_TRAITS_EMAIL: "test@rudderstack.com", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.0", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", + CONTEXT_LOCALE: "en-US", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_OS_ID: "72e528f869711c3d", + CONTEXT_OS_MANUFACTURER: "Google", + CONTEXT_OS_MODEL: "sdk_gphone_x86", + CONTEXT_OS_NAME: "", + CONTEXT_OS_TOKEN: "", + CONTEXT_OS_TYPE: "android", + CONTEXT_SCREEN_DENSITY: 2, + ID: "84e26acc-56a5-4835-8233-591137fca468", + ANONYMOUS_ID: "00000000000000000000000000", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + GROUP_ID: "g1", + SENT_AT: "2019-10-14T09:03:22.563Z", + ORIGINAL_TIMESTAMP: "2019-10-14T09:03:17.562Z", + TIMESTAMP: "2020-01-24T11:59:02.403Z", + RECEIVED_AT: "2020-01-24T11:59:02.403Z", + CHANNEL: "web" + } + } + ], s3_datalake: [ { metadata: { @@ -1956,6 +2356,70 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "ALIASES", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + PREVIOUS_ID: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "79313729-7fe5-4204-963a-dc46f4205e4e", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "1234abc", + SENT_AT: "2020-01-24T06:29:02.366Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.366Z", + CHANNEL: "web", + PREVIOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca" + } + } + ], s3_datalake: [ { metadata: { @@ -2147,6 +2611,40 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "EXTRACT_EVENT", + columns: { + DATE_PROPERTY: "datetime", + DATE_PROPERTY_2: "datetime", + CONTEXT_SOURCES_JOB_ID: "string", + CONTEXT_SOURCES_JOB_RUN_ID: "string", + CONTEXT_SOURCES_TASK_RUN_ID: "string", + CONTEXT_SOURCES_VERSION: "string", + EVENT: "string", + ID: "string", + USER_ID: "string", + RECEIVED_AT: "datetime", + BOOLEAN_PROPERTY: "boolean", + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + DATE_PROPERTY: "2023-02-01T07:53:31.430Z", + DATE_PROPERTY_2: "2023-01-31T07:39:10.002Z", + CONTEXT_SOURCES_JOB_ID: "2JABSy1nq89H7xeJimBL2pCtOOp", + CONTEXT_SOURCES_JOB_RUN_ID: "cfd6705nsevh5p2l77ag", + CONTEXT_SOURCES_TASK_RUN_ID: "cfd6705nsevh5p2l77b0", + CONTEXT_SOURCES_VERSION: "version", + ID: "some-uuid", + USER_ID: "dummy-user-id-inside-properties", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + EVENT: "extract_event", + BOOLEAN_PROPERTY: true, + } + } + ], s3_datalake: [ { metadata: { @@ -2193,6 +2691,9 @@ function output(eventType, provider) { if (provider === "snowflake") { return _.cloneDeep(sampleEvents[eventType].output.snowflake); } + if (provider === "snowpipe_streaming") { + return _.cloneDeep(sampleEvents[eventType].output.snowpipe_streaming); + } if (provider === "s3_datalake") { return _.cloneDeep(sampleEvents[eventType].output.s3_datalake); } diff --git a/test/__tests__/data/warehouse/integration_options_events.js b/test/__tests__/data/warehouse/integration_options_events.js index 35eafb6a9ba..b3f076851b9 100644 --- a/test/__tests__/data/warehouse/integration_options_events.js +++ b/test/__tests__/data/warehouse/integration_options_events.js @@ -74,6 +74,13 @@ const sampleEvents = { jsonPaths: ["tMap"] } }, + SNOWPIPE_STREAMING: { + options: { + skipTracksTable: true, + useBlendoCasing: true, + jsonPaths: ["tMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -432,6 +439,88 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "_GROUPS", + columns: { + UUID_TS: "datetime", + CURRENCY: "string", + REVENUE: "int", + PATH_TO_$1_000_000: "string", + _9OMEGA: "boolean", + CAMELCASE123KEY: "string", + TESTMAP_NESTEDMAP: "json", + TMAP: "json", + TESTARRAY: "json", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USERAGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CURRENCY: "USD", + REVENUE: 50, + PATH_TO_$1_000_000: "None", + _9OMEGA: true, + CAMELCASE123KEY: "camel case", + TESTMAP_NESTEDMAP: '{"n1":"nested prop 1"}', + TMAP: '{"t1":10,"t2":20}', + TESTARRAY: '["This is","an","array"]', + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USERAGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "groups", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + EVENT: "groups" + } + } + ], s3_datalake: [ { metadata: { @@ -730,7 +819,7 @@ const sampleEvents = { ] } }, - users: { + identify: { input: { destination: { Config: { @@ -1255,6 +1344,75 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], s3_datalake: [ { "data": { @@ -1639,6 +1797,8 @@ function opOutput(eventType, provider) { switch (provider) { case "snowflake": return _.cloneDeep(sampleEvents[eventType].output.snowflake); + case "snowpipe_streaming": + return _.cloneDeep(sampleEvents[eventType].output.snowpipe_streaming); case "s3_datalake": return _.cloneDeep(sampleEvents[eventType].output.s3_datalake); case "rs": @@ -1646,13 +1806,13 @@ function opOutput(eventType, provider) { case "bq": return _.cloneDeep(sampleEvents[eventType].output.bq); case "gcs_datalake": - if (eventType === 'users') { + if (eventType === 'identify') { return _.cloneDeep(sampleEvents[eventType].output.gcs_datalake); } else { return _.cloneDeep(sampleEvents[eventType].output.default); } case "azure_datalake": - if (eventType === 'users') { + if (eventType === 'identify') { return _.cloneDeep(sampleEvents[eventType].output.azure_datalake); } else { return _.cloneDeep(sampleEvents[eventType].output.default); diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js index 30cce51fb7d..7615abe5e13 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js @@ -78,6 +78,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -426,5 +434,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "ALIASES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js index 9d38ecc2929..b28b3a161ec 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js @@ -59,6 +59,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "PMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -276,6 +284,43 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_SOURCES_JOB_ID": "djfhksdjhfkjdhfkjahkf", + "CONTEXT_SOURCES_JOB_RUN_ID": "job_run_id", + "CONTEXT_SOURCES_TASK_RUN_ID": "task_run_id", + "CONTEXT_SOURCES_VERSION": "1169/merge", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EVENT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "P_MAP_NESTED_MAP_N_1": "nested prop 1", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50 + }, + "metadata": { + "columns": { + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_SOURCES_JOB_ID": "string", + "CONTEXT_SOURCES_JOB_RUN_ID": "string", + "CONTEXT_SOURCES_TASK_RUN_ID": "string", + "CONTEXT_SOURCES_VERSION": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EVENT": "string", + "ID": "string", + "P_MAP_NESTED_MAP_N_1": "string", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js index bbae993b27b..457d251a74a 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js @@ -78,6 +78,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, GCS_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -431,5 +439,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "GROUPS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js index 42f5cccf49a..d91ef5f44bb 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js @@ -53,6 +53,16 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "UPMap.nestedMap", + "CTMap.nestedMap", + "TMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -879,6 +889,85 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP_N_1": "nested prop 1", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "CT_MAP_NESTED_MAP_N_1": "nested prop 1", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "T_MAP_NESTED_MAP_N_1": "nested prop 1", + "UP_MAP_NESTED_MAP_N_1": "nested prop 1", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "CT_MAP_NESTED_MAP_N_1": "string", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "T_MAP_NESTED_MAP_N_1": "string", + "UP_MAP_NESTED_MAP_N_1": "string", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], datalake: [ { "data": { diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js index dc2d3a3318d..322ee8f3e66 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js @@ -67,6 +67,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -404,5 +412,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PAGES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js index 9b789d27476..27d7b9a69b8 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js @@ -67,6 +67,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + ".ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -404,5 +412,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "SCREENS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js index 691ce57ca15..aabfce149b8 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js @@ -78,6 +78,15 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "UPMap.nestedMap", + "PMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -828,6 +837,148 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "TRACKS" + } + }, + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EMAIL": "test@gmail.com", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EMAIL": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js index d5d57f85b9d..4b74fd37685 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js @@ -66,6 +66,11 @@ module.exports = { jsonPaths: ["alias.traits.testMap.nestedMap", "alias.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["alias.traits.testMap.nestedMap", "alias.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -414,5 +419,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "ALIASES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js index a950b7f526f..03745c0502f 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js @@ -59,6 +59,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "extract.properties.PMap.nestedMap", + "extract.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -276,6 +284,43 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_SOURCES_JOB_ID": "djfhksdjhfkjdhfkjahkf", + "CONTEXT_SOURCES_JOB_RUN_ID": "job_run_id", + "CONTEXT_SOURCES_TASK_RUN_ID": "task_run_id", + "CONTEXT_SOURCES_VERSION": "1169/merge", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EVENT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50 + }, + "metadata": { + "columns": { + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_SOURCES_JOB_ID": "string", + "CONTEXT_SOURCES_JOB_RUN_ID": "string", + "CONTEXT_SOURCES_TASK_RUN_ID": "string", + "CONTEXT_SOURCES_VERSION": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EVENT": "string", + "ID": "string", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js index 6979aa11009..1e7c8110daf 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js @@ -66,6 +66,11 @@ module.exports = { jsonPaths: ["group.traits.testMap.nestedMap", "group.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["group.traits.testMap.nestedMap", "group.context.ctestMap.cnestedMap"] + } + }, GCS_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -419,5 +424,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "GROUPS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js index 89fcc23cd5c..d9c3b80df3c 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js @@ -53,6 +53,16 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "identify.userProperties.UPMap.nestedMap", + "identify.context.traits.CTMap.nestedMap", + "identify.traits.TMap.nestedMap", + "identify.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -879,6 +889,85 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "CT_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "T_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP": "json", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "CT_MAP_NESTED_MAP": "json", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "T_MAP_NESTED_MAP": "json", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], datalake: [ { "data": { diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js index d5282c1cfd7..1f72ec31cf7 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js @@ -55,6 +55,11 @@ module.exports = { jsonPaths: ["page.properties.testMap.nestedMap", "page.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["page.properties.testMap.nestedMap", "page.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -392,5 +397,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PAGES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js index 3eec47b89df..68b5aafcb59 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js @@ -55,6 +55,11 @@ module.exports = { jsonPaths: ["screen.properties.testMap.nestedMap", "screen.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["screen.properties.testMap.nestedMap", "screen.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -392,5 +397,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "SCREENS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js index 6b411835dbf..70c20b8b8e3 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js @@ -78,6 +78,15 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "track.userProperties.UPMap.nestedMap", + "track.properties.PMap.nestedMap", + "track.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -828,6 +837,148 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "TRACKS" + } + }, + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EMAIL": "test@gmail.com", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EMAIL": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/names.js b/test/__tests__/data/warehouse/names.js index b0380dc06d3..e6015cef2cc 100644 --- a/test/__tests__/data/warehouse/names.js +++ b/test/__tests__/data/warehouse/names.js @@ -41,6 +41,19 @@ const names = { C_Z: "string", CAMEL_CASE_123_KEY: "string", _1_C_COMEGA: "string" + }, + snowpipe_streaming: { + OMEGA: "string", + OMEGA_V_2: "string", + _9_MEGA: "string", + MEGA: "string", + OME_GA: "string", + ALPHA: "string", + OME_GA: "string", + _9_MEGA_90: "string", + C_Z: "string", + CAMEL_CASE_123_KEY: "string", + _1_C_COMEGA: "string" } }, data: { @@ -69,6 +82,19 @@ const names = { C_Z: "test", CAMEL_CASE_123_KEY: "test", _1_C_COMEGA: "test" + }, + snowpipe_streaming: { + OMEGA: "test", + OMEGA_V_2: "test", + _9_MEGA: "test", + MEGA: "test", + OME_GA: "test", + ALPHA: "test", + OME_GA: "test", + _9_MEGA_90: "test", + C_Z: "test", + CAMEL_CASE_123_KEY: "test", + _1_C_COMEGA: "test" } }, namesMap: { @@ -97,6 +123,19 @@ const names = { Cízǔ: "C_Z", CamelCase123Key: "CAMEL_CASE_123_KEY", "1CComega": "_1_C_COMEGA" + }, + snowpipe_streaming: { + omega: "OMEGA", + "omega v2": "OMEGA_V_2", + "9mega": "_9_MEGA", + "mega&": "MEGA", + ome$ga: "OME_GA", + alpha$: "ALPHA", + "ome_ ga": "OME_GA", + "9mega________-________90": "_9_MEGA_90", + Cízǔ: "C_Z", + CamelCase123Key: "CAMEL_CASE_123_KEY", + "1CComega": "_1_C_COMEGA" } } } diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 7fdecbd7cff..44d1d33ff85 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -37,14 +37,6 @@ const integrations = [ "s3_datalake", "gcs_datalake", ]; - -const integration = (index ) => { - const it = integrations[index]; - if (it === "snowflake" || it === "snowpipe_streaming") { - return "snowflake"; - } - return it; -} const transformers = integrations.map(integration => require(`../../src/${version}/destinations/${integration}/transform`) ); @@ -62,7 +54,7 @@ const propsKeyMap = { }; const integrationCasedString = (integration, str) => { - if (integration === "snowflake") { + if (integration === "snowflake" || integration === "snowpipe_streaming") { return str.toUpperCase(); } return str; @@ -74,7 +66,7 @@ describe("event types", () => { const i = input("track"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("track", integration(index))); + expect(received).toMatchObject(output("track", integrations[index])); }); }); }); @@ -85,7 +77,7 @@ describe("event types", () => { // also verfies priority order between traits and context.traits transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("identify", integration(index))); + expect(received).toMatchObject(output("identify", integrations[index])); }); }); }); @@ -95,7 +87,7 @@ describe("event types", () => { const i = input("page"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integration(index))); + expect(received).toMatchObject(output("page", integrations[index])); }); }); it("should take name from properties if top-level name is missing", () => { @@ -104,7 +96,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integration(index))); + expect(received).toMatchObject(output("page", integrations[index])); }); }); }); @@ -114,7 +106,7 @@ describe("event types", () => { const i = input("screen"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integration(index))); + expect(received).toMatchObject(output("screen", integrations[index])); }); }); it("should take name from properties if top-level name is missing", () => { @@ -123,7 +115,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integration(index))); + expect(received).toMatchObject(output("screen", integrations[index])); }); }); }); @@ -133,7 +125,7 @@ describe("event types", () => { const i = input("alias"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("alias", integration(index))); + expect(received).toMatchObject(output("alias", integrations[index])); }); }); }); @@ -143,7 +135,7 @@ describe("event types", () => { const i = input("extract"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("extract", integration(index))); + expect(received).toMatchObject(output("extract", integrations[index])); }); }); }); @@ -161,8 +153,9 @@ describe("column & table names", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); - const provider = - (integration(index) === "snowflake" || integration(index) == "snowpipe_streaming") ? "snowflake" : "default"; + const provider = ["snowflake", "snowpipe_streaming"].includes(integrations[index]) + ? integrations[index] + : "default"; expect(received[1].metadata.columns).toMatchObject( names.output.columns[provider] @@ -195,7 +188,7 @@ describe("column & table names", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); - if (integration(index) === "postgres") { + if (integrations[index] === "postgres") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1" @@ -219,7 +212,7 @@ describe("column & table names", () => { //KEY should be trimmed to 63 return; } - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { expect(received[1].metadata).toHaveProperty( "table", "A_1_A_2_A_3_A_4_A_5_B_1_B_2_B_3_B_4_B_5_C_1_C_2_C_3_C_4_C_5_D_1_D_2_D_3_D_4_D_5_E_1_E_2_E_3_E_4_E_5_F_1_F_2_F_3_F_4_F_5_G_1_G_2" @@ -242,7 +235,7 @@ describe("column & table names", () => { ); return; } - if (integration(index) === "s3_datalake" || integration(index) === "gcs_datalake" || integration(index) === "azure_datalake") { + if (integrations[index] === "s3_datalake" || integrations[index] === "gcs_datalake" || integrations[index] === "azure_datalake") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1_d_2_d_3_d_4_d_5_e_1_e_2_e_3_e_4_e_5_f_1_f_2_f_3_f_4_f_5_g_1_g_2_g_3_g_4_g_5" @@ -325,7 +318,7 @@ describe("conflict between rudder set props and user set props", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { let sampleRudderPropKey = "id"; - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { sampleRudderPropKey = "ID"; } @@ -363,7 +356,7 @@ describe("handle reserved words", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { const reserverdKeywordsMap = - reservedANSIKeywordsMap[integration(index).toUpperCase()]; + reservedANSIKeywordsMap[integrations[index].toUpperCase()]; i.message[propsKey] = Object.assign( i.message[propsKey] || {}, @@ -373,7 +366,7 @@ describe("handle reserved words", () => { const received = transformer.process(i); const out = - evType === "track" || evType === "identify" + evType === "track" || (evType === "identify" && integrations[index] !== 'snowpipe_streaming') ? received[1] : received[0]; @@ -386,7 +379,7 @@ describe("handle reserved words", () => { } else { k = snakeCasedKey; } - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { expect(out.metadata.columns).toHaveProperty(k); } else { expect(out.metadata.columns).toHaveProperty(k.toLowerCase()); @@ -470,24 +463,24 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("new_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("new_ip"); } @@ -505,23 +498,23 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("requested_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("requested_ip"); } @@ -542,10 +535,10 @@ describe("remove rudder property if rudder property is null", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ); }); }); @@ -560,29 +553,29 @@ describe("remove any property if event is object ", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); }); transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "event_text") + integrationCasedString(integrations[index], "event_text") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "event_text") + integrationCasedString(integrations[index], "event_text") ); }); i.message.channel = { channel: "android" }; transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); }); }); @@ -598,13 +591,13 @@ describe("store full rudder event", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); const columnName = integrationCasedString( - integration(index), + integrations[index], "rudder_event" ); expect(received[0].metadata.columns).toHaveProperty(columnName); expect(received[0].metadata.columns[columnName]).toEqual( - fullEventColumnTypeByProvider[integration(index)] + fullEventColumnTypeByProvider[integrations[index]] ); expect(received[0].data[columnName]).toEqual(JSON.stringify(i.message)); @@ -644,7 +637,7 @@ describe("rudder reserved columns", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); checkProps.forEach(k => { - k = integrationCasedString(integration(index), k); + k = integrationCasedString(integrations[index], k); expect(received[0].metadata.columns).not.toHaveProperty(k); expect(received[0].data).not.toHaveProperty(k); if (received[1]) { @@ -664,14 +657,25 @@ describe("id column datatype for users table", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); + if (integrations[index] === 'snowpipe_streaming') { + expect(received).toHaveLength(1); + expect( + received[0].metadata.columns[ + integrationCasedString(integrations[index], "user_id") + ] + ).toEqual("int"); + return; + } + + expect(received).toHaveLength(2); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "user_id") + integrationCasedString(integrations[index], "user_id") ] ).toEqual("int"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); }); @@ -681,14 +685,25 @@ describe("id column datatype for users table", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); + if (integrations[index] === 'snowpipe_streaming') { + expect(received).toHaveLength(1); + expect( + received[0].metadata.columns[ + integrationCasedString(integrations[index], "user_id") + ] + ).toEqual("float"); + return; + } + + expect(received).toHaveLength(2); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "user_id") + integrationCasedString(integrations[index], "user_id") ] ).toEqual("float"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("float"); }); @@ -707,22 +722,22 @@ describe("handle leading underscores in properties", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "_timestamp") + integrationCasedString(integrations[index], "_timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "__timestamp") + integrationCasedString(integrations[index], "__timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "__timestamp_new") + integrationCasedString(integrations[index], "__timestamp_new") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "_timestamp") + integrationCasedString(integrations[index], "_timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "__timestamp") + integrationCasedString(integrations[index], "__timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "__timestamp_new") + integrationCasedString(integrations[index], "__timestamp_new") ); }); }); @@ -736,22 +751,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); }); }); @@ -764,22 +779,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); }); }); @@ -792,17 +807,17 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("string"); }); @@ -818,28 +833,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); }); }); @@ -854,28 +869,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); }); }); @@ -915,10 +930,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -943,10 +958,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -956,7 +971,7 @@ describe("Handle no of columns in an event", () => { it("should throw an error if no of columns are more than 200", () => { const i = input("track"); transformers - .filter((transformer, index) => integration(index) !== "s3_datalake" && integration(index) !== "gcs_datalake" && integration(index) !== "azure_datalake") + .filter((transformer, index) => integrations[index] !== "s3_datalake" && integrations[index] !== "gcs_datalake" && integrations[index] !== "azure_datalake") .forEach((transformer, index) => { i.message.properties = largeNoOfColumnsevent; expect(() => transformer.process(i)).toThrow( @@ -984,13 +999,13 @@ describe("Add auto generated messageId for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toMatch(/auto-.*/); }); }); @@ -1007,10 +1022,10 @@ describe("Add receivedAt for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "received_at") + integrationCasedString(integrations[index], "received_at") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integration(index), "received_at") + integrationCasedString(integrations[index], "received_at") ); }); }); @@ -1023,22 +1038,22 @@ describe("Integration options", () => { const i = opInput("track"); transformers.forEach((transformer, index) => { const {jsonPaths} = i.destination.Config; - if (integration(index) === "postgres") { + if (integrations[index] === "postgres") { delete i.destination.Config.jsonPaths; } const received = transformer.process(i); i.destination.Config.jsonPaths = jsonPaths; - expect(received).toEqual(opOutput("track", integration(index))); + expect(received).toEqual(opOutput("track", integrations[index])); }); }); }); describe("users", () => { it("should skip users when skipUsersTable is set", () => { - const i = opInput("users"); + const i = opInput("identify"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toEqual(opOutput("users", integration(index))); + expect(received).toEqual(opOutput("identify", integrations[index])); }); }); }); @@ -1054,6 +1069,8 @@ describe("Integration options", () => { return _.cloneDeep(config.output.postgres); case "snowflake": return _.cloneDeep(config.output.snowflake); + case "snowpipe_streaming": + return _.cloneDeep(config.output.snowpipe_streaming); case "s3_datalake": case "gcs_datalake": case "azure_datalake": @@ -1093,18 +1110,18 @@ describe("Integration options", () => { for (const testCase of testCases) { transformers.forEach((transformer, index) => { - it(`new ${testCase.eventType} for ${integration(index)}`, () => { + it(`new ${testCase.eventType} for ${integrations[index]}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/new/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integration(index))); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) - it(`legacy ${testCase.eventType} for ${integration(index)}`, () => { + it(`legacy ${testCase.eventType} for ${integrations[index]}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/legacy/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integration(index))); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) }); } @@ -1242,7 +1259,10 @@ describe("Destination config", () => { transformers.forEach((transformer, index) => { const received = transformer.process(scenario.event); - expect(received).toHaveLength(scenario.expected.length); + const expectedLength = integrations[index] === "snowpipe_streaming" && scenario.event.message.type === "identify" + ? 1 + : scenario.expected.length; + expect(received).toHaveLength(expectedLength); for (const i in received) { const evt = received[i]; expect(evt.data.id ? evt.data.id : evt.data.ID).toEqual(scenario.expected[i].id); @@ -1285,7 +1305,9 @@ describe("Destination config", () => { } } const output = transformer.process(event); - const events = [output[0], output[1]]; // identifies and users event + const events = integrations[index] === "snowpipe_streaming" + ? [output[0]] + : [output[0], output[1]]; const traitsToCheck = { 'city': 'Disney', 'country': 'USA', @@ -1294,10 +1316,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data[integrationCasedString(integration(index), trait)]).toEqual(value); - expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); + expect(event.data[integrationCasedString(integrations[index], trait)]).toEqual(value); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); }); }); }); @@ -1325,13 +1347,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); - expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); - expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); - expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v_2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v_2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); }); }); }); @@ -1364,7 +1386,10 @@ describe("Destination config", () => { } } const received = transformer.process(event); - const events = [received[0], received[1]]; // identifies and users event + const events = integrations[index] === "snowpipe_streaming" + ? [received[0]] + : [received[0], received[1]]; + // identifies and users event const traitsToCheck = { 'city': 'Disney', 'country': 'USA', @@ -1373,10 +1398,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data).not.toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); + expect(event.data).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); }); }); }); @@ -1402,13 +1427,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); - expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); - expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); - expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); }); }); }); @@ -1615,8 +1640,8 @@ describe("context traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/context_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } }); } @@ -1708,8 +1733,8 @@ describe("group traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/group_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } }); }); From ebcf84e07bf121d882c99df973af265a915a1ce1 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Mon, 9 Dec 2024 13:10:01 +0530 Subject: [PATCH 138/147] fix: braze subscription group fixes (#3901) --- src/util/prometheus.js | 12 ++ src/v0/destinations/braze/braze.util.test.js | 151 ++++++++++++++++-- src/v0/destinations/braze/config.js | 2 +- src/v0/destinations/braze/transform.js | 2 +- src/v0/destinations/braze/util.js | 54 ++++++- .../destinations/braze/processor/data.ts | 4 +- .../destinations/braze/router/data.ts | 33 +++- 7 files changed, 240 insertions(+), 18 deletions(-) diff --git a/src/util/prometheus.js b/src/util/prometheus.js index a4c12e4ea89..2a3a1fb22a8 100644 --- a/src/util/prometheus.js +++ b/src/util/prometheus.js @@ -520,6 +520,18 @@ class Prometheus { type: 'counter', labelNames: ['destination_id'], }, + { + name: 'braze_batch_subscription_size', + help: 'braze_batch_subscription_size', + type: 'gauge', + labelNames: ['destination_id'], + }, + { + name: 'braze_batch_subscription_combined_size', + help: 'braze_batch_subscription_combined_size', + type: 'gauge', + labelNames: ['destination_id'], + }, { name: 'mailjet_packing_size', help: 'mailjet_packing_size', diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 985f2434d50..7d10035233a 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -6,6 +6,7 @@ const { getPurchaseObjs, setAliasObject, handleReservedProperties, + combineSubscriptionGroups, } = require('./util'); const { processBatch } = require('./util'); const { @@ -958,7 +959,9 @@ describe('processBatch', () => { attributes: [{ id: i, name: 'test', xyz: 'abc' }], events: [{ id: i, event: 'test', xyz: 'abc' }], purchases: [{ id: i, purchase: 'test', xyz: 'abc' }], - subscription_groups: [{ id: i, group: 'test', xyz: 'abc' }], + subscription_groups: [ + { subscription_group_id: i, group: 'test', subscription_state: 'abc' }, + ], merge_updates: [{ id: i, alias: 'test', xyz: 'abc' }], }, }, @@ -972,7 +975,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(8); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -981,10 +984,12 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.attributes.length).toBe(25); // Second batch contains remaining 25 attributes expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(25); // Second batch contains remaining 25 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(25); // Second batch contains remaining 25 purchases - expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); - expect(result[0].batchedRequest[4].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates + expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Third batch contains 25 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(25); // Fourth batch contains 25 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[7].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates }); test('processBatch handles more than 75 attributes, events, and purchases with non uniform distribution', () => { @@ -1055,7 +1060,9 @@ describe('processBatch', () => { batchedRequest: { body: { JSON: { - subscription_groups: [{ id: i, group: 'test', xyz: 'abc' }], + subscription_groups: [ + { subscription_group_id: i, group: 'test', subscription_state: 'abc' }, + ], }, }, }, @@ -1093,7 +1100,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response expect(result[0].metadata.length).toBe(490); // Check the total length is same as input jobs (120 + 160 + 100 + 70 +40) - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(7); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -1103,9 +1110,10 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(45); // Second batch contains remaining 45 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(75); // Second batch contains remaining 75 purchases expect(result[0].batchedRequest[2].body.JSON.purchases.length).toBe(10); // Third batch contains remaining 10 purchases - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(20); // Second batch contains 20 subscription group - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(40); // First batch contains 40 merge_updates + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(20); // Third batch contains 20 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates }); test('check success and failure scenarios both for processBatch', () => { @@ -1751,3 +1759,124 @@ describe('handleReservedProperties', () => { }); }); }); + +describe('combineSubscriptionGroups', () => { + it('should merge external_ids, emails, and phones for the same subscription_group_id and subscription_state', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1', 'id2'], + emails: ['email1@example.com', 'email2@example.com'], + phones: ['+1234567890', '+0987654321'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id2', 'id3'], + emails: ['email2@example.com', 'email3@example.com'], + phones: ['+1234567890', '+1122334455'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1', 'id2', 'id3'], + emails: ['email1@example.com', 'email2@example.com', 'email3@example.com'], + phones: ['+1234567890', '+0987654321', '+1122334455'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should handle groups with missing external_ids, emails, or phones', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + emails: ['email1@example.com'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + phones: ['+1234567890'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + emails: ['email1@example.com'], + phones: ['+1234567890'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should handle multiple unique subscription groups', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group2', + subscription_state: 'Unsubscribed', + external_ids: ['id2'], + emails: ['email2@example.com'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group2', + subscription_state: 'Unsubscribed', + external_ids: ['id2'], + emails: ['email2@example.com'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should not include undefined fields in the output', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); +}); diff --git a/src/v0/destinations/braze/config.js b/src/v0/destinations/braze/config.js index 2bbade2754d..8ccabbdb0a8 100644 --- a/src/v0/destinations/braze/config.js +++ b/src/v0/destinations/braze/config.js @@ -36,7 +36,7 @@ const IDENTIFY_BRAZE_MAX_REQ_COUNT = 50; // https://www.braze.com/docs/api/endpoints/user_data/post_user_delete/ const ALIAS_BRAZE_MAX_REQ_COUNT = 50; -const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 50; +const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 25; const DEL_MAX_BATCH_SIZE = 50; const DESTINATION = 'braze'; diff --git a/src/v0/destinations/braze/transform.js b/src/v0/destinations/braze/transform.js index 09fb0205c58..2a9cb8e7dcb 100644 --- a/src/v0/destinations/braze/transform.js +++ b/src/v0/destinations/braze/transform.js @@ -383,7 +383,7 @@ function processGroup(message, destination) { ); } subscriptionGroup.subscription_state = message.traits.subscriptionState; - subscriptionGroup.external_id = [message.userId]; + subscriptionGroup.external_ids = [message.userId]; const phone = getFieldValueFromMessage(message, 'phone'); const email = getFieldValueFromMessage(message, 'email'); if (phone) { diff --git a/src/v0/destinations/braze/util.js b/src/v0/destinations/braze/util.js index 6c8cf64265f..3778c34c43c 100644 --- a/src/v0/destinations/braze/util.js +++ b/src/v0/destinations/braze/util.js @@ -45,6 +45,42 @@ const getEndpointFromConfig = (destination) => { return endpoint; }; +// Merges external_ids, emails, and phones for entries with the same subscription_group_id and subscription_state +const combineSubscriptionGroups = (subscriptionGroups) => { + const uniqueGroups = {}; + + subscriptionGroups.forEach((group) => { + const key = `${group.subscription_group_id}-${group.subscription_state}`; + if (!uniqueGroups[key]) { + uniqueGroups[key] = { + ...group, + external_ids: [...(group.external_ids || [])], + emails: [...(group.emails || [])], + phones: [...(group.phones || [])], + }; + } else { + uniqueGroups[key].external_ids.push(...(group.external_ids || [])); + uniqueGroups[key].emails.push(...(group.emails || [])); + uniqueGroups[key].phones.push(...(group.phones || [])); + } + }); + + return Object.values(uniqueGroups).map((group) => { + const result = { + subscription_group_id: group.subscription_group_id, + subscription_state: group.subscription_state, + external_ids: [...new Set(group.external_ids)], + }; + if (group.emails?.length) { + result.emails = [...new Set(group.emails)]; + } + if (group.phones?.length) { + result.phones = [...new Set(group.phones)]; + } + return result; + }); +}; + const CustomAttributeOperationUtil = { customAttributeUpdateOperation(key, data, traits, mergeObjectsUpdateOperation) { data[key] = {}; @@ -381,8 +417,22 @@ function prepareGroupAndAliasBatch(arrayChunks, responseArray, destination, type } else if (type === 'subscription') { response.endpoint = getSubscriptionGroupEndPoint(getEndpointFromConfig(destination)); const subscription_groups = chunk; + // maketool transformed event + logger.info(`braze subscription chunk ${JSON.stringify(subscription_groups)}`); + + stats.gauge('braze_batch_subscription_size', subscription_groups.length, { + destination_id: destination.ID, + }); + + // Deduplicate the subscription groups before constructing the response body + const deduplicatedSubscriptionGroups = combineSubscriptionGroups(subscription_groups); + + stats.gauge('braze_batch_subscription_combined_size', deduplicatedSubscriptionGroups.length, { + destination_id: destination.ID, + }); + response.body.JSON = removeUndefinedAndNullValues({ - subscription_groups, + subscription_groups: deduplicatedSubscriptionGroups, }); } responseArray.push({ @@ -490,6 +540,7 @@ const processBatch = (transformedEvents) => { prepareGroupAndAliasBatch(mergeUsersArrayChunks, responseArray, destination, 'merge'); if (successMetadata.length > 0) { + console.log(`Response 1 batchRequest ${JSON.stringify(responseArray)}`); finalResponse.push({ batchedRequest: responseArray, metadata: successMetadata, @@ -756,4 +807,5 @@ module.exports = { collectStatsForAliasFailure, collectStatsForAliasMissConfigurations, handleReservedProperties, + combineSubscriptionGroups, }; diff --git a/test/integrations/destinations/braze/processor/data.ts b/test/integrations/destinations/braze/processor/data.ts index 240206791e1..9b6f6dac65b 100644 --- a/test/integrations/destinations/braze/processor/data.ts +++ b/test/integrations/destinations/braze/processor/data.ts @@ -3160,7 +3160,7 @@ export const data = [ { subscription_group_id: '1234', subscription_state: 'subscribed', - external_id: ['Randomuser2222'], + external_ids: ['Randomuser2222'], phones: ['5055077683'], }, ], @@ -3281,7 +3281,7 @@ export const data = [ { subscription_group_id: '1234', subscription_state: 'unsubscribed', - external_id: ['Randomuser2222'], + external_ids: ['Randomuser2222'], emails: ['abc@test.com'], }, ], diff --git a/test/integrations/destinations/braze/router/data.ts b/test/integrations/destinations/braze/router/data.ts index 6803742e862..b788e227413 100644 --- a/test/integrations/destinations/braze/router/data.ts +++ b/test/integrations/destinations/braze/router/data.ts @@ -219,6 +219,34 @@ export const data = [ metadata: { jobId: 6, userId: 'u1' }, message: { type: 'alias', previousId: 'adsfsaf2', userId: 'dsafsdf2' }, }, + { + destination: { + Config: { + restApiKey: 'dummyApiKey', + prefixProperties: true, + useNativeSDK: false, + dataCenter: 'us-01', + enableSubscriptionGroupInGroupCall: true, + }, + DestinationDefinition: { + DisplayName: 'Braze', + ID: '1WhbSZ6uA3H5ChVifHpfL2H6sie', + Name: 'BRAZE', + }, + Enabled: true, + ID: '1WhcOCGgj9asZu850HvugU2C3Aq', + Name: 'Braze', + Transformations: [], + }, + metadata: { jobId: 7, userId: 'u1' }, + message: { + anonymousId: '56yrtsdfgbgxcb-22b4-401d-aae5-1b994be9afdf', + groupId: 'c90f0fd2-2a02-4f2f-bf07-7e7d2c2ed2b1', + traits: { phone: '5055077683', subscriptionState: 'subscribed' }, + userId: 'user12345', + type: 'group', + }, + }, ], destType: 'braze', }, @@ -299,13 +327,13 @@ export const data = [ JSON: { subscription_groups: [ { - external_id: ['user123'], + external_ids: ['user123', 'user12345'], phones: ['5055077683'], subscription_group_id: 'c90f0fd2-2a02-4f2f-bf07-7e7d2c2ed2b1', subscription_state: 'subscribed', }, { - external_id: ['user877'], + external_ids: ['user877'], phones: ['5055077683'], subscription_group_id: '58d0a278-b55b-4f10-b7d2-98d1c5dd4c30', subscription_state: 'subscribed', @@ -356,6 +384,7 @@ export const data = [ { jobId: 4, userId: 'u1' }, { jobId: 5, userId: 'u1' }, { jobId: 6, userId: 'u1' }, + { jobId: 7, userId: 'u1' }, ], batched: true, statusCode: 200, From a2462934b289fd8d43c5586640945c47de6f21fd Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 9 Dec 2024 10:18:19 +0000 Subject: [PATCH 139/147] chore(release): 1.86.0 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb1779fd3a5..e742ea1f553 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.86.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.1...v1.86.0) (2024-12-09) + + +### Features + +* add support for getting anonymousId by note attributes array ([53d2bef](https://github.com/rudderlabs/rudder-transformer/commit/53d2bef38ad5d7bc5504111ec797b3c3973546dd)) +* add support for getting anonymousId by note attributes array ([#3893](https://github.com/rudderlabs/rudder-transformer/issues/3893)) ([d7f390c](https://github.com/rudderlabs/rudder-transformer/commit/d7f390cb471e44afb276484b8b804d1f257c539c)) + + +### Bug Fixes + +* braze subscription group fixes ([#3901](https://github.com/rudderlabs/rudder-transformer/issues/3901)) ([ebcf84e](https://github.com/rudderlabs/rudder-transformer/commit/ebcf84e07bf121d882c99df973af265a915a1ce1)) +* remove redundant ids and userIdentifier when gbraid or wbraid are there ([#3910](https://github.com/rudderlabs/rudder-transformer/issues/3910)) ([313710c](https://github.com/rudderlabs/rudder-transformer/commit/313710ca725538e5ffe357216d9c88e444f995c8)) +* skipping users events for snowpipe streaming ([#3836](https://github.com/rudderlabs/rudder-transformer/issues/3836)) ([12621c8](https://github.com/rudderlabs/rudder-transformer/commit/12621c8eee641f5a03a997e95ed016cff0eefde7)) + ### [1.85.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.0...v1.85.1) (2024-11-21) diff --git a/package-lock.json b/package-lock.json index 40033e278be..991d341e9f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.85.1", + "version": "1.86.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.85.1", + "version": "1.86.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index e0b17a4f47f..407ee1d1ab5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.85.1", + "version": "1.86.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { From 5f299de8c899e6924760c4537a9213a44d6aaf10 Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:16:50 +0530 Subject: [PATCH 140/147] refactor: code to address sonar issues (#3926) * refactor: code to address sonar issues * refactor: garl record transform --- package-lock.json | 4 +- .../v2/destinations/pinterest_tag/utils.js | 62 +++--- src/v0/destinations/amazon_audience/utils.js | 3 +- .../recordTransform.js | 207 ++++++------------ 4 files changed, 94 insertions(+), 182 deletions(-) diff --git a/package-lock.json b/package-lock.json index 40033e278be..14832566c55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10621,7 +10621,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", diff --git a/src/cdk/v2/destinations/pinterest_tag/utils.js b/src/cdk/v2/destinations/pinterest_tag/utils.js index 31a897f1338..dbaeea95011 100644 --- a/src/cdk/v2/destinations/pinterest_tag/utils.js +++ b/src/cdk/v2/destinations/pinterest_tag/utils.js @@ -1,8 +1,8 @@ -/* eslint-disable no-param-reassign */ const sha256 = require('sha256'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { API_VERSION } = require('./config'); +const { CommonUtils } = require('../../../../util/common'); const VALID_ACTION_SOURCES = ['app_android', 'app_ios', 'web', 'offline']; @@ -21,9 +21,15 @@ const ecomEventMaps = [ }, ]; -const USER_NON_ARRAY_PROPERTIES = ['client_user_agent', 'client_ip_address']; +const USER_NON_ARRAY_PROPERTIES = [ + 'client_user_agent', + 'client_ip_address', + 'click_id', + 'partner_id', +]; -const getHashedValue = (key, value) => { +const transformValue = (key, value) => { + const arrayValue = CommonUtils.toArray(value); switch (key) { case 'em': case 'ct': @@ -32,33 +38,18 @@ const getHashedValue = (key, value) => { case 'ln': case 'fn': case 'ge': - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().toLowerCase()) - : value.toString().trim().toLowerCase(); - break; + return arrayValue.map((val) => val.toString().trim().toLowerCase()); case 'ph': - // phone numbers should only contain digits & should not contain leading zeros - value = Array.isArray(value) - ? value.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')) - : value.toString().replace(/\D/g, '').replace(/^0+/, ''); - break; + return arrayValue.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')); case 'zp': - // zip fields should only contain digits - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().replace(/\D/g, '')) - : value.toString().replace(/\D/g, ''); - break; - case 'hashed_maids': - case 'external_id': - case 'db': - // no action needed on value - break; + return arrayValue.map((val) => val.toString().trim().replace(/\D/g, '')); default: - return String(value); + return arrayValue; } - return Array.isArray(value) ? value.map((val) => sha256(val)) : [sha256(value)]; }; +const getHashedValue = (key, value) => transformValue(key, value).map((val) => sha256(val)); + /** * * @param {*} userPayload Payload mapped from user fields @@ -67,10 +58,15 @@ const getHashedValue = (key, value) => { * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html */ const processUserPayload = (userPayload) => { - Object.keys(userPayload).forEach((key) => { - userPayload[key] = getHashedValue(key, userPayload[key]); + const newPayload = { ...userPayload }; + Object.keys(newPayload).forEach((key) => { + if (USER_NON_ARRAY_PROPERTIES.includes(key)) { + newPayload[key] = String(newPayload[key]); + } else { + newPayload[key] = getHashedValue(key, newPayload[key]); + } }); - return userPayload; + return newPayload; }; /** @@ -99,11 +95,7 @@ const processHashedUserPayload = (userPayload, message) => { const processedHashedUserPayload = {}; Object.keys(userPayload).forEach((key) => { if (!USER_NON_ARRAY_PROPERTIES.includes(key)) { - if (Array.isArray(userPayload[key])) { - processedHashedUserPayload[key] = [...userPayload[key]]; - } else { - processedHashedUserPayload[key] = [userPayload[key]]; - } + processedHashedUserPayload[key] = CommonUtils.toArray(userPayload[key]); } else { processedHashedUserPayload[key] = userPayload[key]; } @@ -111,10 +103,8 @@ const processHashedUserPayload = (userPayload, message) => { // multiKeyMap will works on only specific values like m, male, MALE, f, F, Female // if hashed data is sent from the user, it is directly set over here const gender = message.traits?.gender || message.context?.traits?.gender; - if (gender && Array.isArray(gender)) { - processedHashedUserPayload.ge = [...gender]; - } else if (gender) { - processedHashedUserPayload.ge = [gender]; + if (gender) { + processedHashedUserPayload.ge = CommonUtils.toArray(gender); } return processedHashedUserPayload; }; diff --git a/src/v0/destinations/amazon_audience/utils.js b/src/v0/destinations/amazon_audience/utils.js index c25f3013782..350d071a470 100644 --- a/src/v0/destinations/amazon_audience/utils.js +++ b/src/v0/destinations/amazon_audience/utils.js @@ -21,7 +21,8 @@ const buildResponseWithUsers = (users, action, config, jobIdList, secret) => { if (!secret?.clientId) { throw new OAuthSecretError('OAuth - Client Id not found'); } - const externalId = `Rudderstack_${sha256(`${jobIdList}`)}`; + const jobIdHash = sha256(String(jobIdList)); + const externalId = `Rudderstack_${jobIdHash}`; const response = defaultRequestConfig(); response.endpoint = ''; response.method = defaultPostRequestConfig.requestMethod; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index 5866b665385..c3bf27a75d0 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -1,4 +1,3 @@ -/* eslint-disable no-const-assign */ const lodash = require('lodash'); const { InstrumentationError } = require('@rudderstack/integrations-lib'); const { @@ -19,29 +18,22 @@ const { const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); -const processRecordEventArray = ( - records, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - operationType, -) => { - let outputPayloads = {}; - // ** only send it if identifier > 0 - - const fieldsArray = []; - const metadata = []; - records.forEach((record) => { - fieldsArray.push(record.message.fields); - metadata.push(record.metadata); - }); +const processRecordEventArray = (records, context, operationType) => { + const { + message, + destination, + accessToken, + developerToken, + audienceId, + typeOfList, + userSchema, + isHashRequired, + userDataConsent, + personalizationConsent, + } = context; + + const fieldsArray = records.map((record) => record.message.fields); + const metadata = records.map((record) => record.metadata); const userIdentifiersList = populateIdentifiersForRecordEvent( fieldsArray, @@ -51,131 +43,60 @@ const processRecordEventArray = ( ); const outputPayload = constructPayload(message, offlineDataJobsMapping); - outputPayload.operations = []; - // breaking the userIdentiFier array in chunks of 20 + const userIdentifierChunks = returnArrayOfSubarrays(userIdentifiersList, 20); - // putting each chunk in different create/remove operations - switch (operationType) { - case 'add': - // for add operation - userIdentifierChunks.forEach((element) => { - const operations = { - create: {}, - }; - operations.create.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, create: outputPayload }; - break; - case 'remove': - // for remove operation - userIdentifierChunks.forEach((element) => { - const operations = { - remove: {}, - }; - operations.remove.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, remove: outputPayload }; - break; - default: - } + outputPayload.operations = userIdentifierChunks.map((chunk) => ({ + [operationType]: { userIdentifiers: chunk }, + })); - const toSendEvents = []; - Object.values(outputPayloads).forEach((data) => { - const consentObj = populateConsentFromConfig( - { userDataConsent, personalizationConsent }, - consentConfigMap, - ); - toSendEvents.push( - responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), - ); - }); + const consentObj = populateConsentFromConfig( + { userDataConsent, personalizationConsent }, + consentConfigMap, + ); - const successResponse = getSuccessRespEvents(toSendEvents, metadata, destination, true); + const toSendEvents = [outputPayload].map((data) => + responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), + ); - return successResponse; + return getSuccessRespEvents(toSendEvents, metadata, destination, true); }; -function preparepayload(events, config) { +function preparePayload(events, config) { const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); - const { - audienceId, - typeOfList, - isHashRequired, - userSchema, - userDataConsent, - personalizationConsent, - } = config; + + const context = { + message, + destination, + accessToken, + developerToken, + ...config, + }; const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), ); - let insertResponse; - let deleteResponse; - let updateResponse; - - if (groupedRecordsByAction.delete) { - deleteResponse = processRecordEventArray( - groupedRecordsByAction.delete, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'remove', - ); - } - - if (groupedRecordsByAction.insert) { - insertResponse = processRecordEventArray( - groupedRecordsByAction.insert, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } - - if (groupedRecordsByAction.update) { - updateResponse = processRecordEventArray( - groupedRecordsByAction.update, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } + const actionResponses = ['delete', 'insert', 'update'].reduce((responses, action) => { + const operationType = action === 'delete' ? 'remove' : 'create'; + if (groupedRecordsByAction[action]) { + return { + ...responses, + [action]: processRecordEventArray(groupedRecordsByAction[action], context, operationType), + }; + } + return responses; + }, {}); const errorResponse = getErrorResponse(groupedRecordsByAction); const finalResponse = createFinalResponse( - deleteResponse, - insertResponse, - updateResponse, + actionResponses.delete, + actionResponses.insert, + actionResponses.update, errorResponse, ); + if (finalResponse.length === 0) { throw new InstrumentationError( 'Missing valid parameters, unable to generate transformed payload', @@ -196,14 +117,16 @@ function processRecordInputsV0(groupedRecordInputs) { personalizationConsent, } = destination.Config; - return preparepayload(groupedRecordInputs, { + const config = { audienceId: getOperationAudienceId(audienceId, message), typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(groupedRecordInputs, config); } function processRecordInputsV1(groupedRecordInputs) { @@ -211,11 +134,7 @@ function processRecordInputsV1(groupedRecordInputs) { const { audienceId, typeOfList, isHashRequired, userDataConsent, personalizationConsent } = connection.config.destination; - const identifiers = message?.identifiers; - let userSchema; - if (identifiers) { - userSchema = Object.keys(identifiers); - } + const userSchema = message?.identifiers ? Object.keys(message.identifiers) : undefined; const events = groupedRecordInputs.map((record) => ({ ...record, @@ -225,23 +144,23 @@ function processRecordInputsV1(groupedRecordInputs) { }, })); - return preparepayload(events, { + const config = { audienceId, typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(events, config); } function processRecordInputs(groupedRecordInputs) { const event = groupedRecordInputs[0]; - // First check for rETL flow and second check for ES flow - if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) { - return processRecordInputsV0(groupedRecordInputs); - } - return processRecordInputsV1(groupedRecordInputs); + return isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event) + ? processRecordInputsV0(groupedRecordInputs) + : processRecordInputsV1(groupedRecordInputs); } module.exports = { From aa352ab50bcb93df692774c8f2ee49531486a387 Mon Sep 17 00:00:00 2001 From: AASHISH MALIK Date: Tue, 10 Dec 2024 14:44:21 +0530 Subject: [PATCH 141/147] fix: removed console statement (#3927) --- src/v0/destinations/braze/util.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/v0/destinations/braze/util.js b/src/v0/destinations/braze/util.js index 3778c34c43c..74cb7fb9533 100644 --- a/src/v0/destinations/braze/util.js +++ b/src/v0/destinations/braze/util.js @@ -540,7 +540,6 @@ const processBatch = (transformedEvents) => { prepareGroupAndAliasBatch(mergeUsersArrayChunks, responseArray, destination, 'merge'); if (successMetadata.length > 0) { - console.log(`Response 1 batchRequest ${JSON.stringify(responseArray)}`); finalResponse.push({ batchedRequest: responseArray, metadata: successMetadata, From 31e422c2654326126bb3eda79b2520935af3f785 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Tue, 10 Dec 2024 16:06:36 +0530 Subject: [PATCH 142/147] chore: fix build workflow (#3928) --- .github/workflows/build-push-docker-image.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index c7e59dce86a..49162e433be 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -96,15 +96,15 @@ jobs: with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - + - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 - name: Build Docker Image uses: docker/build-push-action@v6.9.0 @@ -149,16 +149,16 @@ jobs: with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - + - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 + - name: Build Docker Image uses: docker/build-push-action@v6.9.0 with: From 6a0f47511f1bb0a57406bfbac4aa0c2f64bfb548 Mon Sep 17 00:00:00 2001 From: Utsab Chowdhury Date: Tue, 10 Dec 2024 16:30:34 +0530 Subject: [PATCH 143/147] chore: fix build workflow (#3929) --- .github/workflows/build-push-docker-image.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index 49162e433be..ba62e5d8d17 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -198,15 +198,15 @@ jobs: needs: [build-transformer-image-amd64, build-transformer-image-arm64] steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 + - name: Create multi-arch manifest run: | docker buildx imagetools create -t ${{ inputs.push_tags }} ${{ inputs.push_tags }}-amd64 ${{ inputs.push_tags }}-arm64 From 325dabe1070b5a2bf3a84b12ce10f19abf40a6a8 Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:45:08 +0530 Subject: [PATCH 144/147] chore: remove references to legacy consent management fields (#3931) --- src/v0/destinations/braze/braze.util.test.js | 1 - .../data_scenarios/cdk_v2/failure.json | 9 +-- .../data_scenarios/cdk_v2/success.json | 9 +-- .../destination/batch/failure_batch.json | 20 ++---- .../destination/batch/successful_batch.json | 16 ++--- .../proc/batch_input_multiplex.json | 6 +- .../destination/proc/multiplex_failure.json | 3 +- .../proc/multiplex_partial_failure.json | 6 +- .../destination/proc/multiplex_success.json | 3 +- .../destination/router/failure_test.json | 15 ++--- .../destinations/algolia/router/data.ts | 20 ++---- .../destinations/braze/router/data.ts | 7 --- .../destinations/candu/processor/data.ts | 63 +++---------------- .../destinations/candu/router/data.ts | 14 +---- .../destinations/clicksend/commonConfig.ts | 5 -- .../destinations/clicksend/router/data.ts | 5 -- .../destinations/emarsys/deleteUsers/data.ts | 20 ------ .../destinations/emarsys/processor/data.ts | 55 ---------------- .../destinations/emarsys/router/data.ts | 5 -- .../fb_custom_audience/router/data.ts | 4 -- .../fb_custom_audience/router/rETL.ts | 2 - .../destinations/gainsight_px/router/data.ts | 2 +- .../router/data.ts | 7 --- .../destinations/hs/router/data.ts | 60 ------------------ .../processor/configLevelFeaturesTestData.ts | 5 -- .../linkedin_ads/processor/trackTestData.ts | 5 -- .../processor/validationTestData.ts | 5 -- .../destinations/linkedin_ads/router/data.ts | 5 -- .../destinations/rockerbox/processor/data.ts | 28 --------- .../destinations/rockerbox/router/data.ts | 12 ---- .../tune/processor/trackTestData.ts | 2 - .../destinations/tune/router/data.ts | 2 - .../destinations/webhook/processor/data.ts | 4 +- test/integrations/destinations/zoho/common.ts | 25 -------- 34 files changed, 44 insertions(+), 406 deletions(-) diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 7d10035233a..6fe4dbbb44e 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -255,7 +255,6 @@ describe('dedup utility tests', () => { enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'test-rest-api-key', supportDedup: true, trackAnonymousUser: true, diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 154d24481dc..c252761e881 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index 88f430dd7c2..ce819c3f80d 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/batch/failure_batch.json b/test/apitests/data_scenarios/destination/batch/failure_batch.json index 6352ca1a11f..80595e44f42 100644 --- a/test/apitests/data_scenarios/destination/batch/failure_batch.json +++ b/test/apitests/data_scenarios/destination/batch/failure_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -576,8 +574,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -612,7 +609,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -933,8 +929,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -969,7 +964,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1247,8 +1241,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1283,7 +1276,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1722,8 +1714,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1758,7 +1749,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/batch/successful_batch.json b/test/apitests/data_scenarios/destination/batch/successful_batch.json index 32745f49d51..45ceb1a5450 100644 --- a/test/apitests/data_scenarios/destination/batch/successful_batch.json +++ b/test/apitests/data_scenarios/destination/batch/successful_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -578,8 +576,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -614,7 +611,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -935,8 +931,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -971,7 +966,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1557,8 +1551,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1593,7 +1586,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3deb7d4b8ba..c24dd08e8dc 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json index 68c7fc3baa9..d08949ffb6a 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json @@ -93,7 +93,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -107,7 +107,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index a2652855d56..78e067e84b1 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index ba4d5266f30..2b05a2fad82 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 197456f66af..4b341142e9e 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -157,7 +157,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -171,7 +171,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -395,7 +394,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -409,7 +408,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -633,7 +631,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -647,7 +645,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1018,7 +1015,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1032,7 +1029,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1234,7 +1230,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1248,7 +1244,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/integrations/destinations/algolia/router/data.ts b/test/integrations/destinations/algolia/router/data.ts index dca899693e5..adc7be1596f 100644 --- a/test/integrations/destinations/algolia/router/data.ts +++ b/test/integrations/destinations/algolia/router/data.ts @@ -2007,7 +2007,6 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1687213909459, }, @@ -2017,16 +2016,11 @@ export const data = [ DestinationDefinition: { Config: { destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, secretKeys: ['apiKey', 'applicationId'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], transformAt: 'router', cdkV2Enabled: true, transformAtV1: 'router', @@ -2146,21 +2140,15 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], }, DestinationDefinition: { Config: { cdkV2Enabled: true, destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], saveDestinationResponse: true, secretKeys: ['apiKey', 'applicationId'], supportedMessageTypes: ['track'], diff --git a/test/integrations/destinations/braze/router/data.ts b/test/integrations/destinations/braze/router/data.ts index b788e227413..8ab04c5d04c 100644 --- a/test/integrations/destinations/braze/router/data.ts +++ b/test/integrations/destinations/braze/router/data.ts @@ -432,7 +432,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -502,7 +501,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -572,7 +570,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -626,7 +623,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -680,7 +676,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -833,7 +828,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -869,7 +863,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, diff --git a/test/integrations/destinations/candu/processor/data.ts b/test/integrations/destinations/candu/processor/data.ts index 6e5ae636bd4..22bd0b35672 100644 --- a/test/integrations/destinations/candu/processor/data.ts +++ b/test/integrations/destinations/candu/processor/data.ts @@ -21,12 +21,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -182,12 +177,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -347,12 +337,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -478,12 +463,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -619,12 +599,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -757,12 +732,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -894,12 +864,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1056,12 +1021,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1221,12 +1181,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/candu/router/data.ts b/test/integrations/destinations/candu/router/data.ts index e6c7d96a159..02e1caa3e93 100644 --- a/test/integrations/destinations/candu/router/data.ts +++ b/test/integrations/destinations/candu/router/data.ts @@ -20,12 +20,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -152,12 +147,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/clicksend/commonConfig.ts b/test/integrations/destinations/clicksend/commonConfig.ts index 815973b8d9f..c5c49e2b926 100644 --- a/test/integrations/destinations/clicksend/commonConfig.ts +++ b/test/integrations/destinations/clicksend/commonConfig.ts @@ -14,11 +14,6 @@ export const destination = { defaultSource: 'php', defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; diff --git a/test/integrations/destinations/clicksend/router/data.ts b/test/integrations/destinations/clicksend/router/data.ts index 3aa3c0abc49..54018787b03 100644 --- a/test/integrations/destinations/clicksend/router/data.ts +++ b/test/integrations/destinations/clicksend/router/data.ts @@ -18,11 +18,6 @@ const commonDestination = { defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', defaultSource: 'php', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, DestinationDefinition: { Config: { diff --git a/test/integrations/destinations/emarsys/deleteUsers/data.ts b/test/integrations/destinations/emarsys/deleteUsers/data.ts index 96b27cad0d5..2596e9648c6 100644 --- a/test/integrations/destinations/emarsys/deleteUsers/data.ts +++ b/test/integrations/destinations/emarsys/deleteUsers/data.ts @@ -64,11 +64,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -113,11 +108,6 @@ export const data = [ defaultContactList: undefined, eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -161,11 +151,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -210,11 +195,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], diff --git a/test/integrations/destinations/emarsys/processor/data.ts b/test/integrations/destinations/emarsys/processor/data.ts index badd14e7cc9..ddb61b83c7c 100644 --- a/test/integrations/destinations/emarsys/processor/data.ts +++ b/test/integrations/destinations/emarsys/processor/data.ts @@ -112,11 +112,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -285,11 +280,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -456,11 +446,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -599,11 +584,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -722,11 +702,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -842,11 +817,6 @@ export const data = [ emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -964,11 +934,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1093,11 +1058,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1220,11 +1180,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1346,11 +1301,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1463,11 +1413,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, diff --git a/test/integrations/destinations/emarsys/router/data.ts b/test/integrations/destinations/emarsys/router/data.ts index 5f6dad10776..4a7bcf93322 100644 --- a/test/integrations/destinations/emarsys/router/data.ts +++ b/test/integrations/destinations/emarsys/router/data.ts @@ -29,11 +29,6 @@ const config = { emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/fb_custom_audience/router/data.ts b/test/integrations/destinations/fb_custom_audience/router/data.ts index cfc24968a89..834b6315f6a 100644 --- a/test/integrations/destinations/fb_custom_audience/router/data.ts +++ b/test/integrations/destinations/fb_custom_audience/router/data.ts @@ -611,7 +611,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -687,7 +686,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -795,7 +793,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -951,7 +948,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/fb_custom_audience/router/rETL.ts b/test/integrations/destinations/fb_custom_audience/router/rETL.ts index 0ba7f8b5317..f8d5fc89a03 100644 --- a/test/integrations/destinations/fb_custom_audience/router/rETL.ts +++ b/test/integrations/destinations/fb_custom_audience/router/rETL.ts @@ -8,7 +8,6 @@ const destinationV2: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -167,7 +166,6 @@ export const destinationV1: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/gainsight_px/router/data.ts b/test/integrations/destinations/gainsight_px/router/data.ts index 1b3d5be8756..3a5255f7d2c 100644 --- a/test/integrations/destinations/gainsight_px/router/data.ts +++ b/test/integrations/destinations/gainsight_px/router/data.ts @@ -57,7 +57,7 @@ const destination2 = { { from: 'inboxready_signup_date', to: 'inboxready_signup_date' }, { from: 'gpt_setup', to: 'gpt_setup' }, ], - oneTrustCookieCategories: [], + apiKey: 'sample-api-key', eventDelivery: false, eventDeliveryTS: 1624472902670, diff --git a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts index 82c8e9b3ff1..bcc718485b3 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts @@ -314,7 +314,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -390,7 +389,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -464,7 +462,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -674,7 +671,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -986,7 +982,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -1152,7 +1147,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', @@ -1265,7 +1259,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', diff --git a/test/integrations/destinations/hs/router/data.ts b/test/integrations/destinations/hs/router/data.ts index b47d6b7f07e..2f0879528bf 100644 --- a/test/integrations/destinations/hs/router/data.ts +++ b/test/integrations/destinations/hs/router/data.ts @@ -1988,13 +1988,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2070,13 +2064,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2150,13 +2138,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2231,13 +2213,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2330,13 +2306,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2425,13 +2395,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2511,13 +2475,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2621,13 +2579,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2702,13 +2654,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2801,13 +2747,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, diff --git a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts index 287e35e5a71..29ff1f10a8c 100644 --- a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts index f9dfc528db7..53272e73bff 100644 --- a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts @@ -32,11 +32,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts index 5cb6ff8cf27..653ad320565 100644 --- a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/router/data.ts b/test/integrations/destinations/linkedin_ads/router/data.ts index cf7defe6af1..16abc0cd060 100644 --- a/test/integrations/destinations/linkedin_ads/router/data.ts +++ b/test/integrations/destinations/linkedin_ads/router/data.ts @@ -20,11 +20,6 @@ const config = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/rockerbox/processor/data.ts b/test/integrations/destinations/rockerbox/processor/data.ts index 76dd8ef11bb..4a64ff09f62 100644 --- a/test/integrations/destinations/rockerbox/processor/data.ts +++ b/test/integrations/destinations/rockerbox/processor/data.ts @@ -85,13 +85,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -206,13 +199,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -339,13 +325,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -501,13 +480,6 @@ export const data = [ clientAuthId: { web: '', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: '', - }, - ], - }, customDomain: { web: '', }, diff --git a/test/integrations/destinations/rockerbox/router/data.ts b/test/integrations/destinations/rockerbox/router/data.ts index af943d7e6b6..535b4f7da59 100644 --- a/test/integrations/destinations/rockerbox/router/data.ts +++ b/test/integrations/destinations/rockerbox/router/data.ts @@ -19,9 +19,6 @@ export const data = [ eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -108,9 +105,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, @@ -143,9 +137,6 @@ export const data = [ eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -232,9 +223,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, diff --git a/test/integrations/destinations/tune/processor/trackTestData.ts b/test/integrations/destinations/tune/processor/trackTestData.ts index 63178d0e339..d9bfab54e39 100644 --- a/test/integrations/destinations/tune/processor/trackTestData.ts +++ b/test/integrations/destinations/tune/processor/trackTestData.ts @@ -22,8 +22,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', diff --git a/test/integrations/destinations/tune/router/data.ts b/test/integrations/destinations/tune/router/data.ts index f21714d0580..4aee5b89673 100644 --- a/test/integrations/destinations/tune/router/data.ts +++ b/test/integrations/destinations/tune/router/data.ts @@ -17,8 +17,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', diff --git a/test/integrations/destinations/webhook/processor/data.ts b/test/integrations/destinations/webhook/processor/data.ts index 92fe8f50d93..7720bc683c8 100644 --- a/test/integrations/destinations/webhook/processor/data.ts +++ b/test/integrations/destinations/webhook/processor/data.ts @@ -3285,7 +3285,7 @@ export const data = [ Config: { webhookUrl: 'https://webhook.site/81dc2730-807f-4bbc-8914-5b37d21c8a55', webhookMethod: 'POST', - oneTrustCookieCategories: [], + connectionMode: 'cloud', eventDelivery: false, eventDeliveryTS: 1720497286192, @@ -3294,7 +3294,7 @@ export const data = [ Config: { secretKeys: ['headers.to'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories', 'consentManagement'], + includeKeys: ['consentManagement'], cdkV2Enabled: true, transformAtV1: 'processor', isAudienceSupported: true, diff --git a/test/integrations/destinations/zoho/common.ts b/test/integrations/destinations/zoho/common.ts index bea4437e6f5..1d89dbce6d7 100644 --- a/test/integrations/destinations/zoho/common.ts +++ b/test/integrations/destinations/zoho/common.ts @@ -65,11 +65,6 @@ const commonDeletionDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -186,11 +181,6 @@ const commonUpsertDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -225,11 +215,6 @@ const commonUpsertDestConfig2: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -264,11 +249,6 @@ const commonUpsertDestConfig2CustomModule: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -293,11 +273,6 @@ const commonUpsertDestConfig3: Destination = { module: 'Leads', trigger: 'workflow', addDefaultDuplicateCheck: true, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; From b7692c85adfb4c495ef12e1b31c6764b859ffc67 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Date: Wed, 11 Dec 2024 11:13:38 +0530 Subject: [PATCH 145/147] chore: silent testcase logs in local (#3932) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e0b17a4f47f..cb7379bb0fd 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ "test": "jest -c jest.config.js --detectOpenHandles", "test:ci": "npm run test -- --coverage --expand --maxWorkers=50%", "test:js": "jest -c jest.default.config.js --detectOpenHandles", - "test:js:silent": "npm run test:js -- --silent", + "test:js:silent": "export LOG_LEVEL=silent && npm run test:js -- --silent", "test:js:ci": "npm run test:js -- --coverage --expand --maxWorkers=50%", "test:ts": "jest -c jest.config.typescript.js --detectOpenHandles", "test:ts:component:generateNwMocks": "npm run test:ts -- component --generate=true", - "test:ts:silent": "npm run test:ts -- --silent", + "test:ts:silent": "export LOG_LEVEL=silent && npm run test:ts -- --silent", "test:ts:ci": "npm run test:ts -- --coverage --expand --maxWorkers=50%", "test:ut:integration": "jest \"user_transformation.integration.test.js\" --detectOpenHandles --notify", "test:ut:integration:silent": "npm run test:ut:integration -- --silent", From d40db6c1e7f71c5ab5fc3a3659d1fc51b6d527fa Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:43:17 +0530 Subject: [PATCH 146/147] fix: handling partial error in a batch for reddit destination (#3935) * fix: handling partial error in a batch for reddit destination * fix: minor change * fix: moving networkHandler to v1 from v0 * fix: sonarcloud code analysis --- .../v2/destinations/reddit/rtWorkflow.yaml | 6 +- src/cdk/v2/destinations/reddit/utils.js | 1 + .../destinations/reddit/networkHandler.js | 65 +++-- .../reddit/dataDelivery/business.ts | 136 ++++++++- .../destinations/reddit/dataDelivery/oauth.ts | 10 +- .../destinations/reddit/network.ts | 107 +++++++ .../destinations/reddit/router/data.ts | 266 ++++++++++++++++++ 7 files changed, 566 insertions(+), 25 deletions(-) rename src/{v0 => v1}/destinations/reddit/networkHandler.js (52%) diff --git a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml index 937ff021f44..fd315b381ab 100644 --- a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml +++ b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml @@ -36,7 +36,11 @@ steps: description: Batches the successfulEvents using endpoint condition: $.outputs.successfulEvents.length template: | - let batches = $.batchEvents($.outputs.successfulEvents); + const dontBatchTrueEvents = $.outputs.successfulEvents{.metadata.dontBatch}[]; + const dontBatchFalseEvents = $.outputs.successfulEvents{!.metadata.dontBatch}[]; + const dontBatchTrueEventsChunks = $.chunk(dontBatchTrueEvents, 1); + + let batches = [...$.batchEvents(dontBatchFalseEvents), ...$.batchEventChunks(dontBatchTrueEventsChunks)]; batches@batch.({ "batchedRequest": { "body": { diff --git a/src/cdk/v2/destinations/reddit/utils.js b/src/cdk/v2/destinations/reddit/utils.js index f562d31313f..e51a72142ac 100644 --- a/src/cdk/v2/destinations/reddit/utils.js +++ b/src/cdk/v2/destinations/reddit/utils.js @@ -81,6 +81,7 @@ const populateRevenueField = (eventType, properties) => { }; module.exports = { batchEvents, + batchEventChunks, populateRevenueField, calculateDefaultRevenue, }; diff --git a/src/v0/destinations/reddit/networkHandler.js b/src/v1/destinations/reddit/networkHandler.js similarity index 52% rename from src/v0/destinations/reddit/networkHandler.js rename to src/v1/destinations/reddit/networkHandler.js index 7c9b32eaa41..608408a7fbe 100644 --- a/src/v0/destinations/reddit/networkHandler.js +++ b/src/v1/destinations/reddit/networkHandler.js @@ -1,16 +1,31 @@ const { RetryableError, TAG_NAMES, NetworkError } = require('@rudderstack/integrations-lib'); const isString = require('lodash/isString'); const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network'); -const { isHttpStatusSuccess } = require('../../util/index'); +const { isHttpStatusSuccess } = require('../../../v0/util/index'); const { REFRESH_TOKEN } = require('../../../adapters/networkhandler/authConstants'); const { processAxiosResponse, getDynamicErrorType, } = require('../../../adapters/utils/networkUtils'); +const { TransformerProxyError } = require('../../../v0/util/errorTypes'); -const redditRespHandler = (destResponse) => { - const { status, response } = destResponse; +const populateResponseWithDontBatch = (rudderJobMetadata, response) => { + const errorMessage = JSON.stringify(response); + return rudderJobMetadata.map((metadata) => { + // eslint-disable-next-line no-param-reassign + metadata.dontBatch = true; + return { + statusCode: 500, + metadata, + error: errorMessage, + }; + }); +}; + +const redditRespHandler = (responseParams) => { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { status, response } = destinationResponse; // to handle the case when authorization-token is invalid if (status === 401) { @@ -28,26 +43,41 @@ const redditRespHandler = (destResponse) => { throw new RetryableError( `${errorMessage} during reddit response transformation`, status, - destResponse, + destinationResponse, authErrorCategory, ); } + if (status === 400 && Array.isArray(rudderJobMetadata) && rudderJobMetadata.length > 1) { + // sending back 500 for retry only when events came in a batch + const responseWithDontBatch = populateResponseWithDontBatch(rudderJobMetadata, response); + throw new TransformerProxyError( + `REDDIT: Error transformer proxy during REDDIT response transformation`, + 500, + { + [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(500), + }, + destinationResponse, + '', + responseWithDontBatch, + ); + } + throw new NetworkError( `${JSON.stringify(response)} during reddit response transformation`, status, { [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), }, - destResponse, + destinationResponse, ); }; const responseHandler = (responseParams) => { - const { destinationResponse } = responseParams; + const { destinationResponse, rudderJobMetadata } = responseParams; const message = `Request Processed Successfully`; const { status } = destinationResponse; if (!isHttpStatusSuccess(status)) { // if error, successfully return status, message and original destination response - redditRespHandler(destinationResponse); + redditRespHandler(responseParams); } const { response } = destinationResponse; const errorMessage = @@ -55,20 +85,23 @@ const responseHandler = (responseParams) => { ? response?.invalid_events[0]?.error_message : null; const destResp = errorMessage || destinationResponse; + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: 200, + metadata, + error: 'success', + })); // Mostly any error will not have a status of 2xx return { status, message, - destResp, + destinationResponse: destResp, + response: responseWithIndividualEvents, }; }; -// eslint-disable-next-line @typescript-eslint/naming-convention -class networkHandler { - constructor() { - this.responseHandler = responseHandler; - this.proxy = proxyRequest; - this.prepareProxy = prepareProxyRequest; - this.processAxiosResponse = processAxiosResponse; - } +function networkHandler() { + this.proxy = proxyRequest; + this.processAxiosResponse = processAxiosResponse; + this.prepareProxy = prepareProxyRequest; + this.responseHandler = responseHandler; } module.exports = { networkHandler }; diff --git a/test/integrations/destinations/reddit/dataDelivery/business.ts b/test/integrations/destinations/reddit/dataDelivery/business.ts index b48004a2ed3..cc2feccffa2 100644 --- a/test/integrations/destinations/reddit/dataDelivery/business.ts +++ b/test/integrations/destinations/reddit/dataDelivery/business.ts @@ -39,6 +39,71 @@ const validRequestPayload = { ], }; +const validRequestMultipleEventsInPayload = { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], +}; + const commonHeaders = { Authorization: 'Bearer dummyAccessToken', 'Content-Type': 'application/json', @@ -73,13 +138,14 @@ export const testScenariosForV0API = [ status: 200, body: { output: { - destResp: { + destinationResponse: { response: { message: 'Successfully processed 1 conversion events.', }, status: 200, }, - message: 'Request Processed Successfully', + message: + '[Generic Response Handler] Request for destination: reddit Processed Successfully', status: 200, }, }, @@ -116,8 +182,15 @@ export const testScenariosForV1API = [ body: { output: { message: 'Request Processed Successfully', + destinationResponse: { + response: { + message: 'Successfully processed 1 conversion events.', + }, + status: 200, + }, response: [ { + error: 'success', metadata: generateMetadata(1), statusCode: 200, }, @@ -180,4 +253,63 @@ export const testScenariosForV1API = [ }, }, }, + { + id: 'reddit_v1_scenario_3', + name: 'reddit', + description: + '[Proxy v1 API] :: Test for a valid request with a partial event failure from the destination', + scenario: 'PartialFailure', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + headers: commonHeaders, + JSON: validRequestMultipleEventsInPayload, + endpoint: + 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + }, + [generateMetadata(1), generateMetadata(2)], + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + message: 'REDDIT: Error transformer proxy during REDDIT response transformation', + response: [ + { + metadata: { ...generateMetadata(1), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + { + metadata: { ...generateMetadata(2), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + ], + statTags: { + destType: 'REDDIT', + destinationId: 'default-destinationId', + errorCategory: 'network', + errorType: 'retryable', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + status: 500, + }, + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/reddit/dataDelivery/oauth.ts b/test/integrations/destinations/reddit/dataDelivery/oauth.ts index 8c0d486a7a3..e3c5875a062 100644 --- a/test/integrations/destinations/reddit/dataDelivery/oauth.ts +++ b/test/integrations/destinations/reddit/dataDelivery/oauth.ts @@ -84,14 +84,13 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: 'Authorization Required', status: 401, }, message: - 'Request failed due to Authorization Required during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, @@ -121,7 +120,6 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: { success: false, @@ -134,8 +132,8 @@ export const v0oauthScenarios = [ status: 401, }, message: - 'This server could not verify that you are authorized to access the document you requested. during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, diff --git a/test/integrations/destinations/reddit/network.ts b/test/integrations/destinations/reddit/network.ts index 80c18c00a0d..54d7a95b73e 100644 --- a/test/integrations/destinations/reddit/network.ts +++ b/test/integrations/destinations/reddit/network.ts @@ -210,4 +210,111 @@ export const networkCallsData = [ statusText: 'Unauthorized', }, }, + { + httpReq: { + url: 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + data: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], + }, + params: { destination: 'reddit' }, + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + method: 'POST', + }, + httpRes: { + data: { + message: 'There were 1 invalid conversion events. None were processed.', + invalid_events: [ + { + error_message: 'event_at timestamp must be less than 168h0m0s old', + event: { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + event_metadata: { + item_count: 0, + products: [{}], + conversion_id: 'c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + }, + }, + ], + }, + status: 400, + statusText: 'Bad Request', + }, + }, ]; diff --git a/test/integrations/destinations/reddit/router/data.ts b/test/integrations/destinations/reddit/router/data.ts index b5bed48ae77..f2dd887b849 100644 --- a/test/integrations/destinations/reddit/router/data.ts +++ b/test/integrations/destinations/reddit/router/data.ts @@ -178,6 +178,131 @@ export const data = [ userId: 'u1', }, }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + session_id: '16733896350494', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Order Completed', + userId: 'testuserId1', + properties: { + checkout_id: '12345', + order_id: '1234', + affiliation: 'Apple Store', + total: 20, + revenue: 15, + shipping: 4, + tax: 1, + discount: 1.5, + coupon: 'ImagePro', + currency: 'USD', + products: [ + { + product_id: '123', + sku: 'G-32', + name: 'Monopoly', + price: 14, + quantity: 1, + category: 'Games', + url: 'https://www.website.com/product/path', + image_url: 'https://www.website.com/product/path.jpg', + }, + { + product_id: '345', + sku: 'F-32', + name: 'UNO', + price: 3.45, + quantity: 2, + category: 'Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Product List Viewed', + userId: 'testuserId1', + properties: { + list_id: 'list1', + category: "What's New", + value: 2600, + value_decimal: 26, + products: [ + { + product_id: '017c6f5d5cf86a4b22432066', + sku: '8732-98', + name: 'Just Another Game', + price: 22, + position: 2, + category: 'Games and Entertainment', + url: 'https://www.myecommercewebsite.com/product', + image_url: 'https://www.myecommercewebsite.com/product/path.jpg', + }, + { + product_id: '89ac6f5d5cf86a4b64eac145', + sku: '1267-01', + name: 'Wrestling Trump Cards', + price: 4, + position: 21, + category: 'Card Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + }, ], destType: 'reddit', }, @@ -325,6 +450,147 @@ export const data = [ DestinationDefinition: { Config: { cdkV2Enabled: true } }, }, }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'Purchase' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 2, + currency: 'USD', + value: 1500, + value_decimal: 15, + products: [ + { id: '123', name: 'Monopoly', category: 'Games' }, + { id: '345', name: 'UNO', category: 'Games' }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'ViewContent' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 0, + value: 2600, + value_decimal: 26, + products: [ + { + id: '017c6f5d5cf86a4b22432066', + name: 'Just Another Game', + category: 'Games and Entertainment', + }, + { + id: '89ac6f5d5cf86a4b64eac145', + name: 'Wrestling Trump Cards', + category: 'Card Games', + }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, ], }, }, From 227419f1ff618f96aafa849862828e2315e4ac55 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:42:46 +0530 Subject: [PATCH 147/147] feat: onboard topsort destination (#3913) * chore: topsort changes * chore: boilerplates * chore: topsort changes * chore: function updates * chore: product array changes * chore: purchase event implementation * chore: purchase function updated * chore: build finalPayload * chore: few updations * chore: mockfn changes * chore: restructured files - moved impressions and clicks logic into its own file - moved purchase related logic into its own file * chore: update formatting * chore: test cases added * chore: destType updated --------- Co-authored-by: Utsab Chowdhury Co-authored-by: Sai Sankeerth --- src/features.ts | 1 + src/v0/destinations/topsort/config.js | 31 + .../data/TopSortPurchaseProductConfig.json | 24 + .../topsort/data/TopsortItemConfig.json | 15 + .../topsort/data/TopsortPlacementConfig.json | 36 ++ .../topsort/data/TopsortTrackConfig.json | 27 + .../topsort/impressions-and-clicks.js | 95 +++ src/v0/destinations/topsort/purchase.js | 56 ++ src/v0/destinations/topsort/transform.js | 158 +++++ src/v0/destinations/topsort/utils.js | 53 ++ src/v0/util/index.js | 8 + .../destinations/topsort/mocks.ts | 5 + .../destinations/topsort/processor/data.ts | 9 + .../topsort/processor/trackClicksTestData.ts | 571 ++++++++++++++++++ .../processor/trackImpressionsTestData.ts | 381 ++++++++++++ .../processor/trackPurchasesTestData.ts | 457 ++++++++++++++ .../destinations/topsort/router/data.ts | 418 +++++++++++++ test/integrations/testTypes.ts | 2 +- test/integrations/testUtils.ts | 1 + 19 files changed, 2347 insertions(+), 1 deletion(-) create mode 100644 src/v0/destinations/topsort/config.js create mode 100644 src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortItemConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortPlacementConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortTrackConfig.json create mode 100644 src/v0/destinations/topsort/impressions-and-clicks.js create mode 100644 src/v0/destinations/topsort/purchase.js create mode 100644 src/v0/destinations/topsort/transform.js create mode 100644 src/v0/destinations/topsort/utils.js create mode 100644 test/integrations/destinations/topsort/mocks.ts create mode 100644 test/integrations/destinations/topsort/processor/data.ts create mode 100644 test/integrations/destinations/topsort/processor/trackClicksTestData.ts create mode 100644 test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts create mode 100644 test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts create mode 100644 test/integrations/destinations/topsort/router/data.ts diff --git a/src/features.ts b/src/features.ts index 4ff419a7fe2..fb91ae28833 100644 --- a/src/features.ts +++ b/src/features.ts @@ -93,6 +93,7 @@ const defaultFeaturesConfig: FeaturesConfig = { AMAZON_AUDIENCE: true, INTERCOM_V2: true, LINKEDIN_AUDIENCE: true, + TOPSORT: true, }, regulations: [ 'BRAZE', diff --git a/src/v0/destinations/topsort/config.js b/src/v0/destinations/topsort/config.js new file mode 100644 index 00000000000..5d4060f526c --- /dev/null +++ b/src/v0/destinations/topsort/config.js @@ -0,0 +1,31 @@ +const { getMappingConfig } = require('../../util'); + +const ENDPOINT = 'https://api.topsort.com/v2/events'; + +const ConfigCategory = { + TRACK: { + type: 'track', + name: 'TopsortTrackConfig', + }, + PLACEMENT: { name: 'TopsortPlacementConfig' }, + ITEM: { name: 'TopsortItemConfig' }, + PURCHASE_ITEM: { name: 'TopSortPurchaseProductConfig' }, +}; + +const ECOMM_EVENTS_WITH_PRODUCT_ARRAY = [ + 'Cart Viewed', + 'Checkout Started', + 'Order Updated', + 'Order Completed', + 'Order Refunded', + 'Order Cancelled', +]; + +const mappingConfig = getMappingConfig(ConfigCategory, __dirname); + +module.exports = { + mappingConfig, + ConfigCategory, + ENDPOINT, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, +}; diff --git a/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json new file mode 100644 index 00000000000..f3f9d877a9d --- /dev/null +++ b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json @@ -0,0 +1,24 @@ +[ + { + "destKey": "productId", + "sourceKeys": ["product_id", "properties.product_id"] + }, + { + "destKey": "unitPrice", + "sourceKeys": ["price", "properties.price"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "quantity", + "sourceKeys": ["quantity", "properties.quantity"], + "metadata": { + "toInt": true + } + }, + { + "destKey": "vendorId", + "sourceKeys": "properties.vendorId" + } +] diff --git a/src/v0/destinations/topsort/data/TopsortItemConfig.json b/src/v0/destinations/topsort/data/TopsortItemConfig.json new file mode 100644 index 00000000000..ff8c77a7ac7 --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortItemConfig.json @@ -0,0 +1,15 @@ +[ + { + "destKey": "position", + "sourceKeys": ["properties.position", "position"], + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "productId", + "sourceKeys": ["properties.product_id", "product_id"], + "required": false + } +] diff --git a/src/v0/destinations/topsort/data/TopsortPlacementConfig.json b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json new file mode 100644 index 00000000000..7c67bb183d2 --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json @@ -0,0 +1,36 @@ +[ + { + "destKey": "path", + "sourceKeys": "context.page.path", + "required": false + }, + { + "destKey": "searchQuery", + "sourceKeys": "properties.query", + "required": false + }, + { + "destKey": "page", + "sourceKeys": "properties.pageNumber", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "pageSize", + "sourceKeys": "properties.pageSize", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "categoryIds", + "sourceKeys": "properties.category_id", + "required": false, + "metadata": { + "toArray": true + } + } +] diff --git a/src/v0/destinations/topsort/data/TopsortTrackConfig.json b/src/v0/destinations/topsort/data/TopsortTrackConfig.json new file mode 100644 index 00000000000..fcc9c57d1be --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortTrackConfig.json @@ -0,0 +1,27 @@ +[ + { + "destKey": "occurredAt", + "sourceKeys": ["timestamp", "originalTimestamp"], + "required": true + }, + { + "destKey": "opaqueUserId", + "sourceKeys": "anonymousId", + "required": true + }, + { + "destKey": "resolvedBidId", + "sourceKeys": "properties.resolvedBidId", + "required": false + }, + { + "destKey": "entity", + "sourceKeys": "properties.entity", + "required": false + }, + { + "destKey": "additionalAttribution", + "sourceKeys": "properties.additionalAttribution", + "required": false + } +] diff --git a/src/v0/destinations/topsort/impressions-and-clicks.js b/src/v0/destinations/topsort/impressions-and-clicks.js new file mode 100644 index 00000000000..ca3c6ad8601 --- /dev/null +++ b/src/v0/destinations/topsort/impressions-and-clicks.js @@ -0,0 +1,95 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processImpressionsAndClicksUtility = { + // Create event data object + createEventData(basePayload, placementPayload, itemPayload, event) { + return { + topsortPayload: { + ...basePayload, + placement: { + ...placementPayload, + ...itemPayload, + }, + id: generateUUID(), + }, + event, + }; + }, + + // Process events with a product array + processProductArray({ + products, + basePayload, + placementPayload, + topsortEventName, + finalPayloads, + }) { + const itemPayloads = getItemPayloads(products, mappingConfig[ConfigCategory.ITEM.name]); + itemPayloads.forEach((itemPayload) => { + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + addFinalPayload(eventData, finalPayloads); + }); + }, + + // Process events with a single product + processSingleProduct({ + basePayload, + placementPayload, + message, + topsortEventName, + finalPayloads, + }) { + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.ITEM.name]); + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + processImpressionsAndClicks({ + isProductArrayAvailable, + basePayload, + topsortEventName, + finalPayloads, + products, + message, + placementPayload, + }) { + if (isProductArrayAvailable) { + // If product array is available, process the event with multiple products + this.processProductArray({ + basePayload, + topsortEventName, + finalPayloads, + products, + placementPayload, + }); + } else { + // Otherwise, process the event with a single product + this.processSingleProduct({ + basePayload, + topsortEventName, + finalPayloads, + message, + placementPayload, + }); + } + }, +}; + +module.exports = { processImpressionsAndClicksUtility }; diff --git a/src/v0/destinations/topsort/purchase.js b/src/v0/destinations/topsort/purchase.js new file mode 100644 index 00000000000..497188cb105 --- /dev/null +++ b/src/v0/destinations/topsort/purchase.js @@ -0,0 +1,56 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processPurchaseEventUtility = { + // Create event data object for purchase events + createEventData(basePayload, items, event) { + return { + topsortPayload: { + ...basePayload, + items, + id: generateUUID(), + }, + event, + }; + }, + + // Function to process events with a product array for purchase events + processProductArray(args) { + const { products, basePayload, topsortEventName, finalPayloads } = args; + const itemPayloads = getItemPayloads( + products, + mappingConfig[ConfigCategory.PURCHASE_ITEM.name], + ); + const eventData = this.createEventData(basePayload, itemPayloads, topsortEventName); + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process events with a single product for purchase events + processSingleProduct(args) { + const { basePayload, message, topsortEventName, finalPayloads } = args; + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.PURCHASE_ITEM.name]); + const eventData = this.createEventData(basePayload, [itemPayload], topsortEventName); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process purchase events (either with a product array or single product) + processPurchaseEvent(args) { + if (args.isProductArrayAvailable) { + // Process the event with multiple products (product array) + this.processProductArray(args); + } else { + // Process the event with a single product + this.processSingleProduct(args); + } + }, +}; + +module.exports = { + processPurchaseEventUtility, +}; diff --git a/src/v0/destinations/topsort/transform.js b/src/v0/destinations/topsort/transform.js new file mode 100644 index 00000000000..e5997ab37dc --- /dev/null +++ b/src/v0/destinations/topsort/transform.js @@ -0,0 +1,158 @@ +const { + InstrumentationError, + ConfigurationError, + getHashFromArray, +} = require('@rudderstack/integrations-lib'); +const { + mappingConfig, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, + ConfigCategory, + ENDPOINT, +} = require('./config'); +const { + constructPayload, + handleRtTfSingleEventError, + defaultRequestConfig, + defaultPostRequestConfig, + getSuccessRespEvents, +} = require('../../util'); +const { isProductArrayValid, getMappedEventName } = require('./utils'); +const { JSON_MIME_TYPE } = require('../../util/constant'); +const { processPurchaseEventUtility } = require('./purchase'); +const { processImpressionsAndClicksUtility } = require('./impressions-and-clicks'); + +const processTopsortEvents = (message, { Config }, finalPayloads) => { + const { topsortEvents } = Config; + const { event, properties } = message; + const { products } = properties; + + // Parse Topsort event mappings + const mappedEventName = getMappedEventName(getHashFromArray(topsortEvents), event); + + if (!mappedEventName) { + throw new InstrumentationError("Event not mapped in 'topsortEvents'. Dropping the event."); + } + + const topsortEventName = mappedEventName; + + // Construct base and placement payloads + const basePayload = constructPayload(message, mappingConfig[ConfigCategory.TRACK.name]); + + const commonArgs = { + basePayload, + topsortEventName, + finalPayloads, + products, + message, + isProductArrayAvailable: + ECOMM_EVENTS_WITH_PRODUCT_ARRAY.includes(event) && isProductArrayValid(event, properties), + }; + + // Process events based on type and construct payload within each logic block + if (topsortEventName === 'impressions' || topsortEventName === 'clicks') { + const placementPayload = constructPayload( + message, + mappingConfig[ConfigCategory.PLACEMENT.name], + ); + processImpressionsAndClicksUtility.processImpressionsAndClicks({ + ...commonArgs, + placementPayload, // Only pass placementPayload for impressions and clicks + }); + } else if (topsortEventName === 'purchases') { + processPurchaseEventUtility.processPurchaseEvent({ + ...commonArgs, + }); + } else { + throw new InstrumentationError(`Event not mapped: ${topsortEventName}`); + } + + return finalPayloads; +}; + +const processEvent = (message, destination, finalPayloads) => { + // Check for missing API Key or missing Advertiser ID + if (!destination.Config.apiKey) { + throw new ConfigurationError('API Key is missing. Aborting message.', 400); + } + if (!message.type) { + throw new InstrumentationError('Message Type is missing. Aborting message.', 400); + } + + const messageType = message.type.toLowerCase(); + + // Handle 'track' event type + if (messageType !== 'track') { + throw new InstrumentationError('Only "track" events are supported. Dropping event.', 400); + } + + processTopsortEvents(message, destination, finalPayloads); +}; + +// Process function that is called per event +const process = (event) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + processEvent(event.message, event.destination, finalPayloads); + + const response = defaultRequestConfig(); + const { apiKey } = event.destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + return response; +}; + +// Router destination handler to process a batch of events +const processRouterDest = async (inputs, reqMetadata) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + const failureResponses = []; + const successMetadatas = []; + + inputs.forEach((input) => { + try { + // Process the event + processEvent(input.message, input.destination, finalPayloads); + // Add to successMetadatas array + successMetadatas.push(input.metadata); + } catch (error) { + // Handle error and store the error details + const failureResponse = handleRtTfSingleEventError(input, error, reqMetadata); + failureResponses.push(failureResponse); + } + }); + + const response = defaultRequestConfig(); + const { destination } = inputs[0]; + const { apiKey } = destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + const successResponses = getSuccessRespEvents(response, successMetadatas, destination, true); + + return [successResponses, ...failureResponses]; +}; + +module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/topsort/utils.js b/src/v0/destinations/topsort/utils.js new file mode 100644 index 00000000000..ca9edfbceae --- /dev/null +++ b/src/v0/destinations/topsort/utils.js @@ -0,0 +1,53 @@ +const { ConfigurationError } = require('@rudderstack/integrations-lib'); +const { constructPayload } = require('../../util'); + +// Function to check if a product array is valid +const isProductArrayValid = (event, properties) => + Array.isArray(properties?.products) && properties?.products.length > 0; + +// Function to construct item payloads for each product +const getItemPayloads = (products, mappingConfigs) => + products.map((product) => constructPayload(product, mappingConfigs)); + +// Function to add the structured event data to the final payloads array +const addFinalPayload = (eventData, finalPayloads) => { + switch (eventData.event) { + case 'impressions': + finalPayloads.impressions.push(eventData.topsortPayload); + break; + case 'clicks': + finalPayloads.clicks.push(eventData.topsortPayload); + break; + case 'purchases': + finalPayloads.purchases.push(eventData.topsortPayload); + break; + default: + throw new ConfigurationError('Invalid event mapping'); + } +}; + +// Function to retrieve mapped event name from Topsort event mappings. +const getMappedEventName = (parsedTopsortEventMappings, event) => { + const eventName = event.toLowerCase(); + + const mappedEventNames = parsedTopsortEventMappings[eventName]; + + // Check if mapping exists + if (!mappedEventNames) { + throw new ConfigurationError(`Event '${eventName}' not found in Topsort event mappings`); + } + + // If there are multiple mappings, pick the first one or apply your logic + if (Array.isArray(mappedEventNames)) { + return mappedEventNames[0]; // Return the first mapping + } + + return mappedEventNames; // Return the single mapping if not an array +}; + +module.exports = { + isProductArrayValid, + getItemPayloads, + addFinalPayload, + getMappedEventName, +}; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index ad08be448ed..0f9abfb0403 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -970,6 +970,7 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null strictMultiMap, validateTimestamp, allowedKeyCheck, + toArray, } = metadata; // if value is null and defaultValue is supplied - use that @@ -1037,6 +1038,13 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null } } + if (toArray) { + if (Array.isArray(formattedVal)) { + return formattedVal; + } + return [formattedVal]; + } + return formattedVal; }; diff --git a/test/integrations/destinations/topsort/mocks.ts b/test/integrations/destinations/topsort/mocks.ts new file mode 100644 index 00000000000..0a3e24b30fd --- /dev/null +++ b/test/integrations/destinations/topsort/mocks.ts @@ -0,0 +1,5 @@ +import utils from '../../../../src/v0/util'; + +export const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('test-id-123-123-123'); +}; diff --git a/test/integrations/destinations/topsort/processor/data.ts b/test/integrations/destinations/topsort/processor/data.ts new file mode 100644 index 00000000000..73f838f1400 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/data.ts @@ -0,0 +1,9 @@ +import { trackClicksTestData } from './trackClicksTestData'; +import { trackImpressionsTestData } from './trackImpressionsTestData'; +import { trackPurchasesTestData } from './trackPurchasesTestData'; + +export const data = [ + ...trackClicksTestData, + ...trackImpressionsTestData, + ...trackPurchasesTestData, +]; diff --git a/test/integrations/destinations/topsort/processor/trackClicksTestData.ts b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts new file mode 100644 index 00000000000..2cfd4589053 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts @@ -0,0 +1,571 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Order Completed', + to: 'clicks', + }, + { + from: 'Order Refunded', + to: 'clicks', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackClicksTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Clicked event with all necessary properties is successfully processed and mapped correctly by Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Clicked', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Validates the correct processing and mapping of an Order Completed event with multiple products.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Tests the handling of an invalid event type (abc) and ensures that Topsort correctly drops the event with a 400 error indicating unsupported event type.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'abc', + event: 'Order Refunded', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }, + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Only "track" events are supported. Dropping event.', + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 3', + name: 'topsort', + description: + 'Verifies the correct processing of an Order Completed event with multiple products and handles an error for an unrecognized Order Updated2 event in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Updated2', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + error: "Event 'order updated2' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts new file mode 100644 index 00000000000..2f1fc60571c --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts @@ -0,0 +1,381 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Viewed', + to: 'impressions', + }, + { + from: 'Checkout Started', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackImpressionsTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Track call with impressions event, verifies that a Product Viewed event is correctly mapped', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Viewed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped and ingested as impressions in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout Started', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that an invalid event (Checkout done) that is not found in Topsort’s event mappings is handled and returns an error with a status code 400.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout done', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: "Event 'checkout done' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts new file mode 100644 index 00000000000..a4736fb471b --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts @@ -0,0 +1,457 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Order Completed', + to: 'purchases', + }, + { + from: 'Product Added', + to: 'purchases', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackPurchasesTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Added event is correctly mapped and ingested as a purchase event in Topsort with the appropriate product details.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped with items.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + unitPrice: 40, + }, + { + productId: '577c6f5d5cf86a4c7735ba03', + unitPrice: 5, + }, + ], + id: 'test-id-123-123-123', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that both a Product Added and an Order Completed event are correctly mapped and ingested into Topsort as purchase events', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/router/data.ts b/test/integrations/destinations/topsort/router/data.ts new file mode 100644 index 00000000000..0cabdcbac8d --- /dev/null +++ b/test/integrations/destinations/topsort/router/data.ts @@ -0,0 +1,418 @@ +import { Destination } from '../../../../../src/types'; +import { RouterTestData } from '../../../testTypes'; +import { generateMetadata } from '../../../testUtils'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Product Added', + to: 'purchases', + }, + { + from: 'Product Removed', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const data: RouterTestData[] = [ + { + id: 'topsort-router-test-1', + name: 'topsort', + description: 'Basic Router Test for track call having clicks event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Clicked', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-2', + name: 'topsort', + description: 'Basic Router Test for track call having impressions event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Removed', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-3', + name: 'topsort', + description: 'Basic Router Test for track call having purchases event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Added', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, +]; diff --git a/test/integrations/testTypes.ts b/test/integrations/testTypes.ts index 3c5cf606009..b11403f50a5 100644 --- a/test/integrations/testTypes.ts +++ b/test/integrations/testTypes.ts @@ -101,7 +101,7 @@ export type ProcessorTestData = { body: ProcessorTransformationResponse[]; }; }; - mockFns?: (mockAdapter: MockAdapter) => {}; + mockFns?: (mockAdapter: MockAdapter) => void; }; export type RouterTestData = { id: string; diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index 7e6e6b9acbb..73d08e452c2 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -277,6 +277,7 @@ export const generateSimplifiedTrackPayload: any = (parametersOverride: any) => device: parametersOverride.context.device, os: parametersOverride.context.os, app: parametersOverride.context.app, + page: parametersOverride.context.page, }), anonymousId: parametersOverride.anonymousId || 'default-anonymousId', originalTimestamp: parametersOverride.originalTimestamp || '2021-01-03T17:02:53.193Z',