Last active
August 26, 2022 16:30
-
-
Save monteith/a602a6df707eaf882b5c64ef55d11c4b to your computer and use it in GitHub Desktop.
Segment to DY function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Learn more about destination functions API at | |
// https://segment.com/docs/connections/destinations/destination-functions | |
/** | |
* Handle identify event | |
* @param {SegmentIdentifyEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
let defaultEventBody = { | |
user: { | |
dyid: undefined, // dyId, | |
dyid_server: undefined, // dyId, | |
}, | |
session: { | |
dy: undefined, // sessionId, | |
}, | |
events: [], | |
context: { | |
page: { | |
type: 'OTHER', | |
data: [], | |
location: 'https://segment.io', | |
}, | |
device: { | |
userAgent: 'Segment.io', | |
}, | |
}, | |
}; | |
async function onIdentify(event, settings) { | |
const { dyApiKey, personaToken, personaSpaceId } = settings; | |
const { anonymousId, traits } = event; | |
if (!anonymousId) { | |
console.log(`No anonymousId found, exiting...`); | |
return; | |
} | |
let eventBody = { ...defaultEventBody }; | |
const hashedEmail = getHash(traits['email']) || undefined; | |
if (hashedEmail) { | |
eventBody.events.push({ | |
name: 'Segment Email', | |
properties: { | |
dyType: 'login-v1', | |
hashedEmail: hashedEmail, | |
}, | |
}); | |
} | |
const audienceKey = event.context.personas.computation_key; | |
const audienceValue = traits[audienceKey]; | |
if (audienceValue) { | |
eventBody.events.push({ | |
name: audienceKey, | |
properties: { | |
member: audienceValue, | |
anonymousId: anonymousId, | |
}, | |
}); | |
} else { | |
console.log(`No audienceValue found in traits`); | |
} | |
const dyId = await getUserDyId(anonymousId, personaSpaceId, personaToken); | |
if (!dyId) { | |
console.log(`No DY data returned, exiting...`); | |
return; | |
} | |
eventBody.user.dyid = dyId; | |
eventBody.user.dyid_server = dyId; | |
const sessionId = await getSessionId(dyApiKey); | |
if (!sessionId) { | |
console.log(`No sessionId found`); | |
} | |
eventBody.session.dy = sessionId; | |
await postDyEvent(eventBody, dyApiKey); | |
} | |
async function getSessionId(apiKey) { | |
const url = `https://dy-api.com/v2/serve/user/choose`; | |
const event = { ...defaultEventBody }; | |
event.selector = { names: [''] }; | |
try { | |
const res = await fetch(url, { | |
method: 'POST', | |
headers: { | |
'DY-API-key': apiKey, | |
'Content-Type': 'application/json', | |
'User-Agent': 'segment.io', | |
}, | |
body: JSON.stringify(body), | |
}); | |
const resJson = await res.json(); | |
return Object.values(resJson.cookies)[1].value; | |
} catch (error) { | |
throw new RetryError(error.message); | |
} | |
} | |
async function getUserDyId(anonymousId, personaSpaceId, personaToken) { | |
const url = `https://profiles.segment.com/v1/spaces/${personaSpaceId}/collections/users/profiles/anonymous_id:${anonymousId}/external_ids?include=dy_id&limit=1`; | |
const res = await fetch(url, { | |
headers: new Headers({ | |
Authorization: 'Basic ' + btoa(personaToken + ':'), | |
'Content-Type': 'application/json', | |
}), | |
method: 'GET', | |
}); | |
if (res.ok) { | |
console.log( | |
'Profile API request successful. Response: ', | |
res.status, | |
res.statusText | |
); | |
} else if (res.status === 404) { | |
console.log('anonymous_id', anonymousId, 'does not exist.'); | |
} else if (res.status === 429 || res.status >= 500) { | |
console.log( | |
'Something went wrong, this event will be retried. Error: ', | |
res.status, | |
res.statusText | |
); | |
throw new RetryError( | |
`Profile API not available. GET ${url} = ${res.status} ${res.statusText}` | |
); | |
} else { | |
console.log( | |
'Something went wrong, please check your settings. Error: ', | |
res.status, | |
res.statusText | |
); | |
throw new Error( | |
`Something went wrong. GET ${url} = ${res.status} ${res.statusText}` | |
); | |
} | |
const resJson = await res.json(); | |
return resJson.data[0].id || null; | |
} | |
async function postDyEvent(event, apiKey) { | |
const url = 'https://dy-api.com/v2/collect/user/event'; | |
try { | |
const res = await fetch(url, { | |
method: 'POST', | |
headers: { | |
'DY-API-key': apiKey, | |
'Content-Type': 'application/json', | |
'User-Agent': 'segment.io', | |
}, | |
body: JSON.stringify(event), | |
}); | |
} catch (error) { | |
throw new RetryError(error.message); | |
} | |
} | |
function getHash(path) { | |
if (path) { | |
return crypto.createHash('sha256').update(path).digest('hex'); | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Handle track event | |
* @param {SegmentTrackEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onTrack(event, settings) { | |
// Learn more at https://segment.com/docs/connections/spec/identify/ | |
throw new EventNotSupported('identify is not supported'); | |
} | |
/** | |
* Handle group event | |
* @param {SegmentGroupEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onGroup(event, settings) { | |
// Learn more at https://segment.com/docs/connections/spec/group/ | |
throw new EventNotSupported('group is not supported'); | |
} | |
/** | |
* Handle page event | |
* @param {SegmentPageEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onPage(event, settings) { | |
// Learn more at https://segment.com/docs/connections/spec/page/ | |
throw new EventNotSupported('page is not supported'); | |
} | |
/** | |
* Handle screen event | |
* @param {SegmentScreenEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onScreen(event, settings) { | |
// Learn more at https://segment.com/docs/connections/spec/screen/ | |
throw new EventNotSupported('screen is not supported'); | |
} | |
/** | |
* Handle alias event | |
* @param {SegmentAliasEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onAlias(event, settings) { | |
// Learn more at https://segment.com/docs/connections/spec/alias/ | |
throw new EventNotSupported('alias is not supported'); | |
} | |
/** | |
* Handle delete event | |
* @param {SegmentDeleteEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onDelete(event, settings) { | |
// Learn more at https://segment.com/docs/partners/spec/#delete | |
throw new EventNotSupported('delete is not supported'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment