@engagex/react 0.1.0 → 0.1.1
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 +6 -6
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,10 +27,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
27
27
|
return (
|
|
28
28
|
<html>
|
|
29
29
|
<body>
|
|
30
|
-
<EngageProvider
|
|
31
|
-
publicKey="pk_live_xxx"
|
|
32
|
-
host="https://engage.data360.asia"
|
|
33
|
-
/>
|
|
30
|
+
<EngageProvider publicKey="pk_live_xxx" />
|
|
34
31
|
{children}
|
|
35
32
|
</body>
|
|
36
33
|
</html>
|
|
@@ -38,7 +35,10 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
38
35
|
}
|
|
39
36
|
```
|
|
40
37
|
|
|
41
|
-
`
|
|
38
|
+
You only pass `publicKey` — the tracking host is baked in. `page.viewed` fires
|
|
39
|
+
automatically on every route change, no `useEffect` needed.
|
|
40
|
+
|
|
41
|
+
> Self-hosting or local dev? Override the host: `<EngageProvider publicKey="pk_..." host="http://localhost:8010" />`.
|
|
42
42
|
|
|
43
43
|
## Send events / identify (any client component)
|
|
44
44
|
|
|
@@ -78,7 +78,7 @@ works with React Router too — no extra wiring.
|
|
|
78
78
|
| Prop | Type | Default | |
|
|
79
79
|
| --- | --- | --- | --- |
|
|
80
80
|
| `publicKey` | `string` | — | Source public key (`pk_...`). |
|
|
81
|
-
| `host` | `string` |
|
|
81
|
+
| `host` | `string` | _(baked-in)_ | Tracking host serving `engage.v1.js`. Override only for self-hosting / local dev. |
|
|
82
82
|
| `autoPageview` | `boolean` | `true` | Auto-fire `page.viewed` on route change. |
|
|
83
83
|
| `branchId` | `number \| string` | — | Attached to every event. |
|
|
84
84
|
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
30
30
|
// src/provider.tsx
|
|
31
31
|
var import_react = require("react");
|
|
32
32
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
33
|
+
var DEFAULT_ENGAGE_HOST = "https://engage.data360.asia";
|
|
33
34
|
var STUB_METHODS = ["init", "track", "identify", "flush"];
|
|
34
35
|
var NAV_EVENT = "engagex:navigation";
|
|
35
36
|
function EngageProvider({
|
|
@@ -40,9 +41,9 @@ function EngageProvider({
|
|
|
40
41
|
children
|
|
41
42
|
}) {
|
|
42
43
|
(0, import_react.useEffect)(() => {
|
|
43
|
-
if (typeof window === "undefined" || !publicKey
|
|
44
|
+
if (typeof window === "undefined" || !publicKey) return;
|
|
44
45
|
const w = window;
|
|
45
|
-
const base = host.replace(/\/+$/, "");
|
|
46
|
+
const base = (host || DEFAULT_ENGAGE_HOST).replace(/\/+$/, "");
|
|
46
47
|
if (!w.__engagex_loaded) {
|
|
47
48
|
w.__engagex_loaded = true;
|
|
48
49
|
const name = "engage";
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/engage.ts"],"sourcesContent":["export { EngageProvider } from './provider'\nexport type { EngageProviderProps } from './provider'\n\nexport { sendEngageEvent, engageIdentify } from './engage'\nexport type { EngageIdentity, EngageConsent, EngageGlobal } from './engage'\n","import { useEffect } from 'react'\n\nexport interface EngageProviderProps {\n /** Your source public key, e.g. \"pk_live_...\". */\n publicKey: string\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/engage.ts"],"sourcesContent":["export { EngageProvider } from './provider'\nexport type { EngageProviderProps } from './provider'\n\nexport { sendEngageEvent, engageIdentify } from './engage'\nexport type { EngageIdentity, EngageConsent, EngageGlobal } from './engage'\n","import { useEffect } from 'react'\n\n/**\n * Default EngageX tracking host that serves engage.v1.js and receives events.\n * Baked in so integrators only pass `publicKey` — they don't need to know the\n * tracking infrastructure. Override `host` only for self-hosting / local dev.\n */\nexport const DEFAULT_ENGAGE_HOST = 'https://engage.data360.asia'\n\nexport interface EngageProviderProps {\n /** Your source public key, e.g. \"pk_live_...\". */\n publicKey: string\n /**\n * Tracking host origin that serves engage.v1.js. Optional — defaults to\n * {@link DEFAULT_ENGAGE_HOST}. Override only for self-hosting / local dev.\n */\n host?: string\n /**\n * Auto-fire `page.viewed` on SPA route changes (default true). Works in Next\n * App/Pages Router and React Router without importing them — it hooks the\n * History API. Disable to fire page views yourself.\n */\n autoPageview?: boolean\n /** Optional branch id attached to every event. */\n branchId?: number | string\n children?: React.ReactNode\n}\n\nconst STUB_METHODS = ['init', 'track', 'identify', 'flush'] as const\nconst NAV_EVENT = 'engagex:navigation'\n\n/**\n * Mount once near the root of your app.\n *\n * // app/layout.tsx (Next.js) — it's a client component\n * <EngageProvider publicKey=\"pk_...\" /> // host defaults to your tracking domain\n *\n * It injects engage.v1.js from `host` (auto-updates, keeps endpoint auto-detect\n * and shared _cdp_tid identity) and tracks page views across client navigation.\n */\nexport function EngageProvider({\n publicKey,\n host,\n autoPageview = true,\n branchId,\n children,\n}: EngageProviderProps) {\n useEffect(() => {\n if (typeof window === 'undefined' || !publicKey) return\n const w = window as unknown as Record<string, any>\n const base = (host || DEFAULT_ENGAGE_HOST).replace(/\\/+$/, '')\n\n // 1) Install the async-loader stub + inject engage.v1.js exactly once.\n if (!w.__engagex_loaded) {\n w.__engagex_loaded = true\n const name = 'engage'\n if (!w[name]) {\n w[name] = { _q: [] as unknown[] }\n STUB_METHODS.forEach((m) => {\n w[name][m] = function () {\n // eslint-disable-next-line prefer-rest-params\n w[name]._q.push([m, arguments])\n }\n })\n }\n const el = document.createElement('script')\n el.async = true\n el.src = base + '/engage.v1.js'\n const first = document.getElementsByTagName('script')[0]\n if (first && first.parentNode) first.parentNode.insertBefore(el, first)\n else document.head.appendChild(el)\n // autoPageview:false at SDK level — page views are handled here so SPA\n // route changes are captured (SDK only auto-fires once on init).\n w[name].init({ key: publicKey, endpoint: base, autoPageview: false, branch_id: branchId })\n }\n\n if (!autoPageview) return\n\n const fire = () => {\n try {\n w.engage?.track('page.viewed', { url: window.location.href })\n } catch {\n /* no-op */\n }\n }\n fire() // initial view\n\n // 2) Framework-agnostic SPA route tracking: patch History API once, then\n // listen for our synthetic nav event + popstate.\n const origPush = window.history.pushState\n const origReplace = window.history.replaceState\n let patchedHere = false\n if (!w.__engagex_history_patched) {\n w.__engagex_history_patched = true\n patchedHere = true\n window.history.pushState = function (this: History, ...args: unknown[]) {\n const r = origPush.apply(this, args as [unknown, string, (string | URL | null)?])\n window.dispatchEvent(new Event(NAV_EVENT))\n return r\n }\n window.history.replaceState = function (this: History, ...args: unknown[]) {\n const r = origReplace.apply(this, args as [unknown, string, (string | URL | null)?])\n window.dispatchEvent(new Event(NAV_EVENT))\n return r\n }\n }\n window.addEventListener(NAV_EVENT, fire)\n window.addEventListener('popstate', fire)\n\n return () => {\n window.removeEventListener(NAV_EVENT, fire)\n window.removeEventListener('popstate', fire)\n if (patchedHere) {\n window.history.pushState = origPush\n window.history.replaceState = origReplace\n w.__engagex_history_patched = false\n }\n }\n }, [publicKey, host, autoPageview, branchId])\n\n return <>{children}</>\n}\n","/**\n * Typed helpers to call the EngageX browser SDK (window.engage) safely from\n * React / Next.js. All calls are SSR-guarded — a no-op on the server.\n *\n * The actual tracking logic lives in engage.v1.js served from your tracking\n * host; <EngageProvider> injects it. These helpers just forward to it.\n */\n\nexport interface EngageIdentity {\n /** At least one resolving key is required: phone / email / zalo_id. */\n phone?: string\n email?: string\n zalo_id?: string\n /** Optional traits — applied fill-missing to the customer profile. */\n name?: string\n /** male | female | other (normalized server-side from \"Nam\"/\"Nữ\"...). */\n gender?: string\n /** e.g. 1990-12-31 or 31/12/1990. */\n birthday?: string\n address?: string\n [key: string]: unknown\n}\n\nexport interface EngageConsent {\n consent: boolean\n purpose?: string\n policy_version?: string\n}\n\nexport interface EngageGlobal {\n init: (opts: Record<string, unknown>) => void\n track: (event: string, properties?: Record<string, unknown>) => void\n identify: (identity: EngageIdentity, consent?: EngageConsent) => void\n flush?: (useBeacon?: boolean) => void\n anonId?: () => string\n _q?: unknown[]\n}\n\ndeclare global {\n interface Window {\n engage?: EngageGlobal\n }\n}\n\nfunction resolve(): EngageGlobal | undefined {\n if (typeof window === 'undefined') return undefined\n return window.engage\n}\n\nfunction warnNotReady(): void {\n if (typeof console !== 'undefined') {\n console.warn('[engagex] window.engage is not ready — did you mount <EngageProvider>?')\n }\n}\n\n/**\n * Send a business/behavioural event, e.g.\n * sendEngageEvent('order.placed', { order_id: 'DH1', total: 1990000 })\n */\nexport function sendEngageEvent(event: string, properties?: Record<string, unknown>): void {\n const e = resolve()\n if (e && typeof e.track === 'function') e.track(event, properties)\n else warnNotReady()\n}\n\n/**\n * Identify the visitor. `identity` mixes resolving keys (phone/email/zalo_id,\n * at least one) with optional traits (name/gender/birthday/address). Re-calling\n * with the same phone updates (fill-missing) — it never creates a duplicate.\n * engageIdentify({ phone: '09...', name: 'An' }, { consent: true })\n */\nexport function engageIdentify(identity: EngageIdentity, consent?: EngageConsent): void {\n const e = resolve()\n if (e && typeof e.identify === 'function') e.identify(identity, consent)\n else warnNotReady()\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -3,8 +3,11 @@ import * as react from 'react';
|
|
|
3
3
|
interface EngageProviderProps {
|
|
4
4
|
/** Your source public key, e.g. "pk_live_...". */
|
|
5
5
|
publicKey: string;
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Tracking host origin that serves engage.v1.js. Optional — defaults to
|
|
8
|
+
* {@link DEFAULT_ENGAGE_HOST}. Override only for self-hosting / local dev.
|
|
9
|
+
*/
|
|
10
|
+
host?: string;
|
|
8
11
|
/**
|
|
9
12
|
* Auto-fire `page.viewed` on SPA route changes (default true). Works in Next
|
|
10
13
|
* App/Pages Router and React Router without importing them — it hooks the
|
|
@@ -19,7 +22,7 @@ interface EngageProviderProps {
|
|
|
19
22
|
* Mount once near the root of your app.
|
|
20
23
|
*
|
|
21
24
|
* // app/layout.tsx (Next.js) — it's a client component
|
|
22
|
-
* <EngageProvider publicKey="pk_..." host
|
|
25
|
+
* <EngageProvider publicKey="pk_..." /> // host defaults to your tracking domain
|
|
23
26
|
*
|
|
24
27
|
* It injects engage.v1.js from `host` (auto-updates, keeps endpoint auto-detect
|
|
25
28
|
* and shared _cdp_tid identity) and tracks page views across client navigation.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,11 @@ import * as react from 'react';
|
|
|
3
3
|
interface EngageProviderProps {
|
|
4
4
|
/** Your source public key, e.g. "pk_live_...". */
|
|
5
5
|
publicKey: string;
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Tracking host origin that serves engage.v1.js. Optional — defaults to
|
|
8
|
+
* {@link DEFAULT_ENGAGE_HOST}. Override only for self-hosting / local dev.
|
|
9
|
+
*/
|
|
10
|
+
host?: string;
|
|
8
11
|
/**
|
|
9
12
|
* Auto-fire `page.viewed` on SPA route changes (default true). Works in Next
|
|
10
13
|
* App/Pages Router and React Router without importing them — it hooks the
|
|
@@ -19,7 +22,7 @@ interface EngageProviderProps {
|
|
|
19
22
|
* Mount once near the root of your app.
|
|
20
23
|
*
|
|
21
24
|
* // app/layout.tsx (Next.js) — it's a client component
|
|
22
|
-
* <EngageProvider publicKey="pk_..." host
|
|
25
|
+
* <EngageProvider publicKey="pk_..." /> // host defaults to your tracking domain
|
|
23
26
|
*
|
|
24
27
|
* It injects engage.v1.js from `host` (auto-updates, keeps endpoint auto-detect
|
|
25
28
|
* and shared _cdp_tid identity) and tracks page views across client navigation.
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/provider.tsx
|
|
4
4
|
import { useEffect } from "react";
|
|
5
5
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
6
|
+
var DEFAULT_ENGAGE_HOST = "https://engage.data360.asia";
|
|
6
7
|
var STUB_METHODS = ["init", "track", "identify", "flush"];
|
|
7
8
|
var NAV_EVENT = "engagex:navigation";
|
|
8
9
|
function EngageProvider({
|
|
@@ -13,9 +14,9 @@ function EngageProvider({
|
|
|
13
14
|
children
|
|
14
15
|
}) {
|
|
15
16
|
useEffect(() => {
|
|
16
|
-
if (typeof window === "undefined" || !publicKey
|
|
17
|
+
if (typeof window === "undefined" || !publicKey) return;
|
|
17
18
|
const w = window;
|
|
18
|
-
const base = host.replace(/\/+$/, "");
|
|
19
|
+
const base = (host || DEFAULT_ENGAGE_HOST).replace(/\/+$/, "");
|
|
19
20
|
if (!w.__engagex_loaded) {
|
|
20
21
|
w.__engagex_loaded = true;
|
|
21
22
|
const name = "engage";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx","../src/engage.ts"],"sourcesContent":["import { useEffect } from 'react'\n\nexport interface EngageProviderProps {\n /** Your source public key, e.g. \"pk_live_...\". */\n publicKey: string\n
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/engage.ts"],"sourcesContent":["import { useEffect } from 'react'\n\n/**\n * Default EngageX tracking host that serves engage.v1.js and receives events.\n * Baked in so integrators only pass `publicKey` — they don't need to know the\n * tracking infrastructure. Override `host` only for self-hosting / local dev.\n */\nexport const DEFAULT_ENGAGE_HOST = 'https://engage.data360.asia'\n\nexport interface EngageProviderProps {\n /** Your source public key, e.g. \"pk_live_...\". */\n publicKey: string\n /**\n * Tracking host origin that serves engage.v1.js. Optional — defaults to\n * {@link DEFAULT_ENGAGE_HOST}. Override only for self-hosting / local dev.\n */\n host?: string\n /**\n * Auto-fire `page.viewed` on SPA route changes (default true). Works in Next\n * App/Pages Router and React Router without importing them — it hooks the\n * History API. Disable to fire page views yourself.\n */\n autoPageview?: boolean\n /** Optional branch id attached to every event. */\n branchId?: number | string\n children?: React.ReactNode\n}\n\nconst STUB_METHODS = ['init', 'track', 'identify', 'flush'] as const\nconst NAV_EVENT = 'engagex:navigation'\n\n/**\n * Mount once near the root of your app.\n *\n * // app/layout.tsx (Next.js) — it's a client component\n * <EngageProvider publicKey=\"pk_...\" /> // host defaults to your tracking domain\n *\n * It injects engage.v1.js from `host` (auto-updates, keeps endpoint auto-detect\n * and shared _cdp_tid identity) and tracks page views across client navigation.\n */\nexport function EngageProvider({\n publicKey,\n host,\n autoPageview = true,\n branchId,\n children,\n}: EngageProviderProps) {\n useEffect(() => {\n if (typeof window === 'undefined' || !publicKey) return\n const w = window as unknown as Record<string, any>\n const base = (host || DEFAULT_ENGAGE_HOST).replace(/\\/+$/, '')\n\n // 1) Install the async-loader stub + inject engage.v1.js exactly once.\n if (!w.__engagex_loaded) {\n w.__engagex_loaded = true\n const name = 'engage'\n if (!w[name]) {\n w[name] = { _q: [] as unknown[] }\n STUB_METHODS.forEach((m) => {\n w[name][m] = function () {\n // eslint-disable-next-line prefer-rest-params\n w[name]._q.push([m, arguments])\n }\n })\n }\n const el = document.createElement('script')\n el.async = true\n el.src = base + '/engage.v1.js'\n const first = document.getElementsByTagName('script')[0]\n if (first && first.parentNode) first.parentNode.insertBefore(el, first)\n else document.head.appendChild(el)\n // autoPageview:false at SDK level — page views are handled here so SPA\n // route changes are captured (SDK only auto-fires once on init).\n w[name].init({ key: publicKey, endpoint: base, autoPageview: false, branch_id: branchId })\n }\n\n if (!autoPageview) return\n\n const fire = () => {\n try {\n w.engage?.track('page.viewed', { url: window.location.href })\n } catch {\n /* no-op */\n }\n }\n fire() // initial view\n\n // 2) Framework-agnostic SPA route tracking: patch History API once, then\n // listen for our synthetic nav event + popstate.\n const origPush = window.history.pushState\n const origReplace = window.history.replaceState\n let patchedHere = false\n if (!w.__engagex_history_patched) {\n w.__engagex_history_patched = true\n patchedHere = true\n window.history.pushState = function (this: History, ...args: unknown[]) {\n const r = origPush.apply(this, args as [unknown, string, (string | URL | null)?])\n window.dispatchEvent(new Event(NAV_EVENT))\n return r\n }\n window.history.replaceState = function (this: History, ...args: unknown[]) {\n const r = origReplace.apply(this, args as [unknown, string, (string | URL | null)?])\n window.dispatchEvent(new Event(NAV_EVENT))\n return r\n }\n }\n window.addEventListener(NAV_EVENT, fire)\n window.addEventListener('popstate', fire)\n\n return () => {\n window.removeEventListener(NAV_EVENT, fire)\n window.removeEventListener('popstate', fire)\n if (patchedHere) {\n window.history.pushState = origPush\n window.history.replaceState = origReplace\n w.__engagex_history_patched = false\n }\n }\n }, [publicKey, host, autoPageview, branchId])\n\n return <>{children}</>\n}\n","/**\n * Typed helpers to call the EngageX browser SDK (window.engage) safely from\n * React / Next.js. All calls are SSR-guarded — a no-op on the server.\n *\n * The actual tracking logic lives in engage.v1.js served from your tracking\n * host; <EngageProvider> injects it. These helpers just forward to it.\n */\n\nexport interface EngageIdentity {\n /** At least one resolving key is required: phone / email / zalo_id. */\n phone?: string\n email?: string\n zalo_id?: string\n /** Optional traits — applied fill-missing to the customer profile. */\n name?: string\n /** male | female | other (normalized server-side from \"Nam\"/\"Nữ\"...). */\n gender?: string\n /** e.g. 1990-12-31 or 31/12/1990. */\n birthday?: string\n address?: string\n [key: string]: unknown\n}\n\nexport interface EngageConsent {\n consent: boolean\n purpose?: string\n policy_version?: string\n}\n\nexport interface EngageGlobal {\n init: (opts: Record<string, unknown>) => void\n track: (event: string, properties?: Record<string, unknown>) => void\n identify: (identity: EngageIdentity, consent?: EngageConsent) => void\n flush?: (useBeacon?: boolean) => void\n anonId?: () => string\n _q?: unknown[]\n}\n\ndeclare global {\n interface Window {\n engage?: EngageGlobal\n }\n}\n\nfunction resolve(): EngageGlobal | undefined {\n if (typeof window === 'undefined') return undefined\n return window.engage\n}\n\nfunction warnNotReady(): void {\n if (typeof console !== 'undefined') {\n console.warn('[engagex] window.engage is not ready — did you mount <EngageProvider>?')\n }\n}\n\n/**\n * Send a business/behavioural event, e.g.\n * sendEngageEvent('order.placed', { order_id: 'DH1', total: 1990000 })\n */\nexport function sendEngageEvent(event: string, properties?: Record<string, unknown>): void {\n const e = resolve()\n if (e && typeof e.track === 'function') e.track(event, properties)\n else warnNotReady()\n}\n\n/**\n * Identify the visitor. `identity` mixes resolving keys (phone/email/zalo_id,\n * at least one) with optional traits (name/gender/birthday/address). Re-calling\n * with the same phone updates (fill-missing) — it never creates a duplicate.\n * engageIdentify({ phone: '09...', name: 'An' }, { consent: true })\n */\nexport function engageIdentify(identity: EngageIdentity, consent?: EngageConsent): void {\n const e = resolve()\n if (e && typeof e.identify === 'function') e.identify(identity, consent)\n else warnNotReady()\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@engagex/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "React / Next.js wrapper for EngageX tracking. Loads engage.v1.js from your tracking host and gives you a typed <EngageProvider>, sendEngageEvent() and engageIdentify() with automatic SPA page-view tracking.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|