@segment/analytics-browser-actions-facebook-conversions-api-web 1.9.0 → 1.9.1-staging-c01044061.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.
@@ -2,212 +2,184 @@ import { FBEvent, UserData, EventOptions, FBClient, FBStandardEventType, FBNonSt
2
2
  import { Payload } from './generated-types'
3
3
  import { Settings } from '../generated-types'
4
4
  import { UniversalStorage, Analytics } from '@segment/analytics-next'
5
- import {US_STATE_CODES, COUNTRY_CODES, MAX_INIT_COUNT, INIT_COUNT_KEY, USER_DATA_KEY } from '../constants'
5
+ import { US_STATE_CODES, COUNTRY_CODES, MAX_INIT_COUNT, INIT_COUNT_KEY, USER_DATA_KEY } from '../constants'
6
6
  import { storageFallback, setStorageInitCount } from '../functions'
7
7
  import { getNotVisibleForEvent } from './depends-on'
8
8
 
9
9
  export function send(client: FBClient, payload: Payload, settings: Settings, analytics: Analytics) {
10
- const { pixelId } = settings
11
- const {
12
- event_config: {
13
- custom_event_name,
14
- event_name
15
- } = {}
16
- } = payload
10
+ const { pixelId } = settings
11
+ const { event_config: { custom_event_name, event_name } = {} } = payload
17
12
 
18
- const isCustom = event_name === 'CustomEvent' ? true : false
13
+ const isCustom = event_name === 'CustomEvent' ? true : false
19
14
 
20
- const errorMessage = validate(payload)
15
+ const errorMessage = validate(payload)
21
16
 
22
- if(errorMessage) {
23
- console.warn(`${errorMessage}`)
24
- return
25
- }
26
-
27
- const fbEvent = formatFBEvent(payload)
28
-
29
- maybeSendUserData(client, payload, settings, analytics)
30
-
31
- const options = formatOptions(payload)
32
-
33
- if(isCustom){
34
- client(
35
- 'trackSingleCustom',
36
- pixelId,
37
- custom_event_name as string,
38
- { ...fbEvent },
39
- options
40
- )
41
- }
42
- else {
43
- client(
44
- 'trackSingle',
45
- pixelId,
46
- event_name as FBStandardEventType,
47
- { ...fbEvent },
48
- options
49
- )
50
- }
17
+ if (errorMessage) {
18
+ console.warn(`${errorMessage}`)
19
+ return
20
+ }
21
+
22
+ const fbEvent = formatFBEvent(payload)
23
+
24
+ maybeSendUserData(client, payload, settings, analytics)
25
+
26
+ const options = formatOptions(payload)
27
+
28
+ if (isCustom) {
29
+ client('trackSingleCustom', pixelId, custom_event_name as string, { ...fbEvent }, options)
30
+ } else {
31
+ client('trackSingle', pixelId, event_name as FBStandardEventType, { ...fbEvent }, options)
32
+ }
51
33
  }
52
34
 
53
35
  function validate(payload: Payload): string | undefined {
54
- const {
55
- event_config: { event_name },
56
- content_ids,
57
- contents
58
- } = payload
59
-
60
- if(['AddToCart', 'Purchase', 'ViewContent'].includes(event_name)){
61
- if ((!content_ids || (Array.isArray(content_ids) && content_ids.length === 0)) && (!contents || (Array.isArray(contents) && contents.length === 0))) {
62
- return `At least one of content_ids or contents is required for the ${event_name} event.`
63
- }
36
+ const {
37
+ event_config: { event_name },
38
+ content_ids,
39
+ contents
40
+ } = payload
41
+
42
+ if (['AddToCart', 'Purchase', 'ViewContent'].includes(event_name)) {
43
+ if (
44
+ (!content_ids || (Array.isArray(content_ids) && content_ids.length === 0)) &&
45
+ (!contents || (Array.isArray(contents) && contents.length === 0))
46
+ ) {
47
+ return `At least one of content_ids or contents is required for the ${event_name} event.`
64
48
  }
49
+ }
65
50
 
66
- return undefined
51
+ return undefined
67
52
  }
68
53
 
69
54
  function formatFBEvent(payload: Payload): FBEvent {
70
- const {
71
- content_category,
72
- content_ids,
73
- content_name,
74
- content_type,
75
- contents,
76
- currency,
77
- delivery_category,
78
- num_items,
79
- value,
80
- predicted_ltv,
81
- net_revenue,
82
- custom_data,
83
- event_config: {
84
- event_name,
85
- show_fields
86
- } = {}
87
- } = payload
88
-
89
- const fbEvent: FBEvent = {
90
- ...(content_category ? { content_category } : {}),
91
- ...(content_ids && Array.isArray(content_ids) && content_ids.length > 0 ? { content_ids } : {}),
92
- ...(content_name ? { content_name } : {}),
93
- ...(content_type ? { content_type } : {}),
94
- ...(contents && Array.isArray(contents) && contents.length > 0 ? { contents } : {}),
95
- ...(currency ? { currency } : {}),
96
- ...(delivery_category ? { delivery_category } : {}),
97
- ...(typeof num_items === 'number' ? { num_items } : {}),
98
- ...(typeof value === 'number' ? { value } : {}),
99
- ...(typeof predicted_ltv === 'number' ? { predicted_ltv } : {}),
100
- ...(typeof net_revenue === 'number' ? { net_revenue } : {}),
101
- ...(custom_data && Object.entries(custom_data).length > 0 ? { custom_data } : {})
102
- }
103
-
104
- if(show_fields === false){
105
- // If show_fields is false we delete values for fields which are hidden in the UI.
106
- const fieldsToDelete = getNotVisibleForEvent(event_name as FBStandardEventType | FBNonStandardEventType)
107
- fieldsToDelete.forEach(field => {
108
- if (field in fbEvent) {
109
- delete fbEvent[field as keyof typeof fbEvent]
110
- }
111
- })
112
- }
113
-
114
- return Object.keys(fbEvent).length > 0 ? fbEvent : {}
55
+ const {
56
+ content_category,
57
+ content_ids,
58
+ content_name,
59
+ content_type,
60
+ contents,
61
+ currency,
62
+ delivery_category,
63
+ num_items,
64
+ value,
65
+ predicted_ltv,
66
+ net_revenue,
67
+ custom_data,
68
+ event_config: { event_name, show_fields } = {}
69
+ } = payload
70
+
71
+ const fbEvent: FBEvent = {
72
+ ...(content_category ? { content_category } : {}),
73
+ ...(content_ids && Array.isArray(content_ids) && content_ids.length > 0 ? { content_ids } : {}),
74
+ ...(content_name ? { content_name } : {}),
75
+ ...(content_type ? { content_type } : {}),
76
+ ...(contents && Array.isArray(contents) && contents.length > 0 ? { contents } : {}),
77
+ ...(currency ? { currency } : {}),
78
+ ...(delivery_category ? { delivery_category } : {}),
79
+ ...(typeof num_items === 'number' ? { num_items } : {}),
80
+ ...(typeof value === 'number' ? { value } : {}),
81
+ ...(typeof predicted_ltv === 'number' ? { predicted_ltv } : {}),
82
+ ...(typeof net_revenue === 'number' ? { net_revenue } : {}),
83
+ ...(custom_data && Object.entries(custom_data).length > 0 ? { custom_data } : {})
84
+ }
85
+
86
+ if (show_fields === false) {
87
+ // If show_fields is false we delete values for fields which are hidden in the UI.
88
+ const fieldsToDelete = getNotVisibleForEvent(event_name as FBStandardEventType | FBNonStandardEventType)
89
+ fieldsToDelete.forEach((field) => {
90
+ if (field in fbEvent) {
91
+ delete fbEvent[field as keyof typeof fbEvent]
92
+ }
93
+ })
94
+ }
95
+
96
+ return Object.keys(fbEvent).length > 0 ? fbEvent : {}
115
97
  }
116
98
 
117
99
  function formatOptions(payload: Payload): EventOptions | undefined {
118
- const { eventID, eventSourceUrl } = payload
119
- const options: EventOptions = {
120
- ...(eventID ? { eventID } : {}),
121
- ...(eventSourceUrl ? { eventSourceUrl } : {}),
122
- }
123
- return Object.values(options).some(Boolean) ? options : undefined
100
+ const { eventID, eventSourceUrl } = payload
101
+ const options: EventOptions = {
102
+ ...(eventID ? { eventID } : {}),
103
+ ...(eventSourceUrl ? { eventSourceUrl } : {})
104
+ }
105
+ return Object.values(options).some(Boolean) ? options : undefined
124
106
  }
125
107
 
126
108
  function maybeSendUserData(client: FBClient, payload: Payload, settings: Settings, analytics: Analytics) {
127
- const { pixelId } = settings
128
- const { userData } = payload
129
- const userDataFormatted = formatUserData(userData)
130
-
131
- if(userDataFormatted) {
132
- const storage = (analytics.storage as UniversalStorage<Record<string, string>>) ?? storageFallback
133
- const initCountFromStorage: string | null = storage.get(INIT_COUNT_KEY)
134
- const initCount: number | undefined = (initCountFromStorage && !isNaN(Number(initCountFromStorage)))
135
- ? parseInt(initCountFromStorage, 10)
136
- : undefined
137
-
138
- if(typeof initCount === 'number' && initCount < MAX_INIT_COUNT) {
139
- client('init', pixelId, userDataFormatted)
140
- setStorageInitCount(analytics, initCount + 1)
141
- }
142
-
143
- storage.set(USER_DATA_KEY, JSON.stringify(userDataFormatted))
144
- }
145
- }
146
-
147
- function formatUserData(userData: Payload['userData']): UserData | undefined {
148
- if(!userData){
149
- return undefined
109
+ const { pixelId } = settings
110
+ const { userData } = payload
111
+ const userDataFormatted = formatUserData(userData)
112
+
113
+ if (userDataFormatted) {
114
+ const storage = (analytics.storage as UniversalStorage<Record<string, string>>) ?? storageFallback
115
+ const initCountFromStorage: string | null = storage.get(INIT_COUNT_KEY)
116
+ const initCount: number | undefined =
117
+ initCountFromStorage && !isNaN(Number(initCountFromStorage)) ? parseInt(initCountFromStorage, 10) : undefined
118
+
119
+ if (typeof initCount === 'number' && initCount < MAX_INIT_COUNT) {
120
+ client('init', pixelId, userDataFormatted)
121
+ setStorageInitCount(analytics, initCount + 1)
150
122
  }
151
123
 
152
- const {
153
- external_id,
154
- em,
155
- ph,
156
- fn,
157
- ln,
158
- ge,
159
- db,
160
- ct,
161
- st,
162
- zp,
163
- country
164
- } = userData
165
-
166
- const dbFormatted = formatDate(db)
167
- const stFormatted = fromMap(US_STATE_CODES, st)
168
- const countryFormatted = fromMap(COUNTRY_CODES, country)
169
-
170
- const ud: UserData = {
171
- ...(typeof em === 'string' ? {em: em.toLowerCase().trim()} : {}), // lowercase and trim whitespace
172
- ...(typeof ph === 'string' ? {ph: ph.replace(/\D/g, '')} : {}), // remove non-numeric characters
173
- ...(typeof fn === 'string' ? {fn: fn.toLowerCase().trim()} : {}), // lowercase and trim whitespace
174
- ...(typeof ln === 'string' ? {ln: ln.toLowerCase().trim()} : {}), // lowercase and trim whitespace
175
- ...(typeof ge === 'string' && ['m', 'f'].includes(ge) ? { ge: ge as 'm' | 'f' } : {}),
176
- ...(typeof dbFormatted === 'string' ? {db: dbFormatted} : {}), // format date to YYYYMMDD
177
- ...(typeof ct === 'string' ? {ct: ct.toLowerCase().replace(/\s+/g, '')} : {}), // lowercase and replace any whitespace
178
- ...(typeof stFormatted === 'string' ? {st: stFormatted} : {}), // lowercase 2 character state code
179
- ...(typeof zp === 'string' ? {zp: zp.trim()} : {}),
180
- ...(typeof countryFormatted === 'string' ? {country: countryFormatted} : {}), // lowercase 2 character country code
181
- ...(typeof external_id === 'string' ? {external_id: external_id.trim()} : {}) // trim whitespace
182
- }
124
+ storage.set(USER_DATA_KEY, JSON.stringify(userDataFormatted))
125
+ }
126
+ }
183
127
 
184
- if(Object.keys(ud).length === 0){
185
- return undefined
186
- }
187
- return ud
128
+ function formatUserData(userData: Payload['userData']): UserData | undefined {
129
+ if (!userData) {
130
+ return undefined
131
+ }
132
+
133
+ const { external_id, em, ph, fn, ln, ge, db, ct, st, zp, country } = userData
134
+
135
+ const dbFormatted = formatDate(db)
136
+ const stFormatted = fromMap(US_STATE_CODES, st)
137
+ const countryFormatted = fromMap(COUNTRY_CODES, country)
138
+
139
+ const ud: UserData = {
140
+ ...(typeof em === 'string' ? { em: em.toLowerCase().trim() } : {}), // lowercase and trim whitespace
141
+ ...(typeof ph === 'string' ? { ph: ph.replace(/\D/g, '') } : {}), // remove non-numeric characters
142
+ ...(typeof fn === 'string' ? { fn: fn.toLowerCase().trim() } : {}), // lowercase and trim whitespace
143
+ ...(typeof ln === 'string' ? { ln: ln.toLowerCase().trim() } : {}), // lowercase and trim whitespace
144
+ ...(typeof ge === 'string' && ['m', 'f'].includes(ge) ? { ge: ge as 'm' | 'f' } : {}),
145
+ ...(typeof dbFormatted === 'string' ? { db: dbFormatted } : {}), // format date to YYYYMMDD
146
+ ...(typeof ct === 'string' ? { ct: ct.toLowerCase().replace(/\s+/g, '') } : {}), // lowercase and replace any whitespace
147
+ ...(typeof stFormatted === 'string' ? { st: stFormatted } : {}), // lowercase 2 character state code
148
+ ...(typeof zp === 'string' ? { zp: zp.trim() } : {}),
149
+ ...(typeof countryFormatted === 'string' ? { country: countryFormatted } : {}), // lowercase 2 character country code
150
+ ...(typeof external_id === 'string' ? { external_id: external_id.trim() } : {}) // trim whitespace
151
+ }
152
+
153
+ if (Object.keys(ud).length === 0) {
154
+ return undefined
155
+ }
156
+ return ud
188
157
  }
189
158
 
190
159
  function formatDate(isoDate?: string): string | undefined {
191
- if (!isoDate || typeof isoDate !== 'string') {
192
- return undefined
193
- }
194
- const date = new Date(isoDate)
195
- if (isNaN(date.getTime())) {
196
- return undefined
197
- }
198
- const year = date.getUTCFullYear()
199
- const month = (date.getUTCMonth() + 1).toString().padStart(2, '0')
200
- const day = date.getUTCDate().toString().padStart(2, '0')
201
- return `${year}${month}${day}`
160
+ if (!isoDate || typeof isoDate !== 'string') {
161
+ return undefined
162
+ }
163
+ const date = new Date(isoDate)
164
+ if (isNaN(date.getTime())) {
165
+ return undefined
166
+ }
167
+ const year = date.getUTCFullYear()
168
+ const month = (date.getUTCMonth() + 1).toString().padStart(2, '0')
169
+ const day = date.getUTCDate().toString().padStart(2, '0')
170
+ return `${year}${month}${day}`
202
171
  }
203
172
 
204
173
  function fromMap(map: Map<string, string>, value?: string): string | undefined {
205
- const cleaned = value?.toLowerCase().replace(/[^a-z]/g, '').trim()
206
- if (!cleaned) {
207
- return undefined
208
- }
209
- if(cleaned.length === 2 && Array.from(map.values()).includes(cleaned)) {
210
- return cleaned
211
- }
212
- return map.get(cleaned) || undefined
213
- }
174
+ const cleaned = value
175
+ ?.toLowerCase()
176
+ .replace(/[^a-z]/g, '')
177
+ .trim()
178
+ if (!cleaned) {
179
+ return undefined
180
+ }
181
+ if (cleaned.length === 2 && Array.from(map.values()).includes(cleaned)) {
182
+ return cleaned
183
+ }
184
+ return map.get(cleaned) || undefined
185
+ }
package/src/send/index.ts CHANGED
@@ -12,8 +12,8 @@ const action: BrowserActionDefinition<Settings, FBClient, Payload> = {
12
12
  platform: 'web',
13
13
  fields: AllFields,
14
14
  perform: (client, { payload, settings, analytics }) => {
15
- return send(client, payload, settings, analytics)
15
+ return send(client, payload, settings, analytics)
16
16
  }
17
17
  }
18
18
 
19
- export default action
19
+ export default action
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export interface WindowWithOptionalFbq extends Omit<Window, 'fbq' | '_fbq'> {
2
- fbq?: FBClient;
3
- _fbq?: FBClient;
2
+ fbq?: FBClient
3
+ _fbq?: FBClient
4
4
  }
5
5
 
6
6
  export type FBStandardEventType =
@@ -29,8 +29,8 @@ export type InitOptions = {
29
29
  agent?: string
30
30
  }
31
31
 
32
- export type EventOptions = {
33
- eventID?: string
32
+ export type EventOptions = {
33
+ eventID?: string
34
34
  eventSourceUrl?: string
35
35
  }
36
36
 
@@ -63,7 +63,7 @@ export type FBEvent = {
63
63
  currency?: string
64
64
  delivery_category?: string
65
65
  num_items?: number
66
- value?: number
66
+ value?: number
67
67
  custom_data?: {
68
68
  [k: string]: unknown
69
69
  }
@@ -78,26 +78,26 @@ export type FBClient = {
78
78
  callMethod?: (...args: unknown[]) => void
79
79
  (command: 'set', key: string, value: boolean, pixelId: string): void
80
80
  (command: 'dataProcessingOptions', options: string[], country?: number, state?: number): void
81
- (command: 'init', pixelId: string, userData?: UserData, options?: InitOptions ): void
81
+ (command: 'init', pixelId: string, userData?: UserData, options?: InitOptions): void
82
82
  (command: 'trackSingle', pixelId: string, event: FBStandardEventType, params?: FBEvent, options?: EventOptions): void
83
83
  (command: 'trackSingleCustom', pixelId: string, event: string, params?: FBEvent, options?: EventOptions): void
84
84
  }
85
85
 
86
86
  export const LDU = {
87
- Disabled: {key: 'Disabled', state: undefined, country: undefined},
88
- GeolocationLogic: {key: 'GeolocationLogic', state: 0, country: 0},
89
- California: {key: 'California', state: 1000, country: 1},
90
- Colorado: {key: 'Colorado', state: 1001, country: 1},
91
- Connecticut: {key: 'Connecticut', state: 1002, country: 1},
92
- Florida: {key: 'Florida', state: 1003, country: 1},
93
- Oregon: {key: 'Oregon', state: 1004, country: 1},
94
- Texas: {key: 'Texas', state: 1005, country: 1},
95
- Montana: {key: 'Montana', state: 1006, country: 1},
96
- Delaware: {key: 'Delaware', state: 1007, country: 1},
97
- Nebraska: {key: 'Nebraska', state: 1008, country: 1},
98
- NewHampshire: {key: 'NewHampshire', state: 1009, country: 1},
99
- NewJersey: {key: 'NewJersey', state: 1010, country: 1},
100
- Minnesota: {key: 'Minnesota', state: 1011, country: 1}
87
+ Disabled: { key: 'Disabled', state: undefined, country: undefined },
88
+ GeolocationLogic: { key: 'GeolocationLogic', state: 0, country: 0 },
89
+ California: { key: 'California', state: 1000, country: 1 },
90
+ Colorado: { key: 'Colorado', state: 1001, country: 1 },
91
+ Connecticut: { key: 'Connecticut', state: 1002, country: 1 },
92
+ Florida: { key: 'Florida', state: 1003, country: 1 },
93
+ Oregon: { key: 'Oregon', state: 1004, country: 1 },
94
+ Texas: { key: 'Texas', state: 1005, country: 1 },
95
+ Montana: { key: 'Montana', state: 1006, country: 1 },
96
+ Delaware: { key: 'Delaware', state: 1007, country: 1 },
97
+ Nebraska: { key: 'Nebraska', state: 1008, country: 1 },
98
+ NewHampshire: { key: 'NewHampshire', state: 1009, country: 1 },
99
+ NewJersey: { key: 'NewJersey', state: 1010, country: 1 },
100
+ Minnesota: { key: 'Minnesota', state: 1011, country: 1 }
101
101
  } as const
102
102
 
103
- export type LDU = typeof LDU[keyof typeof LDU]
103
+ export type LDU = typeof LDU[keyof typeof LDU]