@anker-in/analysis 0.1.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/README.md +240 -0
- package/dist/autoTrack/click.d.ts +2 -0
- package/dist/autoTrack/click.d.ts.map +1 -0
- package/dist/autoTrack/click.js +80 -0
- package/dist/autoTrack/index.d.ts +2 -0
- package/dist/autoTrack/index.d.ts.map +1 -0
- package/dist/autoTrack/index.js +47 -0
- package/dist/autoTrack/pv.d.ts +2 -0
- package/dist/autoTrack/pv.d.ts.map +1 -0
- package/dist/autoTrack/pv.js +57 -0
- package/dist/autoTrack/trackByTags.d.ts +17 -0
- package/dist/autoTrack/trackByTags.d.ts.map +1 -0
- package/dist/autoTrack/trackByTags.js +141 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/tagsMap.d.ts +9 -0
- package/dist/constants/tagsMap.d.ts.map +1 -0
- package/dist/constants/tagsMap.js +8 -0
- package/dist/core/adapters/gtag.d.ts +37 -0
- package/dist/core/adapters/gtag.d.ts.map +1 -0
- package/dist/core/adapters/gtag.js +55 -0
- package/dist/core/adapters/index.d.ts +6 -0
- package/dist/core/adapters/index.d.ts.map +1 -0
- package/dist/core/adapters/index.js +5 -0
- package/dist/core/adapters/meta.d.ts +20 -0
- package/dist/core/adapters/meta.d.ts.map +1 -0
- package/dist/core/adapters/meta.js +41 -0
- package/dist/core/helpers/function-utils.d.ts +17 -0
- package/dist/core/helpers/function-utils.d.ts.map +1 -0
- package/dist/core/helpers/function-utils.js +43 -0
- package/dist/core/helpers/index.d.ts +8 -0
- package/dist/core/helpers/index.d.ts.map +1 -0
- package/dist/core/helpers/index.js +7 -0
- package/dist/core/helpers/logger.d.ts +20 -0
- package/dist/core/helpers/logger.d.ts.map +1 -0
- package/dist/core/helpers/logger.js +32 -0
- package/dist/core/helpers/platform-detector.d.ts +14 -0
- package/dist/core/helpers/platform-detector.d.ts.map +1 -0
- package/dist/core/helpers/platform-detector.js +28 -0
- package/dist/core/helpers/script-loader.d.ts +39 -0
- package/dist/core/helpers/script-loader.d.ts.map +1 -0
- package/dist/core/helpers/script-loader.js +107 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/track/gtagTrack.d.ts +2 -0
- package/dist/core/track/gtagTrack.d.ts.map +1 -0
- package/dist/core/track/gtagTrack.js +12 -0
- package/dist/core/track/index.d.ts +4 -0
- package/dist/core/track/index.d.ts.map +1 -0
- package/dist/core/track/index.js +3 -0
- package/dist/core/track/metaTrack.d.ts +2 -0
- package/dist/core/track/metaTrack.d.ts.map +1 -0
- package/dist/core/track/metaTrack.js +18 -0
- package/dist/core/track/track.d.ts +6 -0
- package/dist/core/track/track.d.ts.map +1 -0
- package/dist/core/track/track.js +128 -0
- package/dist/core/tracking/dispatcher.d.ts +10 -0
- package/dist/core/tracking/dispatcher.d.ts.map +1 -0
- package/dist/core/tracking/dispatcher.js +67 -0
- package/dist/core/tracking/index.d.ts +6 -0
- package/dist/core/tracking/index.d.ts.map +1 -0
- package/dist/core/tracking/index.js +5 -0
- package/dist/core/tracking/with-tracking.d.ts +33 -0
- package/dist/core/tracking/with-tracking.d.ts.map +1 -0
- package/dist/core/tracking/with-tracking.js +137 -0
- package/dist/core/utils.d.ts +64 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +182 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/pixels/GtagPixel.d.ts +7 -0
- package/dist/pixels/GtagPixel.d.ts.map +1 -0
- package/dist/pixels/GtagPixel.js +73 -0
- package/dist/pixels/MetaPixel.d.ts +7 -0
- package/dist/pixels/MetaPixel.d.ts.map +1 -0
- package/dist/pixels/MetaPixel.js +61 -0
- package/dist/pixels/PixelsManager.d.ts +5 -0
- package/dist/pixels/PixelsManager.d.ts.map +1 -0
- package/dist/pixels/PixelsManager.js +17 -0
- package/dist/pixels/index.d.ts +4 -0
- package/dist/pixels/index.d.ts.map +1 -0
- package/dist/pixels/index.js +3 -0
- package/dist/types/common.d.ts +66 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +1 -0
- package/dist/types/gtag.d.ts +34 -0
- package/dist/types/gtag.d.ts.map +1 -0
- package/dist/types/gtag.js +1 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/meta.d.ts +8 -0
- package/dist/types/meta.d.ts.map +1 -0
- package/dist/types/meta.js +4 -0
- package/dist/types/trackByTags.d.ts +26 -0
- package/dist/types/trackByTags.d.ts.map +1 -0
- package/dist/types/trackByTags.js +4 -0
- package/package.json +79 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isPlatformAvailable, logger } from "../utils";
|
|
2
|
+
import { gtagTrack } from "./gtagTrack";
|
|
3
|
+
import { metaTrack } from "./metaTrack";
|
|
4
|
+
function track(config) {
|
|
5
|
+
const { platform, ...params } = config;
|
|
6
|
+
if (!isPlatformAvailable(platform)) {
|
|
7
|
+
logger.warn(`Platform ${platform} is not available`);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
switch (platform) {
|
|
12
|
+
case "gtag": {
|
|
13
|
+
const gtagParams = params;
|
|
14
|
+
handleGtagTrack(gtagParams);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
case "meta": {
|
|
18
|
+
const metaParams = params;
|
|
19
|
+
handleMetaTrack(metaParams);
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
logger.warn(`Unsupported platform: ${platform}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
logger.error(`Failed to track on platform ${platform}:`, error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 处理 Gtag 埋点
|
|
32
|
+
*/
|
|
33
|
+
function handleGtagTrack(params) {
|
|
34
|
+
const { eventName, measurementId, nonInteraction, customParams } = params;
|
|
35
|
+
// 构建 gtag 事件参数对象
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
const eventParams = {
|
|
38
|
+
...customParams,
|
|
39
|
+
};
|
|
40
|
+
// 处理转化类事件
|
|
41
|
+
if ("send_to" in params) {
|
|
42
|
+
eventParams.send_to = params.send_to;
|
|
43
|
+
if (params.value !== undefined) {
|
|
44
|
+
eventParams.value = params.value;
|
|
45
|
+
}
|
|
46
|
+
if (params.currency) {
|
|
47
|
+
eventParams.currency = params.currency;
|
|
48
|
+
}
|
|
49
|
+
if (params.transactionId) {
|
|
50
|
+
eventParams.transaction_id = params.transactionId;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// 处理电商类事件
|
|
54
|
+
if ("items" in params) {
|
|
55
|
+
// 转换 items 格式为 gtag 标准格式
|
|
56
|
+
eventParams.items = params.items.map((item) => ({
|
|
57
|
+
item_id: item.item_id,
|
|
58
|
+
item_name: item.item_name,
|
|
59
|
+
price: item.price,
|
|
60
|
+
quantity: item.quantity,
|
|
61
|
+
...(item.item_brand && { item_brand: item.item_brand }),
|
|
62
|
+
...(item.item_category && { item_category: item.item_category }),
|
|
63
|
+
...(item.item_variant && { item_variant: item.item_variant }),
|
|
64
|
+
...(item.currency && { currency: item.currency }),
|
|
65
|
+
// 保留其他自定义字段
|
|
66
|
+
...Object.fromEntries(Object.entries(item).filter(([key]) => ![
|
|
67
|
+
"item_id",
|
|
68
|
+
"item_name",
|
|
69
|
+
"price",
|
|
70
|
+
"quantity",
|
|
71
|
+
"item_brand",
|
|
72
|
+
"item_category",
|
|
73
|
+
"item_variant",
|
|
74
|
+
"currency",
|
|
75
|
+
].includes(key))),
|
|
76
|
+
}));
|
|
77
|
+
if (params.value !== undefined) {
|
|
78
|
+
eventParams.value = params.value;
|
|
79
|
+
}
|
|
80
|
+
if (params.currency) {
|
|
81
|
+
eventParams.currency = params.currency;
|
|
82
|
+
}
|
|
83
|
+
if (params.transactionId) {
|
|
84
|
+
eventParams.transaction_id = params.transactionId;
|
|
85
|
+
}
|
|
86
|
+
if (params.tax !== undefined) {
|
|
87
|
+
eventParams.tax = params.tax;
|
|
88
|
+
}
|
|
89
|
+
if (params.shipping !== undefined) {
|
|
90
|
+
eventParams.shipping = params.shipping;
|
|
91
|
+
}
|
|
92
|
+
if (params.coupon) {
|
|
93
|
+
eventParams.coupon = params.coupon;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 添加非交互事件标记
|
|
97
|
+
if (nonInteraction) {
|
|
98
|
+
eventParams.non_interaction = true;
|
|
99
|
+
}
|
|
100
|
+
// 构建 dataLayer 格式: ['event', eventName, params]
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
102
|
+
const dataLayerArgs = [
|
|
103
|
+
"event",
|
|
104
|
+
eventName,
|
|
105
|
+
eventParams,
|
|
106
|
+
];
|
|
107
|
+
// 如果有 measurementId,先发送 config
|
|
108
|
+
if (measurementId) {
|
|
109
|
+
gtagTrack(["config", measurementId, {}]);
|
|
110
|
+
}
|
|
111
|
+
// 发送事件
|
|
112
|
+
gtagTrack(dataLayerArgs);
|
|
113
|
+
logger.log(`Gtag event tracked: ${eventName}`, eventParams);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 处理 Meta Pixel 埋点
|
|
117
|
+
*/
|
|
118
|
+
function handleMetaTrack(params) {
|
|
119
|
+
const { event, data } = params;
|
|
120
|
+
if (!event) {
|
|
121
|
+
logger.warn("Meta Pixel event name is required");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
metaTrack(event, data);
|
|
125
|
+
logger.log(`Meta Pixel event tracked: ${event}`, data);
|
|
126
|
+
}
|
|
127
|
+
export default track;
|
|
128
|
+
export { track };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点调度器模块
|
|
3
|
+
* 负责根据平台类型分发事件到对应的适配器
|
|
4
|
+
*/
|
|
5
|
+
import type { TrackConfig } from "../../types";
|
|
6
|
+
declare function track(config: TrackConfig<"gtag">): void;
|
|
7
|
+
declare function track(config: TrackConfig<"meta">): void;
|
|
8
|
+
export default track;
|
|
9
|
+
export { track };
|
|
10
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../../src/core/tracking/dispatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,aAAa,CAAC;AAKrB,iBAAS,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AAClD,iBAAS,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AA6ElD,eAAe,KAAK,CAAC;AACrB,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点调度器模块
|
|
3
|
+
* 负责根据平台类型分发事件到对应的适配器
|
|
4
|
+
*/
|
|
5
|
+
import { isPlatformAvailable, logger } from "../helpers";
|
|
6
|
+
import { gtagEvent, gtagConfig } from "../adapters/gtag";
|
|
7
|
+
import { metaTrack } from "../adapters/meta";
|
|
8
|
+
function track(config) {
|
|
9
|
+
const { platform, ...params } = config;
|
|
10
|
+
if (!isPlatformAvailable(platform)) {
|
|
11
|
+
logger.warn(`Platform ${platform} is not available`);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
switch (platform) {
|
|
16
|
+
case "gtag": {
|
|
17
|
+
const gtagParams = params;
|
|
18
|
+
handleGtagTrack(gtagParams);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
case "meta": {
|
|
22
|
+
const metaParams = params;
|
|
23
|
+
handleMetaTrack(metaParams);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
default:
|
|
27
|
+
logger.warn(`Unsupported platform: ${platform}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
logger.error(`Failed to track on platform ${platform}:`, error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 处理 Gtag 埋点(转化事件)
|
|
36
|
+
*/
|
|
37
|
+
function handleGtagTrack(params) {
|
|
38
|
+
const { eventName, measurementId, ...restParams } = params;
|
|
39
|
+
// 如果有 measurementId,先发送 config
|
|
40
|
+
if (measurementId) {
|
|
41
|
+
gtagConfig(measurementId, {});
|
|
42
|
+
}
|
|
43
|
+
// 构建事件参数
|
|
44
|
+
const eventParams = { ...restParams };
|
|
45
|
+
// 处理 transactionId -> transaction_id 转换
|
|
46
|
+
if (eventParams.transactionId && !eventParams.transaction_id) {
|
|
47
|
+
eventParams.transaction_id = eventParams.transactionId;
|
|
48
|
+
delete eventParams.transactionId;
|
|
49
|
+
}
|
|
50
|
+
// 发送转化事件
|
|
51
|
+
gtagEvent(eventName, eventParams);
|
|
52
|
+
logger.log(`Gtag conversion tracked: ${eventName}`, eventParams);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 处理 Meta Pixel 埋点
|
|
56
|
+
*/
|
|
57
|
+
function handleMetaTrack(params) {
|
|
58
|
+
const { event, data } = params;
|
|
59
|
+
if (!event) {
|
|
60
|
+
logger.warn("Meta Pixel event name is required");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
metaTrack(event, data);
|
|
64
|
+
logger.log(`Meta Pixel event tracked: ${event}`, data);
|
|
65
|
+
}
|
|
66
|
+
export default track;
|
|
67
|
+
export { track };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tracking/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点装饰器模块
|
|
3
|
+
* 提供函数包装器和 React Hooks,为业务函数添加埋点能力
|
|
4
|
+
*/
|
|
5
|
+
import type { WithTrackingConfig } from "../../types";
|
|
6
|
+
export declare function withTracking<T extends (...args: any[]) => any>(fn: T, config: WithTrackingConfig): T;
|
|
7
|
+
/**
|
|
8
|
+
* React Hooks 专用
|
|
9
|
+
*
|
|
10
|
+
* 为 React 组件提供埋点 Hook
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* function ProductCard({ product }) {
|
|
15
|
+
* const trackAddToCart = useTracking({
|
|
16
|
+
* trackConfig: {
|
|
17
|
+
* platform: "gtag",
|
|
18
|
+
* eventName: "add_to_cart"
|
|
19
|
+
* }
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const handleClick = () => {
|
|
23
|
+
* trackAddToCart(() => {
|
|
24
|
+
* addToCart(product.id);
|
|
25
|
+
* });
|
|
26
|
+
* };
|
|
27
|
+
*
|
|
28
|
+
* return <button onClick={handleClick}>Add to Cart</button>;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useTracking(config: WithTrackingConfig): <T extends (...args: any[]) => any>(fn: T) => T;
|
|
33
|
+
//# sourceMappingURL=with-tracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tracking.d.ts","sourceRoot":"","sources":["../../../src/core/tracking/with-tracking.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAgCrB,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAC5D,EAAE,EAAE,CAAC,EACL,MAAM,EAAE,kBAAkB,GACzB,CAAC,CA8FH;AAOD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,IAC5C,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,CAAC,OAGjD"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点装饰器模块
|
|
3
|
+
* 提供函数包装器和 React Hooks,为业务函数添加埋点能力
|
|
4
|
+
*/
|
|
5
|
+
import { track } from "./dispatcher";
|
|
6
|
+
import { logger, debounce, throttle } from "../helpers";
|
|
7
|
+
import { trackByTags } from "../../autoTrack/trackByTags";
|
|
8
|
+
/**
|
|
9
|
+
* 执行埋点上报
|
|
10
|
+
*/
|
|
11
|
+
function executeTracking(trackPoint, trackConfig) {
|
|
12
|
+
const configs = Array.isArray(trackConfig)
|
|
13
|
+
? trackConfig
|
|
14
|
+
: [trackConfig ?? {}];
|
|
15
|
+
configs.forEach((config) => {
|
|
16
|
+
try {
|
|
17
|
+
track(config);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
logger.error("withTracking: 埋点执行失败", error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
if (typeof window !== "undefined" &&
|
|
24
|
+
!!trackPoint &&
|
|
25
|
+
window.__FUN_TRACK_TAGS__?.[trackPoint ?? ""]?.length > 0) {
|
|
26
|
+
trackByTags({
|
|
27
|
+
tags: window.__FUN_TRACK_TAGS__?.[trackPoint ?? ""] ?? [],
|
|
28
|
+
data: [{ event: "custom" }],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function withTracking(fn, config) {
|
|
33
|
+
const { trackConfig, timing = "after", condition, trackOnError = false, errorTrackConfig, debounce: debounceTime, throttle: throttleTime, trackPoint, } = config;
|
|
34
|
+
// 核心包装函数
|
|
35
|
+
function wrappedFunction(...args) {
|
|
36
|
+
// 条件检查
|
|
37
|
+
if (condition && !condition(args)) {
|
|
38
|
+
return fn(...args);
|
|
39
|
+
}
|
|
40
|
+
// 生成埋点配置
|
|
41
|
+
const getTrackConfig = (result) => {
|
|
42
|
+
return typeof trackConfig === "function"
|
|
43
|
+
? trackConfig(args, result)
|
|
44
|
+
: trackConfig;
|
|
45
|
+
};
|
|
46
|
+
// Before 时机
|
|
47
|
+
if (timing === "before" || timing === "both") {
|
|
48
|
+
const config = getTrackConfig();
|
|
49
|
+
executeTracking(trackPoint, config);
|
|
50
|
+
}
|
|
51
|
+
// 执行原函数
|
|
52
|
+
try {
|
|
53
|
+
const result = fn(...args);
|
|
54
|
+
// 处理异步函数
|
|
55
|
+
if (result instanceof Promise) {
|
|
56
|
+
return result
|
|
57
|
+
.then((resolvedResult) => {
|
|
58
|
+
if (timing === "after" || timing === "both") {
|
|
59
|
+
const config = getTrackConfig(resolvedResult);
|
|
60
|
+
executeTracking(trackPoint, config);
|
|
61
|
+
}
|
|
62
|
+
return resolvedResult;
|
|
63
|
+
})
|
|
64
|
+
.catch((error) => {
|
|
65
|
+
if (trackOnError && errorTrackConfig) {
|
|
66
|
+
executeTracking(trackPoint, errorTrackConfig(error, args));
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// 同步函数 After 时机
|
|
72
|
+
if (timing === "after" || timing === "both") {
|
|
73
|
+
const config = getTrackConfig(result);
|
|
74
|
+
executeTracking(trackPoint, config);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// 错误时上报
|
|
80
|
+
if (trackOnError && errorTrackConfig) {
|
|
81
|
+
executeTracking(trackPoint, errorTrackConfig(error, args));
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (typeof window !== "undefined" && !!trackPoint) {
|
|
87
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
88
|
+
if (urlParams.has("TRACK_DEV")) {
|
|
89
|
+
return ((...args) => {
|
|
90
|
+
window.open(`http://localhost:3002/tracking?trackPoint=${trackPoint}`, "_blank");
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 应用防抖/节流
|
|
95
|
+
if (debounceTime) {
|
|
96
|
+
return debounce(wrappedFunction, debounceTime);
|
|
97
|
+
}
|
|
98
|
+
if (throttleTime) {
|
|
99
|
+
return throttle(wrappedFunction, throttleTime);
|
|
100
|
+
}
|
|
101
|
+
// __TRACK_POINT_MARKER__(trackPoint);
|
|
102
|
+
return wrappedFunction;
|
|
103
|
+
}
|
|
104
|
+
// 定义标记函数(仅用于 AST 识别)
|
|
105
|
+
function __TRACK_POINT_MARKER__(trackPoint) {
|
|
106
|
+
// 空函数,仅用于 AST 标记
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* React Hooks 专用
|
|
110
|
+
*
|
|
111
|
+
* 为 React 组件提供埋点 Hook
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* function ProductCard({ product }) {
|
|
116
|
+
* const trackAddToCart = useTracking({
|
|
117
|
+
* trackConfig: {
|
|
118
|
+
* platform: "gtag",
|
|
119
|
+
* eventName: "add_to_cart"
|
|
120
|
+
* }
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* const handleClick = () => {
|
|
124
|
+
* trackAddToCart(() => {
|
|
125
|
+
* addToCart(product.id);
|
|
126
|
+
* });
|
|
127
|
+
* };
|
|
128
|
+
*
|
|
129
|
+
* return <button onClick={handleClick}>Add to Cart</button>;
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function useTracking(config) {
|
|
134
|
+
return (fn) => {
|
|
135
|
+
return withTracking(fn, config);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { PlatformType } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* 创建日志工具
|
|
4
|
+
*/
|
|
5
|
+
export declare function createLogger(initialEnabled?: boolean): {
|
|
6
|
+
setEnabled(value: boolean): void;
|
|
7
|
+
log(...args: any[]): void;
|
|
8
|
+
warn(...args: any[]): void;
|
|
9
|
+
error(...args: any[]): void;
|
|
10
|
+
};
|
|
11
|
+
export declare const logger: {
|
|
12
|
+
setEnabled(value: boolean): void;
|
|
13
|
+
log(...args: any[]): void;
|
|
14
|
+
warn(...args: any[]): void;
|
|
15
|
+
error(...args: any[]): void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 加载外部脚本
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadScript(src: string, id?: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* 安全执行函数,捕获错误
|
|
23
|
+
*/
|
|
24
|
+
export declare function safeExecute<T>(fn: () => T, errorMessage?: string): T | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* 防抖函数
|
|
27
|
+
*/
|
|
28
|
+
export declare function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void;
|
|
29
|
+
/**
|
|
30
|
+
* 节流函数
|
|
31
|
+
*/
|
|
32
|
+
export declare function throttle<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void;
|
|
33
|
+
export declare const isPlatformAvailable: (platform: PlatformType) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 更新脚本的 type 属性配置
|
|
36
|
+
*/
|
|
37
|
+
export interface UpdateScriptTypeOptions {
|
|
38
|
+
/** 脚本元素的 ID */
|
|
39
|
+
id: string;
|
|
40
|
+
/** 是否启用脚本 */
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
/** 是否在启用时重新执行脚本内容 */
|
|
43
|
+
executeOnEnable?: boolean;
|
|
44
|
+
/** 错误处理回调 */
|
|
45
|
+
onError?: (error: Error) => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 动态更新脚本的 type 属性
|
|
49
|
+
* 用于根据 cookie consent 状态动态启用/禁用脚本
|
|
50
|
+
*
|
|
51
|
+
* @param options - 配置选项
|
|
52
|
+
* @returns 是否成功更新
|
|
53
|
+
*/
|
|
54
|
+
export declare function updateScriptType(options: UpdateScriptTypeOptions): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 批量更新多个脚本的 type 属性
|
|
57
|
+
*
|
|
58
|
+
* @param scriptIds - 脚本 ID 数组或生成 ID 的函数
|
|
59
|
+
* @param enabled - 是否启用脚本
|
|
60
|
+
* @param executeOnEnable - 是否在启用时重新执行脚本内容
|
|
61
|
+
* @returns 成功更新的脚本数量
|
|
62
|
+
*/
|
|
63
|
+
export declare function updateScriptsType(scriptIds: string[] | ((index: number) => string), enabled: boolean, executeOnEnable?: boolean): number;
|
|
64
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;GAEG;AACH,wBAAgB,YAAY,CAAC,cAAc,UAAQ;sBAI7B,OAAO;iBAIZ,GAAG,EAAE;kBAMJ,GAAG,EAAE;mBAMJ,GAAG,EAAE;EAMvB;AAGD,eAAO,MAAM,MAAM;sBAzBG,OAAO;iBAIZ,GAAG,EAAE;kBAMJ,GAAG,EAAE;mBAMJ,GAAG,EAAE;CASY,CAAC;AAErC;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BlE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,CAAC,EACX,YAAY,CAAC,EAAE,MAAM,GACpB,CAAC,GAAG,SAAS,CAOf;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxD,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAQlC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxD,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CASlC;AAED,eAAO,MAAM,mBAAmB,GAAI,UAAU,YAAY,KAAG,OAgB5D,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,eAAe;IACf,EAAE,EAAE,MAAM,CAAC;IACX,aAAa;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CA2C1E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,EACjD,OAAO,EAAE,OAAO,EAChB,eAAe,UAAO,GACrB,MAAM,CAyBR"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 创建日志工具
|
|
3
|
+
*/
|
|
4
|
+
export function createLogger(initialEnabled = false) {
|
|
5
|
+
let enabled = initialEnabled;
|
|
6
|
+
return {
|
|
7
|
+
setEnabled(value) {
|
|
8
|
+
enabled = value;
|
|
9
|
+
},
|
|
10
|
+
log(...args) {
|
|
11
|
+
if (enabled) {
|
|
12
|
+
console.log("[Analysis SDK]", ...args);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
warn(...args) {
|
|
16
|
+
if (enabled) {
|
|
17
|
+
console.warn("[Analysis SDK]", ...args);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
error(...args) {
|
|
21
|
+
if (enabled) {
|
|
22
|
+
console.error("[Analysis SDK]", ...args);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// 全局 logger 实例
|
|
28
|
+
export const logger = createLogger();
|
|
29
|
+
/**
|
|
30
|
+
* 加载外部脚本
|
|
31
|
+
*/
|
|
32
|
+
export function loadScript(src, id) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
// 检查是否已加载
|
|
35
|
+
if (id && document.getElementById(id)) {
|
|
36
|
+
logger.log(`Script ${id} already loaded`);
|
|
37
|
+
resolve();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const script = document.createElement("script");
|
|
41
|
+
script.src = src;
|
|
42
|
+
script.async = true;
|
|
43
|
+
if (id) {
|
|
44
|
+
script.id = id;
|
|
45
|
+
}
|
|
46
|
+
script.onload = () => {
|
|
47
|
+
logger.log(`Script loaded: ${src}`);
|
|
48
|
+
resolve();
|
|
49
|
+
};
|
|
50
|
+
script.onerror = () => {
|
|
51
|
+
logger.error(`Failed to load script: ${src}`);
|
|
52
|
+
reject(new Error(`Failed to load script: ${src}`));
|
|
53
|
+
};
|
|
54
|
+
document.head.appendChild(script);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 安全执行函数,捕获错误
|
|
59
|
+
*/
|
|
60
|
+
export function safeExecute(fn, errorMessage) {
|
|
61
|
+
try {
|
|
62
|
+
return fn();
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
logger.error(errorMessage || "Error executing function:", error);
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 防抖函数
|
|
71
|
+
*/
|
|
72
|
+
export function debounce(fn, delay) {
|
|
73
|
+
let timer = null;
|
|
74
|
+
return function (...args) {
|
|
75
|
+
if (timer)
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
timer = setTimeout(() => {
|
|
78
|
+
fn.apply(this, args);
|
|
79
|
+
}, delay);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 节流函数
|
|
84
|
+
*/
|
|
85
|
+
export function throttle(fn, delay) {
|
|
86
|
+
let lastTime = 0;
|
|
87
|
+
return function (...args) {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
if (now - lastTime >= delay) {
|
|
90
|
+
lastTime = now;
|
|
91
|
+
fn.apply(this, args);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export const isPlatformAvailable = (platform) => {
|
|
96
|
+
if (typeof window === "undefined") {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
switch (platform) {
|
|
100
|
+
case "gtag":
|
|
101
|
+
return (typeof window.gtag !== "undefined" ||
|
|
102
|
+
typeof window.dataLayer !== "undefined");
|
|
103
|
+
case "meta":
|
|
104
|
+
return typeof window.fbq !== "undefined";
|
|
105
|
+
default:
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* 动态更新脚本的 type 属性
|
|
111
|
+
* 用于根据 cookie consent 状态动态启用/禁用脚本
|
|
112
|
+
*
|
|
113
|
+
* @param options - 配置选项
|
|
114
|
+
* @returns 是否成功更新
|
|
115
|
+
*/
|
|
116
|
+
export function updateScriptType(options) {
|
|
117
|
+
const { id, enabled, executeOnEnable = true, onError } = options;
|
|
118
|
+
if (typeof window === "undefined") {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const scriptElement = document.getElementById(id);
|
|
122
|
+
if (!scriptElement) {
|
|
123
|
+
logger.warn(`Script element with id "${id}" not found`);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const newType = enabled ? "text/javascript" : "text/plain";
|
|
127
|
+
const currentType = scriptElement.getAttribute("type");
|
|
128
|
+
// 如果从 text/plain 变为 text/javascript,需要重新执行脚本
|
|
129
|
+
if (executeOnEnable &&
|
|
130
|
+
currentType === "text/plain" &&
|
|
131
|
+
newType === "text/javascript") {
|
|
132
|
+
scriptElement.setAttribute("type", newType);
|
|
133
|
+
// 重新执行脚本内容
|
|
134
|
+
const scriptContent = scriptElement.innerHTML;
|
|
135
|
+
if (scriptContent && typeof window.eval === "function") {
|
|
136
|
+
try {
|
|
137
|
+
window.eval(scriptContent);
|
|
138
|
+
logger.log(`Script "${id}" executed successfully`);
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
142
|
+
logger.error(`Script "${id}" execution error:`, error);
|
|
143
|
+
if (onError) {
|
|
144
|
+
onError(error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
scriptElement.setAttribute("type", newType);
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 批量更新多个脚本的 type 属性
|
|
156
|
+
*
|
|
157
|
+
* @param scriptIds - 脚本 ID 数组或生成 ID 的函数
|
|
158
|
+
* @param enabled - 是否启用脚本
|
|
159
|
+
* @param executeOnEnable - 是否在启用时重新执行脚本内容
|
|
160
|
+
* @returns 成功更新的脚本数量
|
|
161
|
+
*/
|
|
162
|
+
export function updateScriptsType(scriptIds, enabled, executeOnEnable = true) {
|
|
163
|
+
if (typeof window === "undefined") {
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
let successCount = 0;
|
|
167
|
+
const ids = Array.isArray(scriptIds)
|
|
168
|
+
? scriptIds
|
|
169
|
+
: Array.from({ length: 100 }, (_, i) => scriptIds(i)).filter((id) => document.getElementById(id));
|
|
170
|
+
ids.forEach((id) => {
|
|
171
|
+
const success = updateScriptType({
|
|
172
|
+
id,
|
|
173
|
+
enabled,
|
|
174
|
+
executeOnEnable,
|
|
175
|
+
});
|
|
176
|
+
if (success) {
|
|
177
|
+
successCount++;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
logger.log(`Updated ${successCount}/${ids.length} scripts`);
|
|
181
|
+
return successCount;
|
|
182
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis SDK - 埋点 SDK 主入口
|
|
3
|
+
*
|
|
4
|
+
* 提供统一的埋点接口,支持多平台埋点上报
|
|
5
|
+
*/
|
|
6
|
+
export { track } from "./core/tracking";
|
|
7
|
+
export { gtagTrack } from "./core/adapters";
|
|
8
|
+
export { metaTrack } from "./core/adapters";
|
|
9
|
+
export { withTracking, useTracking } from "./core/tracking";
|
|
10
|
+
export { trackByTags } from "./autoTrack/trackByTags";
|
|
11
|
+
export { logger, isPlatformAvailable, updateScriptType, updateScriptsType, } from "./core/helpers";
|
|
12
|
+
export { GtagPixel, MetaPixel, PixelsManager } from "./pixels";
|
|
13
|
+
export { TrackTagsVersionMap } from "./constants";
|
|
14
|
+
export type { PlatformType, TrackEventType, BasePlatformConfig, PixelsManagerConfig, GtagConfig, MetaPixelConfig, TikTokPixelConfig, ScarabConfig, AnalysisConfig, TrackParams, Tracker, AutoTrackConfig, Currency, TrackConfig, GtagEventName, GtagTrackParams, GtagConfigParams, MetaTrackParams, TrackByTagsData, TrackByTagsParams, ParsedTag, } from "./types";
|
|
15
|
+
export type { UpdateScriptTypeOptions } from "./core/helpers";
|
|
16
|
+
import { track } from "./core/tracking";
|
|
17
|
+
import { trackByTags } from "./autoTrack/trackByTags";
|
|
18
|
+
import { updateScriptType, updateScriptsType } from "./core/helpers";
|
|
19
|
+
import { withTracking, useTracking } from "./core/tracking";
|
|
20
|
+
declare const _default: {
|
|
21
|
+
track: typeof track;
|
|
22
|
+
trackByTags: typeof trackByTags;
|
|
23
|
+
withTracking: typeof withTracking;
|
|
24
|
+
useTracking: typeof useTracking;
|
|
25
|
+
logger: {
|
|
26
|
+
setEnabled(value: boolean): void;
|
|
27
|
+
log(...args: any[]): void;
|
|
28
|
+
warn(...args: any[]): void;
|
|
29
|
+
error(...args: any[]): void;
|
|
30
|
+
};
|
|
31
|
+
isPlatformAvailable: (platform: import("./types").PlatformType) => boolean;
|
|
32
|
+
updateScriptType: typeof updateScriptType;
|
|
33
|
+
updateScriptsType: typeof updateScriptsType;
|
|
34
|
+
};
|
|
35
|
+
export default _default;
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|