@wapitee/typhoonx-hydrogen 0.5.0 → 0.7.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 +4 -0
- package/dist/TyphoonX.d.ts.map +1 -1
- package/dist/TyphoonX.js +43 -5
- package/dist/client-id.d.ts +2 -0
- package/dist/client-id.d.ts.map +1 -1
- package/dist/client-id.js +4 -0
- package/dist/meta-pixel.d.ts +7 -0
- package/dist/meta-pixel.d.ts.map +1 -0
- package/dist/meta-pixel.js +23 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,10 @@ const {nonce, header, NonceProvider} = createContentSecurityPolicy({
|
|
|
48
48
|
| `shopId` | `string` | yes | Shopify store ID |
|
|
49
49
|
| `cookieDomain` | `string` | no | Cookie `Domain` for a first-party client id. Defaults to the current hostname's apex domain (e.g. `.example.com`) |
|
|
50
50
|
|
|
51
|
+
### Meta Pixel
|
|
52
|
+
|
|
53
|
+
If the storefront runs Meta Pixel, every event also carries its `_fbp` cookie as `fbp` and its `_fbc` cookie as `fbc`. When `_fbc` is not set yet but the page URL has `fbclid`, `fbc` is built as `fb.1.<timestamp>.<fbclid>`. Missing values are omitted.
|
|
54
|
+
|
|
51
55
|
## License
|
|
52
56
|
|
|
53
57
|
[MIT](./LICENSE) © Wapitee Interactive
|
package/dist/TyphoonX.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TyphoonX.d.ts","sourceRoot":"","sources":["../src/TyphoonX.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TyphoonX.d.ts","sourceRoot":"","sources":["../src/TyphoonX.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqCD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,aAAa,sCAuBpD"}
|
package/dist/TyphoonX.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { flattenConnection, parseGid, useAnalytics } from '@shopify/hydrogen';
|
|
3
3
|
import { useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { getOrCreateClientId } from './client-id.js';
|
|
4
|
+
import { getOrCreateClientId, hasClientId } from './client-id.js';
|
|
5
|
+
import { getMetaPixelIds } from './meta-pixel.js';
|
|
5
6
|
const COLLECT_ENDPOINT = 'https://spell.typhoonx.io/api/v1/receive';
|
|
6
7
|
export default function TyphoonX(props) {
|
|
8
|
+
const { subscribe } = useAnalytics();
|
|
9
|
+
const isInsideProvider = subscribe.length > 0;
|
|
7
10
|
const [isClient, setIsClient] = useState(false);
|
|
8
11
|
useEffect(() => {
|
|
9
12
|
setIsClient(true);
|
|
10
13
|
}, []);
|
|
11
|
-
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!isInsideProvider) {
|
|
16
|
+
console.error('[TyphoonX] <TyphoonX> must be rendered inside <Analytics.Provider>.');
|
|
17
|
+
}
|
|
18
|
+
}, [isInsideProvider]);
|
|
19
|
+
if (!isClient || !isInsideProvider) {
|
|
12
20
|
return null;
|
|
13
21
|
}
|
|
14
22
|
return _jsx(TyphoonXClient, { ...props });
|
|
@@ -18,6 +26,17 @@ function TyphoonXClient({ cookieDomain, merchantId, shopId }) {
|
|
|
18
26
|
const { ready } = register('TyphoonX');
|
|
19
27
|
const currentUrlRef = useRef(null);
|
|
20
28
|
const previousUrlRef = useRef(null);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
try {
|
|
31
|
+
if (!hasClientId()) {
|
|
32
|
+
window.localStorage.setItem('__typhoon_first_visit_time', new Date().toISOString());
|
|
33
|
+
window.localStorage.setItem('__typhoon_first_visit_url', window.location.href);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Do nothing
|
|
38
|
+
}
|
|
39
|
+
}, [hasClientId()]);
|
|
21
40
|
useEffect(() => {
|
|
22
41
|
const clientId = getOrCreateClientId(cookieDomain);
|
|
23
42
|
const referrerFor = (url) => {
|
|
@@ -41,6 +60,7 @@ function TyphoonXClient({ cookieDomain, merchantId, shopId }) {
|
|
|
41
60
|
timestamp: new Date().toISOString(),
|
|
42
61
|
user_agent: window.navigator.userAgent,
|
|
43
62
|
...(currency === undefined ? {} : { currency }),
|
|
63
|
+
...getMetaPixelIds(url),
|
|
44
64
|
});
|
|
45
65
|
subscribe('cart_viewed', (data) => {
|
|
46
66
|
const { cart } = data;
|
|
@@ -72,10 +92,28 @@ function TyphoonXClient({ cookieDomain, merchantId, shopId }) {
|
|
|
72
92
|
});
|
|
73
93
|
});
|
|
74
94
|
subscribe('page_viewed', (data) => {
|
|
95
|
+
const payload = shared(data.url);
|
|
75
96
|
send({
|
|
76
|
-
...
|
|
97
|
+
...payload,
|
|
77
98
|
event: 'page_view',
|
|
78
99
|
});
|
|
100
|
+
try {
|
|
101
|
+
const visitTime = window.localStorage.getItem('__typhoon_first_visit_time');
|
|
102
|
+
const visitUrl = window.localStorage.getItem('__typhoon_first_visit_url');
|
|
103
|
+
if (!visitTime || !visitUrl)
|
|
104
|
+
return;
|
|
105
|
+
send({
|
|
106
|
+
...payload,
|
|
107
|
+
request_page_url: visitUrl,
|
|
108
|
+
timestamp: visitTime,
|
|
109
|
+
event: 'first_visit',
|
|
110
|
+
});
|
|
111
|
+
window.localStorage.removeItem('__typhoon_first_visit_time');
|
|
112
|
+
window.localStorage.removeItem('__typhoon_first_visit_url');
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Do nothing
|
|
116
|
+
}
|
|
79
117
|
});
|
|
80
118
|
subscribe('product_added_to_cart', (data) => {
|
|
81
119
|
const { currentLine } = data;
|
|
@@ -113,8 +151,8 @@ function TyphoonXClient({ cookieDomain, merchantId, shopId }) {
|
|
|
113
151
|
quantity,
|
|
114
152
|
},
|
|
115
153
|
],
|
|
116
|
-
value: String(Number(prevLine.cost.totalAmount.amount)
|
|
117
|
-
|
|
154
|
+
value: String(Number(prevLine.cost.totalAmount.amount) -
|
|
155
|
+
Number(currentLine?.cost.totalAmount.amount ?? 0)),
|
|
118
156
|
});
|
|
119
157
|
});
|
|
120
158
|
subscribe('product_viewed', (data) => {
|
package/dist/client-id.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Whether `__typhoon_client_id` is already set. */
|
|
2
|
+
export declare function hasClientId(): boolean;
|
|
1
3
|
/** Existing `__typhoon_client_id`, or a new UUID cookie on the apex domain. */
|
|
2
4
|
export declare function getOrCreateClientId(cookieDomain?: string): string;
|
|
3
5
|
//# sourceMappingURL=client-id.d.ts.map
|
package/dist/client-id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-id.d.ts","sourceRoot":"","sources":["../src/client-id.ts"],"names":[],"mappings":"AAwBA,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjE"}
|
|
1
|
+
{"version":3,"file":"client-id.d.ts","sourceRoot":"","sources":["../src/client-id.ts"],"names":[],"mappings":"AAwBA,oDAAoD;AACpD,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjE"}
|
package/dist/client-id.js
CHANGED
|
@@ -8,6 +8,10 @@ const cookies = new Cookies(null, {
|
|
|
8
8
|
sameSite: 'lax',
|
|
9
9
|
maxAge: MAX_AGE,
|
|
10
10
|
});
|
|
11
|
+
/** Whether `__typhoon_client_id` is already set. */
|
|
12
|
+
export function hasClientId() {
|
|
13
|
+
return cookies.get(COOKIE, { doNotParse: true }) !== undefined;
|
|
14
|
+
}
|
|
11
15
|
/** Existing `__typhoon_client_id`, or a new UUID cookie on the apex domain. */
|
|
12
16
|
export function getOrCreateClientId(cookieDomain) {
|
|
13
17
|
const existing = cookies.get(COOKIE, { doNotParse: true });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface MetaPixelIds {
|
|
2
|
+
fbc?: string;
|
|
3
|
+
fbp?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Meta Pixel `_fbp` / `_fbc` cookies, with `_fbc` falling back to `url`'s `fbclid`. */
|
|
6
|
+
export declare function getMetaPixelIds(url: string): MetaPixelIds;
|
|
7
|
+
//# sourceMappingURL=meta-pixel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta-pixel.d.ts","sourceRoot":"","sources":["../src/meta-pixel.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAQzD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import CookieLib from 'universal-cookie';
|
|
2
|
+
// Runtime default export is the class.
|
|
3
|
+
const cookies = new CookieLib();
|
|
4
|
+
/** Meta Pixel `_fbp` / `_fbc` cookies, with `_fbc` falling back to `url`'s `fbclid`. */
|
|
5
|
+
export function getMetaPixelIds(url) {
|
|
6
|
+
const fbp = cookies.get('_fbp', { doNotParse: true });
|
|
7
|
+
const fbc = cookies.get('_fbc', { doNotParse: true }) ?? fbcFromUrl(url);
|
|
8
|
+
return {
|
|
9
|
+
...(fbc === undefined ? {} : { fbc }),
|
|
10
|
+
...(fbp === undefined ? {} : { fbp }),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function fbcFromUrl(url) {
|
|
14
|
+
let fbclid;
|
|
15
|
+
try {
|
|
16
|
+
fbclid = new URL(url).searchParams.get('fbclid');
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
// Meta specifies subdomain index 1 for an `_fbc` built outside the Pixel.
|
|
22
|
+
return fbclid ? `fb.1.${String(Date.now())}.${fbclid}` : undefined;
|
|
23
|
+
}
|