Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/fb_proxt_v1' into fb_proxt_v1
Browse files Browse the repository at this point in the history
  • Loading branch information
sandeepdsvs committed Feb 29, 2024
2 parents d5402a7 + c115dda commit d8309eb
Show file tree
Hide file tree
Showing 25 changed files with 1,515 additions and 25 deletions.
31 changes: 31 additions & 0 deletions src/cdk/v2/destinations/ninetailed/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { getMappingConfig } = require('../../../../v0/util');

const ConfigCategories = {
GENERAL: {
type: 'general',
name: 'generalPayloadMapping',
},
CONTEXT: {
type: 'context',
name: 'contextMapping',
},
TRACK: {
type: 'track',
name: 'trackMapping',
},
IDENTIFY: {
type: 'identify',
name: 'identifyMapping',
},
PAGE: {
type: 'page',
name: 'pageMapping',
},
};

// MAX_BATCH_SIZE : // Maximum number of events to send in a single batch
const mappingConfig = getMappingConfig(ConfigCategories, __dirname);
const batchEndpoint =
'https://experience.ninetailed.co/v2/organizations/{{organisationId}}/environments/{{environment}}/events';

module.exports = { ConfigCategories, mappingConfig, batchEndpoint, MAX_BATCH_SIZE: 200 };
43 changes: 43 additions & 0 deletions src/cdk/v2/destinations/ninetailed/data/contextMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[
{
"sourceKeys": "app.name",
"required": true,
"destKey": "app.name"
},
{
"sourceKeys": "app.version",
"required": true,
"destKey": "app.version"
},
{
"sourceKeys": "campaign",
"destKey": "campaign"
},
{
"sourceKeys": "library.name",
"required": true,
"destKey": "library.name"
},
{
"sourceKeys": "library.version",
"required": true,
"destKey": "library.version"
},
{
"sourceKeys": "locale",
"destKey": "locale"
},
{
"sourceKeys": "page",
"destKey": "page"
},
{
"sourceKeys": "userAgent",
"destKey": "userAgent"
},
{
"sourceKeys": "location",
"required": true,
"destKey": "location"
}
]
25 changes: 25 additions & 0 deletions src/cdk/v2/destinations/ninetailed/data/generalPayloadMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[
{
"sourceKeys": "anonymousId",
"required": true,
"destKey": "anonymousId"
},
{
"sourceKeys": "messageId",
"required": true,
"destKey": "messageId"
},
{
"sourceKeys": "channel",
"required": true,
"destKey": "channel"
},
{
"sourceKeys": "type",
"destKey": "type"
},
{
"sourceKeys": "originalTimestamp",
"destKey": "originalTimestamp"
}
]
14 changes: 14 additions & 0 deletions src/cdk/v2/destinations/ninetailed/data/identifyMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"sourceKeys": "traits",
"sourceFromGenericMap": true,
"required": true,
"destKey": "traits"
},
{
"sourceKeys": "userIdOnly",
"sourceFromGenericMap": true,
"required": true,
"destKey": "userId"
}
]
7 changes: 7 additions & 0 deletions src/cdk/v2/destinations/ninetailed/data/pageMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"sourceKeys": "properties",
"required": true,
"destKey": "properties"
}
]
12 changes: 12 additions & 0 deletions src/cdk/v2/destinations/ninetailed/data/trackMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"sourceKeys": "properties",
"required": true,
"destKey": "properties"
},
{
"sourceKeys": "event",
"required": true,
"destKey": "event"
}
]
33 changes: 33 additions & 0 deletions src/cdk/v2/destinations/ninetailed/procWorkflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
bindings:
- name: EventType
path: ../../../../constants
- path: ../../bindings/jsontemplate
- name: defaultRequestConfig
path: ../../../../v0/util
- name: removeUndefinedAndNullValues
path: ../../../../v0/util
- path: ./utils

steps:
- name: messageType
template: |
.message.type.toLowerCase();
- name: validateInput
template: |
let messageType = $.outputs.messageType;
$.assert(messageType, "message Type is not present. Aborting");
$.assert(messageType in {{$.EventType.([.TRACK,.IDENTIFY,.PAGE])}}, "message type " + messageType + " is not supported");
$.assertConfig(.destination.Config.organisationId, "Organisation ID is not present. Aborting");
$.assertConfig(.destination.Config.environment, "Environment is not present. Aborting");
- name: preparePayload
template: |
const payload = $.constructFullPayload(.message);
$.context.payload = $.removeUndefinedAndNullValues(payload);
- name: buildResponse
template: |
const response = $.defaultRequestConfig();
response.body.JSON.events = [$.context.payload];
response.endpoint = $.getEndpoint(.destination.Config);
response.method = "POST";
response
35 changes: 35 additions & 0 deletions src/cdk/v2/destinations/ninetailed/rtWorkflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
bindings:
- path: ./config
- name: handleRtTfSingleEventError
path: ../../../../v0/util/index
- path: ./utils
steps:
- name: validateInput
template: |
$.assert(Array.isArray(^) && ^.length > 0, "Invalid event array")
- name: transform
externalWorkflow:
path: ./procWorkflow.yaml
loopOverInput: true

- name: successfulEvents
template: |
$.outputs.transform#idx.output.({
"output": .body.JSON.events[0],
"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.failedEvents, ...$.outputs.batchSuccessfulEvents]
109 changes: 109 additions & 0 deletions src/cdk/v2/destinations/ninetailed/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const { BatchUtils } = require('@rudderstack/workflow-engine');
const config = require('./config');
const { constructPayload } = require('../../../../v0/util');

/**
* This fucntion constructs payloads based upon mappingConfig for all calls
* We build context as it has some specific payloads with default values so just breaking them down
* @param {*} message
* @returns
*/
const constructFullPayload = (message) => {
const context = constructPayload(
message?.context || {},
config.mappingConfig[config.ConfigCategories.CONTEXT.name],
);
const payload = constructPayload(
message,
config.mappingConfig[config.ConfigCategories.GENERAL.name],
);
let typeSpecifcPayload;
switch (message.type) {
case 'track':
typeSpecifcPayload = constructPayload(
message,
config.mappingConfig[config.ConfigCategories.TRACK.name],
);
break;
case 'identify':
typeSpecifcPayload = constructPayload(
message,
config.mappingConfig[config.ConfigCategories.IDENTIFY.name],
);
break;
case 'page':
typeSpecifcPayload = constructPayload(
message,
config.mappingConfig[config.ConfigCategories.PAGE.name],
);
break;
default:
break;
}
payload.context = context;
return { ...payload, ...typeSpecifcPayload }; // merge base and type-specific payloads;
};

const getEndpoint = (Config) => {
const { organisationId, environment } = Config;
return config.batchEndpoint
.replace('{{organisationId}}', organisationId)
.replace('{{environment}}', environment);
};

const mergeMetadata = (batch) => {
const metadata = [];
batch.forEach((event) => {
metadata.push(event.metadata);
});
return metadata;
};

const getMergedEvents = (batch) => {
const events = [];
batch.forEach((event) => {
events.push(event.output);
});
return events;
};

const batchBuilder = (batch) => ({
batchedRequest: {
body: {
JSON: { events: getMergedEvents(batch) },
JSON_ARRAY: {},
XML: {},
FORM: {},
},
version: '1',
type: 'REST',
method: 'POST',
endpoint: getEndpoint(batch[0].destination.Config),
headers: {
'Content-Type': 'application/json',
},
params: {},
files: {},
},
metadata: mergeMetadata(batch),
batched: true,
statusCode: 200,
destination: batch[0].destination,
});

/**
* This fucntions make chunk of successful events based on MAX_BATCH_SIZE
* and then build the response for each chunk to be returned as object of an array
* @param {*} events
* @returns
*/
const batchResponseBuilder = (events) => {
const batches = BatchUtils.chunkArrayBySizeAndLength(events, { maxItems: config.MAX_BATCH_SIZE });
const response = [];
batches.items.forEach((batch) => {
response.push(batchBuilder(batch));
});
return response;
};

module.exports = { constructFullPayload, getEndpoint, batchResponseBuilder };
3 changes: 2 additions & 1 deletion src/features.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@
"TIKTOK_AUDIENCE": true,
"REDDIT": true,
"THE_TRADE_DESK": true,
"INTERCOM": true
"INTERCOM": true,
"NINETAILED": true
},
"regulations": [
"BRAZE",
Expand Down
25 changes: 23 additions & 2 deletions src/v0/destinations/klaviyo/data/KlaviyoIdentify.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@
"traits.address.region",
"context.traits.region",
"context.traits.address.region",
"properties.region"
"properties.region",
"traits.state",
"traits.address.state",
"context.traits.address.state",
"context.traits.state",
"properties.state"
],
"required": false
},
Expand All @@ -77,14 +82,19 @@
"sourceKeys": [
"traits.zip",
"traits.postalcode",
"traits.postalCode",
"traits.address.zip",
"traits.address.postalcode",
"traits.address.postalCode",
"context.traits.zip",
"context.traits.postalcode",
"context.traits.postalCode",
"context.traits.address.zip",
"context.traits.address.postalcode",
"context.traits.address.postalCode",
"properties.zip",
"properties.postalcode"
"properties.postalcode",
"properties.postalCode"
],
"required": false
},
Expand All @@ -97,5 +107,16 @@
"destKey": "location.timezone",
"sourceKeys": ["traits.timezone", "context.traits.timezone", "properties.timezone"],
"required": false
},
{
"destKey": "location.address1",
"sourceKeys": [
"traits.street",
"traits.address.street",
"context.traits.street",
"context.traits.address.street",
"properties.street"
],
"required": false
}
]
Loading

0 comments on commit d8309eb

Please sign in to comment.