@segment/analytics-browser-actions-facebook-conversions-api-web 1.8.1-staging-701e5e031.0 → 1.9.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.
- package/dist/cjs/functions.js +2 -5
- package/dist/cjs/functions.js.map +1 -1
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/send/depends-on.js +5 -37
- package/dist/cjs/send/depends-on.js.map +1 -1
- package/dist/cjs/send/fields.js +5 -5
- package/dist/cjs/send/fields.js.map +1 -1
- package/dist/cjs/send/functions.js +8 -10
- package/dist/cjs/send/functions.js.map +1 -1
- package/dist/cjs/types.d.ts +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/functions.js +2 -5
- package/dist/esm/functions.js.map +1 -1
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/send/depends-on.js +5 -37
- package/dist/esm/send/depends-on.js.map +1 -1
- package/dist/esm/send/fields.js +5 -5
- package/dist/esm/send/fields.js.map +1 -1
- package/dist/esm/send/functions.js +8 -10
- package/dist/esm/send/functions.js.map +1 -1
- package/dist/esm/types.d.ts +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/constants.ts +1 -1
- package/src/functions.ts +66 -59
- package/src/index.ts +27 -22
- package/src/send/depends-on.ts +30 -62
- package/src/send/fields.ts +291 -299
- package/src/send/functions.ts +179 -151
- package/src/send/generated-types.ts +3 -3
- package/src/send/index.ts +2 -2
- package/src/types.ts +22 -22
package/src/send/functions.ts
CHANGED
|
@@ -2,184 +2,212 @@ 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 {
|
|
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
|
-
|
|
11
|
-
|
|
10
|
+
const { pixelId } = settings
|
|
11
|
+
const {
|
|
12
|
+
event_config: {
|
|
13
|
+
custom_event_name,
|
|
14
|
+
event_name
|
|
15
|
+
} = {}
|
|
16
|
+
} = payload
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
const isCustom = event_name === 'CustomEvent' ? true : false
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
const errorMessage = validate(payload)
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
33
51
|
}
|
|
34
52
|
|
|
35
53
|
function validate(payload: Payload): string | undefined {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
) {
|
|
47
|
-
return `At least one of content_ids or contents is required for the ${event_name} event.`
|
|
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
|
+
}
|
|
48
64
|
}
|
|
49
|
-
}
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
return undefined
|
|
52
67
|
}
|
|
53
68
|
|
|
54
69
|
function formatFBEvent(payload: Payload): FBEvent {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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 : {}
|
|
97
115
|
}
|
|
98
116
|
|
|
99
117
|
function formatOptions(payload: Payload): EventOptions | undefined {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
function maybeSendUserData(client: FBClient, payload: Payload, settings: Settings, analytics: Analytics) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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))
|
|
122
144
|
}
|
|
123
|
-
|
|
124
|
-
storage.set(USER_DATA_KEY, JSON.stringify(userDataFormatted))
|
|
125
|
-
}
|
|
126
|
-
}
|
|
145
|
+
}
|
|
127
146
|
|
|
128
147
|
function formatUserData(userData: Payload['userData']): UserData | undefined {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
if(!userData){
|
|
149
|
+
return undefined
|
|
150
|
+
}
|
|
151
|
+
|
|
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
|
+
}
|
|
183
|
+
|
|
184
|
+
if(Object.keys(ud).length === 0){
|
|
185
|
+
return undefined
|
|
186
|
+
}
|
|
187
|
+
return ud
|
|
157
188
|
}
|
|
158
189
|
|
|
159
190
|
function formatDate(isoDate?: string): string | undefined {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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}`
|
|
171
202
|
}
|
|
172
203
|
|
|
173
204
|
function fromMap(map: Map<string, string>, value?: string): string | undefined {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
return map.get(cleaned) || undefined
|
|
185
|
-
}
|
|
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
|
+
}
|
|
@@ -91,7 +91,7 @@ export interface Payload {
|
|
|
91
91
|
[k: string]: unknown
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
-
* This ID can be any unique string. Event ID is used to deduplicate events sent
|
|
94
|
+
* This ID can be any unique string. Event ID is used to deduplicate events sent both the server side Conversions API and the browser Pixel.
|
|
95
95
|
*/
|
|
96
96
|
eventID?: string
|
|
97
97
|
/**
|
|
@@ -111,7 +111,7 @@ export interface Payload {
|
|
|
111
111
|
*/
|
|
112
112
|
em?: string
|
|
113
113
|
/**
|
|
114
|
-
* Phone number of the user
|
|
114
|
+
* Phone number of the user. Make sure to include the country code. For example, "15551234567" for a US number.
|
|
115
115
|
*/
|
|
116
116
|
ph?: string
|
|
117
117
|
/**
|
|
@@ -139,7 +139,7 @@ export interface Payload {
|
|
|
139
139
|
*/
|
|
140
140
|
st?: string
|
|
141
141
|
/**
|
|
142
|
-
* ZIP or postal code of the user. For example,
|
|
142
|
+
* ZIP or postal code of the user. For example, U.S zip code: 94035, Australia zip code: 1987, France zip code: 75018, UK zip code: m11ae.
|
|
143
143
|
*/
|
|
144
144
|
zp?: string
|
|
145
145
|
/**
|
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
|
|
|
@@ -41,7 +41,7 @@ export type UserData = {
|
|
|
41
41
|
ph?: string // Phone number (FB hashes with SHA-256)
|
|
42
42
|
fn?: string // First name (FB hashes with SHA-256)
|
|
43
43
|
ln?: string // Last name (FB hashes with SHA-256)
|
|
44
|
-
ge?:
|
|
44
|
+
ge?: 'm' | 'f' // Gender (FB hashes with SHA-256)
|
|
45
45
|
db?: string // Date of birth (FB hashes with SHA-256) - format: YYYYMMDD
|
|
46
46
|
ct?: string // City (FB hashes with SHA-256)
|
|
47
47
|
st?: string // State (FB hashes with SHA-256)
|
|
@@ -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: {
|
|
88
|
-
GeolocationLogic: {
|
|
89
|
-
California: {
|
|
90
|
-
Colorado: {
|
|
91
|
-
Connecticut: {
|
|
92
|
-
Florida: {
|
|
93
|
-
Oregon: {
|
|
94
|
-
Texas: {
|
|
95
|
-
Montana: {
|
|
96
|
-
Delaware: {
|
|
97
|
-
Nebraska: {
|
|
98
|
-
NewHampshire: {
|
|
99
|
-
NewJersey: {
|
|
100
|
-
Minnesota: {
|
|
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]
|