|
| 1 | +/** |
| 2 | + * @typedef {Object} SegmentTrackEvent |
| 3 | + * @see {@link https://segment.com/docs/connections/spec/track/} for full track event spec |
| 4 | + * @see {@link https://segment.com/docs/connections/spec/common/} for full common fields spec |
| 5 | + * @property {String} event Track event name |
| 6 | + * @property {String} messageId Original API message identifier |
| 7 | + * @property {String} userId Tracked user id that we want to modify and re-track |
| 8 | + * @property {String} timestamp Timestamp of event in ISO 8601 format |
| 9 | + * @property {Object} properties Track event arbitrary properties, we want to add 3 own |
| 10 | + */ |
| 11 | + |
| 12 | +/** |
| 13 | + * @typedef {Object} FunctionSettings |
| 14 | + * @property {String} apiKey Write key of source to forward alias and track events to |
| 15 | + */ |
| 16 | + |
| 17 | +/** |
| 18 | + * Call Segment V1 API, using HTTP API Segment Source by write key |
| 19 | + * @see {@link https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/} for source doc |
| 20 | + * @internal |
| 21 | + * @param {String} apiKey |
| 22 | + * @param {String<'alias'|'track'>} route |
| 23 | + * @param {Object} body |
| 24 | + * @return {Promise<void>} |
| 25 | + */ |
| 26 | +async function callSegmentAPI(apiKey, route, body) { |
| 27 | + let response; |
| 28 | + |
| 29 | + try { |
| 30 | + response = await fetch(`https://api.segment.io/v1/${route}`, { |
| 31 | + method: 'POST', |
| 32 | + headers: { |
| 33 | + Authorization: `Basic ${btoa(`${apiKey}:`)}`, |
| 34 | + 'Content-Type': 'application/json', |
| 35 | + }, |
| 36 | + body: JSON.stringify(body), |
| 37 | + }); |
| 38 | + } catch (error) { |
| 39 | + throw new RetryError(error.message); |
| 40 | + } |
| 41 | + |
| 42 | + if (response.status >= 500 || response.status === 429) { |
| 43 | + throw new RetryError(`Failed with ${response.status}`); |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +/** |
| 48 | + * Handle track event |
| 49 | + * @param {SegmentTrackEvent} event |
| 50 | + * @param {FunctionSettings} settings |
| 51 | + * @return {Promise<void>} |
| 52 | + */ |
| 53 | +async function onTrack(event, settings) { |
| 54 | + const { apiKey } = settings; |
| 55 | + |
| 56 | + if (!apiKey) { |
| 57 | + throw new ValidationError('Forward source write key is required'); |
| 58 | + } |
| 59 | + |
| 60 | + const anticipatedId = crypto.createHash('md5').update(event.userId).digest('hex'); |
| 61 | + |
| 62 | + const [slug1, slug2, slug3] = event.userId.split('-'); |
| 63 | + |
| 64 | + await Promise.all([ |
| 65 | + callSegmentAPI(apiKey, 'alias', { |
| 66 | + previousId: event.userId, |
| 67 | + userId: anticipatedId, |
| 68 | + timestamp: event.timestamp, |
| 69 | + }), |
| 70 | + callSegmentAPI(apiKey, 'track', { |
| 71 | + event: event.event, |
| 72 | + userId: anticipatedId, |
| 73 | + properties: { |
| 74 | + ...event.properties, |
| 75 | + slug1, |
| 76 | + slug2, |
| 77 | + slug3, |
| 78 | + }, |
| 79 | + }), |
| 80 | + ]); |
| 81 | +} |
0 commit comments