@segment/analytics-browser-actions-facebook-conversions-api-web 1.11.1-staging-49cc16573.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import {US_STATE_CODES, COUNTRY_CODES, MAX_INIT_COUNT, INIT_COUNT_KEY, USER_DATA
6
6
  import { storageFallback, setStorageInitCount } from '../functions'
7
7
  import { getNotVisibleForEvent } from './depends-on'
8
8
 
9
- export function send(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
9
+ export async function send(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
10
10
  const { pixelId } = settings
11
11
  const {
12
12
  event_config: {
@@ -26,7 +26,7 @@ export function send(client: FBClient, clientParamBuilder: FBClientParamBuilder
26
26
 
27
27
  const fbEvent = formatFBEvent(payload)
28
28
 
29
- maybeSendUserData(client, clientParamBuilder, payload, settings, analytics)
29
+ await maybeSendUserData(client, clientParamBuilder, payload, settings, analytics)
30
30
 
31
31
  const options = formatOptions(payload)
32
32
 
@@ -66,7 +66,7 @@ function validate(payload: Payload): string | undefined {
66
66
  return undefined
67
67
  }
68
68
 
69
- function formatFBEvent(payload: Payload): FBEvent {
69
+ export function formatFBEvent(payload: Payload): FBEvent {
70
70
  const {
71
71
  content_category,
72
72
  content_ids,
@@ -87,6 +87,7 @@ function formatFBEvent(payload: Payload): FBEvent {
87
87
  } = payload
88
88
 
89
89
  const fbEvent: FBEvent = {
90
+ partner_agent: 'segment',
90
91
  ...(content_category ? { content_category } : {}),
91
92
  ...(content_ids && Array.isArray(content_ids) && content_ids.length > 0 ? { content_ids } : {}),
92
93
  ...(content_name ? { content_name } : {}),
@@ -102,7 +103,7 @@ function formatFBEvent(payload: Payload): FBEvent {
102
103
  }
103
104
 
104
105
  if(show_fields === false){
105
- // If show_fields is false we delete values for fields which are hidden in the UI.
106
+ // If show_fields is false we delete values for fields which are hidden in the UI.
106
107
  const fieldsToDelete = getNotVisibleForEvent(event_name as FBStandardEventType | FBNonStandardEventType)
107
108
  fieldsToDelete.forEach(field => {
108
109
  if (field in fbEvent) {
@@ -111,7 +112,7 @@ function formatFBEvent(payload: Payload): FBEvent {
111
112
  })
112
113
  }
113
114
 
114
- return Object.keys(fbEvent).length > 0 ? fbEvent : {}
115
+ return fbEvent
115
116
  }
116
117
 
117
118
  function formatOptions(payload: Payload): EventOptions | undefined {
@@ -123,14 +124,14 @@ function formatOptions(payload: Payload): EventOptions | undefined {
123
124
  return Object.values(options).some(Boolean) ? options : undefined
124
125
  }
125
126
 
126
- function maybeSendUserData(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
127
+ async function maybeSendUserData(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
127
128
  const {
128
129
  pixelId
129
130
  } = settings
130
131
  const {
131
132
  userData
132
133
  } = payload
133
- const userDataFormatted = formatUserData(userData, clientParamBuilder)
134
+ const userDataFormatted = await formatUserData(userData, clientParamBuilder)
134
135
 
135
136
  if(userDataFormatted) {
136
137
  /*
@@ -153,7 +154,7 @@ function maybeSendUserData(client: FBClient, clientParamBuilder: FBClientParamBu
153
154
  }
154
155
  }
155
156
 
156
- function formatUserData(userData: Payload['userData'], clientParamBuilder: FBClientParamBuilder | undefined): UserData | undefined {
157
+ export async function formatUserData(userData: Payload['userData'], clientParamBuilder: FBClientParamBuilder | undefined): Promise<UserData | undefined> {
157
158
  if(!userData){
158
159
  return undefined
159
160
  }
@@ -182,19 +183,45 @@ function formatUserData(userData: Payload['userData'], clientParamBuilder: FBCli
182
183
  fbcValue = clientParamBuilder.getFbc() || fbcValue
183
184
  fbpValue = clientParamBuilder.getFbp() || fbpValue
184
185
  }
185
-
186
+
187
+ const [
188
+ emData,
189
+ phData,
190
+ fnData,
191
+ lnData,
192
+ geData,
193
+ dbData,
194
+ ctData,
195
+ stData,
196
+ zpData,
197
+ countryData,
198
+ externalIdData
199
+ ] = await Promise.all([
200
+ formatPII(em, 'email', 'em', clientParamBuilder, (s) => s.toLowerCase().trim()),
201
+ formatPII(ph, 'phone', 'ph', clientParamBuilder, (s) => s.replace(/\D/g, '')),
202
+ formatPII(fn, 'first_name', 'fn', clientParamBuilder, (s) => s.toLowerCase().trim()),
203
+ formatPII(ln, 'last_name', 'ln', clientParamBuilder, (s) => s.toLowerCase().trim()),
204
+ formatPII(ge, 'gender', 'ge', clientParamBuilder, (s) => (['m', 'f'].includes(s) ? s : undefined)),
205
+ formatPII(db, 'date_of_birth', 'db', clientParamBuilder, (s) => formatDate(s)),
206
+ formatPII(ct, 'city', 'ct', clientParamBuilder, (s) => s.toLowerCase().replace(/\s+/g, '')),
207
+ formatPII(st, 'state', 'st', clientParamBuilder, (s) => fromMap(US_STATE_CODES, s)),
208
+ formatPII(zp, 'zip_code', 'zp', clientParamBuilder, (s) => s.trim()),
209
+ formatPII(country, 'country', 'country', clientParamBuilder, (s) => fromMap(COUNTRY_CODES, s)),
210
+ formatPII(external_id, 'external_id', 'external_id', clientParamBuilder, (s) => s.trim())
211
+ ])
212
+
186
213
  const ud: UserData = {
187
- ...(formatPII(em, 'email', 'em', clientParamBuilder, (s) => s.toLowerCase().trim())),
188
- ...(formatPII(ph, 'phone', 'ph', clientParamBuilder, (s) => s.replace(/\D/g, ''))),
189
- ...(formatPII(fn, 'first_name', 'fn', clientParamBuilder, (s) => s.toLowerCase().trim())),
190
- ...(formatPII(ln, 'last_name', 'ln', clientParamBuilder, (s) => s.toLowerCase().trim())),
191
- ...(formatPII(ge, 'gender', 'ge', clientParamBuilder, (s) => (['m', 'f'].includes(s) ? s as 'm' | 'f' : undefined) ) as {ge: 'm'|'f'} || {}),
192
- ...(formatPII(db, 'date_of_birth', 'db', clientParamBuilder, (s) => formatDate(s))),
193
- ...(formatPII(ct, 'city', 'ct', clientParamBuilder, (s) => s.toLowerCase().replace(/\s+/g, ''))),
194
- ...(formatPII(st, 'state', 'st', clientParamBuilder, (s) => fromMap(US_STATE_CODES, s))),
195
- ...(formatPII(zp, 'zip_code', 'zp', clientParamBuilder, (s) => s.trim())),
196
- ...(formatPII(country, 'country', 'country', clientParamBuilder, (s) => fromMap(COUNTRY_CODES, s))),
197
- ...(formatPII(external_id, 'external_id', 'external_id', clientParamBuilder, (s) => s.trim())),
214
+ ...emData,
215
+ ...phData,
216
+ ...fnData,
217
+ ...lnData,
218
+ ...(geData as { ge?: 'm' | 'f' }),
219
+ ...dbData,
220
+ ...ctData,
221
+ ...stData,
222
+ ...zpData,
223
+ ...countryData,
224
+ ...externalIdData,
198
225
  ...(fbcValue ? { fbc: fbcValue } : {}),
199
226
  ...(fbpValue ? { fbp: fbpValue } : {})
200
227
  }
@@ -205,18 +232,30 @@ function formatUserData(userData: Payload['userData'], clientParamBuilder: FBCli
205
232
  return ud
206
233
  }
207
234
 
208
- function formatPII<K extends PIIParamName, V extends string>(
235
+ async function formatPII<K extends PIIParamName, V extends string>(
209
236
  value: string | undefined,
210
237
  piiType: PIIType,
211
238
  piiParamType: K,
212
239
  clientParamBuilder: FBClientParamBuilder | undefined,
213
240
  formatter: (s: string) => string | undefined
214
- ): Partial<Record<K, V>> {
241
+ ): Promise<Partial<Record<K, V>>> {
215
242
  if(!value) {
216
243
  return {}
217
244
  }
218
- const val = clientParamBuilder?.getNormalizedAndHashedPII(value, piiType) ?? formatter(value)
219
- return val ? ({ [piiParamType]: val as V } as Partial<Record<K, V>>) : {}
245
+ if(clientParamBuilder){
246
+ const val = clientParamBuilder.getNormalizedAndHashedPII(value, piiType)
247
+ return val ? ({ [piiParamType]: val as V } as Partial<Record<K, V>>) : {}
248
+ }
249
+ else {
250
+ const val = formatter(value)
251
+ if(!val) {
252
+ return {}
253
+ }
254
+ else {
255
+ const hashValue = await sha256Hash(val)
256
+ return ({ [piiParamType]: hashValue as V }) as Partial<Record<K, V>>
257
+ }
258
+ }
220
259
  }
221
260
 
222
261
  function formatDate(isoDate?: string): string | undefined {
@@ -242,4 +281,12 @@ function fromMap(map: Map<string, string>, value?: string): string | undefined {
242
281
  return cleaned
243
282
  }
244
283
  return map.get(cleaned) || undefined
284
+ }
285
+
286
+ export async function sha256Hash(value: string): Promise<string> {
287
+ const encoder = new TextEncoder()
288
+ const data = encoder.encode(value)
289
+ const hashBuffer = await window.crypto.subtle.digest('SHA-256', data)
290
+ const hashArray = Array.from(new Uint8Array(hashBuffer))
291
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
245
292
  }
package/src/types.ts CHANGED
@@ -52,6 +52,7 @@ export type UserData = {
52
52
  }
53
53
 
54
54
  export type FBEvent = {
55
+ partner_agent: 'segment'
55
56
  content_category?: string
56
57
  content_ids?: string[]
57
58
  content_name?: string