@ht-sdks/events-sdk-js-browser 1.5.7 → 1.5.8
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/README.md +41 -0
- package/dist/cjs/browser/dedupe-plugin-likes.js +53 -0
- package/dist/cjs/browser/dedupe-plugin-likes.js.map +1 -0
- package/dist/cjs/browser/index.js +89 -32
- package/dist/cjs/browser/index.js.map +1 -1
- package/dist/cjs/core/analytics/index.js.map +1 -1
- package/dist/cjs/generated/version.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/plugins/built-in-plugins.js +5 -0
- package/dist/cjs/plugins/built-in-plugins.js.map +1 -0
- package/dist/cjs/plugins/facebook-params/index.js +115 -0
- package/dist/cjs/plugins/facebook-params/index.js.map +1 -0
- package/dist/cjs/plugins/index.js +26 -0
- package/dist/cjs/plugins/index.js.map +1 -0
- package/dist/pkg/browser/dedupe-plugin-likes.js +48 -0
- package/dist/pkg/browser/dedupe-plugin-likes.js.map +1 -0
- package/dist/pkg/browser/index.js +89 -32
- package/dist/pkg/browser/index.js.map +1 -1
- package/dist/pkg/core/analytics/index.js.map +1 -1
- package/dist/pkg/generated/version.js +1 -1
- package/dist/pkg/index.js.map +1 -1
- package/dist/pkg/plugins/built-in-plugins.js +2 -0
- package/dist/pkg/plugins/built-in-plugins.js.map +1 -0
- package/dist/pkg/plugins/facebook-params/index.js +112 -0
- package/dist/pkg/plugins/facebook-params/index.js.map +1 -0
- package/dist/pkg/plugins/index.js +23 -0
- package/dist/pkg/plugins/index.js.map +1 -0
- package/dist/types/browser/dedupe-plugin-likes.d.ts +7 -0
- package/dist/types/browser/dedupe-plugin-likes.d.ts.map +1 -0
- package/dist/types/browser/index.d.ts.map +1 -1
- package/dist/types/core/analytics/index.d.ts +7 -1
- package/dist/types/core/analytics/index.d.ts.map +1 -1
- package/dist/types/core/buffer/index.d.ts +1 -1
- package/dist/types/generated/version.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/plugins/built-in-plugins.d.ts +3 -0
- package/dist/types/plugins/built-in-plugins.d.ts.map +1 -0
- package/dist/types/plugins/facebook-params/index.d.ts +27 -0
- package/dist/types/plugins/facebook-params/index.d.ts.map +1 -0
- package/dist/types/plugins/index.d.ts +11 -0
- package/dist/types/plugins/index.d.ts.map +1 -0
- package/dist/umd/events.min.js +1 -1
- package/dist/umd/events.min.js.gz +0 -0
- package/dist/umd/events.min.js.map +1 -1
- package/dist/umd/events.min.js.map.gz +0 -0
- package/dist/umd/facebook-params.bundle.bc6597a53dc18e288950.js +2 -0
- package/dist/umd/facebook-params.bundle.bc6597a53dc18e288950.js.gz +0 -0
- package/dist/umd/facebook-params.bundle.bc6597a53dc18e288950.js.map +1 -0
- package/dist/umd/facebook-params.bundle.bc6597a53dc18e288950.js.map.gz +0 -0
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.gz +0 -0
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/index.js.map.gz +0 -0
- package/dist/umd/meta-param-builder.bundle.aab3a6e0c91673752d5a.js +2 -0
- package/dist/umd/meta-param-builder.bundle.aab3a6e0c91673752d5a.js.gz +0 -0
- package/dist/umd/meta-param-builder.bundle.aab3a6e0c91673752d5a.js.map +1 -0
- package/dist/umd/meta-param-builder.bundle.aab3a6e0c91673752d5a.js.map.gz +0 -0
- package/package.json +2 -1
- package/src/browser/dedupe-plugin-likes.ts +62 -0
- package/src/browser/index.ts +70 -11
- package/src/core/analytics/index.ts +8 -1
- package/src/generated/version.ts +1 -1
- package/src/index.ts +1 -0
- package/src/plugins/built-in-plugins.ts +3 -0
- package/src/plugins/facebook-params/index.ts +121 -0
- package/src/plugins/index.ts +22 -0
- package/src/types/meta-capi-param-builder-clientjs.d.ts +32 -0
package/src/browser/index.ts
CHANGED
|
@@ -31,6 +31,16 @@ import { ClassicIntegrationSource } from '../plugins/ajs-destination/types'
|
|
|
31
31
|
import { attachInspector } from '../core/inspector'
|
|
32
32
|
import { setGlobalAnalyticsKey } from '../lib/global-analytics-helper'
|
|
33
33
|
import { createDestination } from '../plugins/destinations'
|
|
34
|
+
import { createPlugin } from '../plugins'
|
|
35
|
+
import {
|
|
36
|
+
BUILT_IN_PLUGINS,
|
|
37
|
+
type BuiltInPluginName,
|
|
38
|
+
} from '../plugins/built-in-plugins'
|
|
39
|
+
import {
|
|
40
|
+
dedupePluginFactories,
|
|
41
|
+
dedupePlugins,
|
|
42
|
+
dedupeStringPluginNames,
|
|
43
|
+
} from './dedupe-plugin-likes'
|
|
34
44
|
|
|
35
45
|
export interface LegacyIntegrationConfiguration {
|
|
36
46
|
/* @deprecated - This does not indicate browser types anymore */
|
|
@@ -180,18 +190,36 @@ async function registerPlugins(
|
|
|
180
190
|
analytics: Analytics,
|
|
181
191
|
opts: InitOptions,
|
|
182
192
|
options: InitOptions,
|
|
183
|
-
pluginLikes: (Plugin | PluginFactory)[] = [],
|
|
193
|
+
pluginLikes: (Plugin | PluginFactory | BuiltInPluginName)[] = [],
|
|
184
194
|
legacyIntegrationSources: ClassicIntegrationSource[]
|
|
185
195
|
): Promise<Context> {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
(pluginLike)
|
|
196
|
+
const stringPluginNames: BuiltInPluginName[] = []
|
|
197
|
+
const plugins: Plugin[] = []
|
|
198
|
+
const pluginSources: PluginFactory[] = []
|
|
199
|
+
|
|
200
|
+
for (const pluginLike of pluginLikes) {
|
|
201
|
+
if (typeof pluginLike === 'string') {
|
|
202
|
+
if (BUILT_IN_PLUGINS.includes(pluginLike)) {
|
|
203
|
+
stringPluginNames.push(pluginLike)
|
|
204
|
+
} else {
|
|
205
|
+
console.warn(`failed to load plugin: ${pluginLike}`)
|
|
206
|
+
}
|
|
207
|
+
} else if (typeof pluginLike === 'object' && pluginLike !== null) {
|
|
208
|
+
plugins.push(pluginLike)
|
|
209
|
+
} else if (
|
|
192
210
|
typeof pluginLike === 'function' &&
|
|
193
211
|
typeof pluginLike.pluginName === 'string'
|
|
194
|
-
|
|
212
|
+
) {
|
|
213
|
+
pluginSources.push(pluginLike)
|
|
214
|
+
} else {
|
|
215
|
+
console.warn(`failed to load plugin: ${pluginLike}`)
|
|
216
|
+
continue
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const uniqueStringPluginNames = dedupeStringPluginNames(stringPluginNames)
|
|
221
|
+
const uniquePlugins = dedupePlugins(plugins)
|
|
222
|
+
const uniquePluginSources = dedupePluginFactories(pluginSources)
|
|
195
223
|
|
|
196
224
|
const tsubMiddleware = hasTsubMiddleware(legacySettings)
|
|
197
225
|
? await import(
|
|
@@ -242,13 +270,40 @@ async function registerPlugins(
|
|
|
242
270
|
mergedSettings,
|
|
243
271
|
options.obfuscate,
|
|
244
272
|
tsubMiddleware,
|
|
245
|
-
|
|
273
|
+
uniquePluginSources
|
|
246
274
|
).catch(() => [])
|
|
247
275
|
|
|
276
|
+
// Load string-based plugins
|
|
277
|
+
const loadedStringPlugins = await Promise.allSettled(
|
|
278
|
+
uniqueStringPluginNames.map(async (name) => {
|
|
279
|
+
const plugin = await createPlugin(name)
|
|
280
|
+
if (plugin) {
|
|
281
|
+
return plugin
|
|
282
|
+
} else {
|
|
283
|
+
console.warn(`failed to load plugin: ${name}`)
|
|
284
|
+
return null
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
const resolvedStringPlugins = loadedStringPlugins
|
|
290
|
+
.map((result, index) => {
|
|
291
|
+
if (result.status === 'fulfilled') {
|
|
292
|
+
return result.value
|
|
293
|
+
}
|
|
294
|
+
console.error(
|
|
295
|
+
`failed to load plugin: ${uniqueStringPluginNames[index]}`,
|
|
296
|
+
result.reason
|
|
297
|
+
)
|
|
298
|
+
return null
|
|
299
|
+
})
|
|
300
|
+
.filter((plugin): plugin is Plugin => plugin !== null)
|
|
301
|
+
|
|
248
302
|
const toRegister = [
|
|
249
303
|
validation,
|
|
250
304
|
envEnrichment,
|
|
251
|
-
...
|
|
305
|
+
...uniquePlugins,
|
|
306
|
+
...resolvedStringPlugins,
|
|
252
307
|
...legacyDestinations,
|
|
253
308
|
...remotePlugins,
|
|
254
309
|
]
|
|
@@ -384,7 +439,11 @@ async function loadAnalytics(
|
|
|
384
439
|
|
|
385
440
|
attachInspector(analytics)
|
|
386
441
|
|
|
387
|
-
|
|
442
|
+
// Merge plugins from both settings and options
|
|
443
|
+
// This allows plugins to be specified in either place:
|
|
444
|
+
// - settings.plugins (when using HtEventsBrowser.load({ writeKey, plugins: [...] }))
|
|
445
|
+
// - options.plugins (when using snippet pattern: htevents.load(writeKey, { plugins: [...] }))
|
|
446
|
+
const plugins = [...(settings.plugins ?? []), ...(options.plugins ?? [])]
|
|
388
447
|
|
|
389
448
|
const classicIntegrations = settings.classicIntegrations ?? []
|
|
390
449
|
|
|
@@ -60,6 +60,7 @@ import type {
|
|
|
60
60
|
HTTPCookieServiceOptions,
|
|
61
61
|
} from '../http-cookies'
|
|
62
62
|
import type { DestinationSettings } from '../../plugins/destinations'
|
|
63
|
+
import type { BuiltInPluginName } from '../../plugins/built-in-plugins'
|
|
63
64
|
|
|
64
65
|
const deprecationWarning =
|
|
65
66
|
'This is being deprecated and will be not be available in future releases of Analytics JS'
|
|
@@ -83,7 +84,7 @@ function createDefaultQueue(
|
|
|
83
84
|
export interface AnalyticsSettings {
|
|
84
85
|
writeKey: string
|
|
85
86
|
timeout?: number
|
|
86
|
-
plugins?: (Plugin | PluginFactory)[]
|
|
87
|
+
plugins?: (Plugin | PluginFactory | BuiltInPluginName)[]
|
|
87
88
|
classicIntegrations?: ClassicIntegrationSource[]
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -139,6 +140,12 @@ export interface InitOptions {
|
|
|
139
140
|
*/
|
|
140
141
|
destinations?: Record<string, DestinationSettings>
|
|
141
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Array of plugins to load. Can be plugin instances, plugin factories, or built-in plugin names.
|
|
145
|
+
* Built-in names are resolved via createPlugin() for code-split loading.
|
|
146
|
+
*/
|
|
147
|
+
plugins?: (Plugin | PluginFactory | BuiltInPluginName)[]
|
|
148
|
+
|
|
142
149
|
/**
|
|
143
150
|
* When setting httpCookieServiceOptions, an HTTPCookieService is automatically created
|
|
144
151
|
*/
|
package/src/generated/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is generated.
|
|
2
|
-
export const version = '1.5.
|
|
2
|
+
export const version = '1.5.8'
|
package/src/index.ts
CHANGED
|
@@ -10,5 +10,6 @@ export * from './core/user'
|
|
|
10
10
|
export type { HtEventsSnippet } from './browser/standalone-interface'
|
|
11
11
|
export type { MiddlewareFunction } from './plugins/middleware'
|
|
12
12
|
export { Destination } from './plugins/destinations'
|
|
13
|
+
export type { BuiltInPluginName } from './plugins/built-in-plugins'
|
|
13
14
|
export { getGlobalAnalytics } from './lib/global-analytics-helper'
|
|
14
15
|
export { UniversalStorage, Store, StorageObject } from './core/storage'
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Context } from '../../core/context'
|
|
2
|
+
import type { Plugin } from '../../core/plugin'
|
|
3
|
+
import { PluginType } from '@ht-sdks/events-sdk-js-core'
|
|
4
|
+
import { Analytics } from '../../core/analytics'
|
|
5
|
+
import { isServer } from '../../core/environment'
|
|
6
|
+
import type { ClientParamBuilder } from 'meta-capi-param-builder-clientjs'
|
|
7
|
+
|
|
8
|
+
const SDK_LOAD_TIMEOUT_MS = 2000
|
|
9
|
+
const SDK_LOAD_TIMEOUT_MESSAGE = 'Facebook Parameter Builder SDK load timed out'
|
|
10
|
+
|
|
11
|
+
function withTimeout<T>(
|
|
12
|
+
promise: Promise<T>,
|
|
13
|
+
ms: number,
|
|
14
|
+
message: string
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
let timer: ReturnType<typeof setTimeout>
|
|
17
|
+
|
|
18
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
19
|
+
timer = setTimeout(() => reject(new Error(message)), ms)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
23
|
+
clearTimeout(timer)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class FacebookParamsPlugin implements Plugin {
|
|
28
|
+
private clientParamBuilder: ClientParamBuilder | null = null
|
|
29
|
+
private sdkReady = false
|
|
30
|
+
|
|
31
|
+
name = 'Facebook Parameters'
|
|
32
|
+
type: PluginType = 'enrichment'
|
|
33
|
+
version = '0.1.0'
|
|
34
|
+
|
|
35
|
+
isLoaded = () => this.sdkReady
|
|
36
|
+
|
|
37
|
+
load = async (_ctx: Context, _instance: Analytics): Promise<void> => {
|
|
38
|
+
if (isServer()) {
|
|
39
|
+
// Server-side rendering - skip loading
|
|
40
|
+
return Promise.resolve()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Runs to completion on its own, even if the race below gives up waiting
|
|
44
|
+
const init = (async () => {
|
|
45
|
+
const paramBuilderModule = await import(
|
|
46
|
+
/* webpackChunkName: "meta-param-builder" */ 'meta-capi-param-builder-clientjs'
|
|
47
|
+
)
|
|
48
|
+
const clientParamBuilder = (paramBuilderModule.default ??
|
|
49
|
+
paramBuilderModule) as ClientParamBuilder
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
!clientParamBuilder ||
|
|
53
|
+
typeof clientParamBuilder.processAndCollectAllParams !== 'function' ||
|
|
54
|
+
typeof clientParamBuilder.getFbc !== 'function' ||
|
|
55
|
+
typeof clientParamBuilder.getFbp !== 'function'
|
|
56
|
+
) {
|
|
57
|
+
console.warn(
|
|
58
|
+
'Facebook Parameter Builder SDK loaded but clientParamBuilder is not available or does not expose expected interface'
|
|
59
|
+
)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await clientParamBuilder.processAndCollectAllParams()
|
|
64
|
+
this.clientParamBuilder = clientParamBuilder
|
|
65
|
+
this.sdkReady = true
|
|
66
|
+
})().catch((error) => {
|
|
67
|
+
console.warn('Failed to load Facebook Parameter Builder SDK:', error)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// Timeout only bounds how long the event queue waits — it doesn't cancel init
|
|
71
|
+
await _instance.queue.criticalTasks.run(() =>
|
|
72
|
+
withTimeout(init, SDK_LOAD_TIMEOUT_MS, SDK_LOAD_TIMEOUT_MESSAGE).catch(
|
|
73
|
+
() => {}
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private enrich = (ctx: Context): Context => {
|
|
79
|
+
if (!this.sdkReady || !this.clientParamBuilder) {
|
|
80
|
+
return ctx
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const evtCtx = ctx.event.context
|
|
85
|
+
if (!evtCtx) {
|
|
86
|
+
return ctx
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Get fbc and fbp from cookies (processAndCollectAllParams was called during load)
|
|
90
|
+
const fbc = this.clientParamBuilder.getFbc()
|
|
91
|
+
const fbp = this.clientParamBuilder.getFbp()
|
|
92
|
+
|
|
93
|
+
// Only add if not empty (getFbc/getFbp return empty string if cookie doesn't exist)
|
|
94
|
+
if (fbc) {
|
|
95
|
+
evtCtx.fbc = fbc
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (fbp) {
|
|
99
|
+
evtCtx.fbp = fbp
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
// Silently fail - don't break event processing if SDK has issues
|
|
103
|
+
console.warn('Error extracting Facebook parameters:', error)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return ctx
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
track = this.enrich
|
|
110
|
+
identify = this.enrich
|
|
111
|
+
page = this.enrich
|
|
112
|
+
group = this.enrich
|
|
113
|
+
alias = this.enrich
|
|
114
|
+
screen = this.enrich
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Default plugin instance using Meta's official ParamBuilder SDK.
|
|
119
|
+
* Used when plugin is loaded via string name: plugins: ["facebook-params"]
|
|
120
|
+
*/
|
|
121
|
+
export const facebookParams = new FacebookParamsPlugin()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Plugin } from '../core/plugin'
|
|
2
|
+
import type { BuiltInPluginName } from './built-in-plugins'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a plugin instance from a string name.
|
|
6
|
+
* This allows script tag users to specify plugins by name without importing them.
|
|
7
|
+
*
|
|
8
|
+
* @param name - The name of the plugin to load
|
|
9
|
+
* @returns A promise that resolves to the plugin instance, or undefined if not found
|
|
10
|
+
*/
|
|
11
|
+
export async function createPlugin(
|
|
12
|
+
name: BuiltInPluginName
|
|
13
|
+
): Promise<Plugin | undefined> {
|
|
14
|
+
switch (name) {
|
|
15
|
+
case 'facebook-params':
|
|
16
|
+
return import(
|
|
17
|
+
/* webpackChunkName: "facebook-params" */ './facebook-params'
|
|
18
|
+
).then((mod) => mod.facebookParams)
|
|
19
|
+
default:
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
declare module 'meta-capi-param-builder-clientjs' {
|
|
2
|
+
// Facebook Parameter Builder SDK types (clientParamBuilder)
|
|
3
|
+
// Based on Meta's official API: https://developers.facebook.com/docs/marketing-api/conversions-api/parameter-builder-feature-library/client-side-onboarding
|
|
4
|
+
export interface ClientParamBuilder {
|
|
5
|
+
/**
|
|
6
|
+
* Processes and collects all parameters (fbc, fbp, client_ip_address).
|
|
7
|
+
* Must be called before getFbc(), getFbp(), or getClientIpAddress().
|
|
8
|
+
* @param url - Optional. The full URL to collect clickID from. If not provided, uses window.location.href
|
|
9
|
+
* @param getIpFn - Optional. Function to retrieve client IPv6 address (fallback to IPv4 if unavailable)
|
|
10
|
+
* @returns Promise that resolves to updated cookie object with _fbc, _fbp, and _fbi keys
|
|
11
|
+
*/
|
|
12
|
+
processAndCollectAllParams(
|
|
13
|
+
url?: string,
|
|
14
|
+
getIpFn?: () => Promise<string>
|
|
15
|
+
): Promise<{ _fbc?: string; _fbp?: string; _fbi?: string }>
|
|
16
|
+
/**
|
|
17
|
+
* Returns the fbc value from cookie. Returns empty string if cookie does not exist.
|
|
18
|
+
*/
|
|
19
|
+
getFbc(): string
|
|
20
|
+
/**
|
|
21
|
+
* Returns the fbp value from cookie. Returns empty string if cookie does not exist.
|
|
22
|
+
*/
|
|
23
|
+
getFbp(): string
|
|
24
|
+
/**
|
|
25
|
+
* Returns the client_ip_address value from cookie. Returns empty string if cookie does not exist.
|
|
26
|
+
*/
|
|
27
|
+
getClientIpAddress(): string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const clientParamBuilder: ClientParamBuilder
|
|
31
|
+
export default clientParamBuilder
|
|
32
|
+
}
|