@affiliateo/web 1.6.0 → 2.0.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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/provider.d.ts +14 -0
- package/dist/provider.js +64 -36
- package/package.json +2 -7
- package/dist/metadata.d.ts +0 -21
- package/dist/metadata.js +0 -60
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { AffiliateoProvider, useAffiliateRef } from './provider';
|
|
1
|
+
export { AffiliateoProvider, useAffiliateRef, getAttribution } from './provider';
|
|
2
2
|
export type { AffiliateoConfig, AffiliateoContextValue } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { AffiliateoProvider, useAffiliateRef } from './provider';
|
|
2
|
+
export { AffiliateoProvider, useAffiliateRef, getAttribution } from './provider';
|
package/dist/provider.d.ts
CHANGED
|
@@ -4,6 +4,20 @@ import type { AffiliateoConfig, AffiliateoContextValue } from './types';
|
|
|
4
4
|
* Returns the affiliate ref code and visitor ID.
|
|
5
5
|
*/
|
|
6
6
|
export declare function useAffiliateRef(): AffiliateoContextValue;
|
|
7
|
+
/**
|
|
8
|
+
* Returns attribution data from localStorage for checkout flows.
|
|
9
|
+
* Call this client-side and include the result in your checkout request body.
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* ```ts
|
|
13
|
+
* const attribution = getAttribution()
|
|
14
|
+
* const res = await fetch('/api/checkout', {
|
|
15
|
+
* method: 'POST',
|
|
16
|
+
* body: JSON.stringify({ ...checkoutData, ...attribution }),
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function getAttribution(): Record<string, string>;
|
|
7
21
|
export declare function AffiliateoProvider({ campaignId, apiUrl, children, }: AffiliateoConfig & {
|
|
8
22
|
children: React.ReactNode;
|
|
9
23
|
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/provider.js
CHANGED
|
@@ -2,20 +2,23 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
4
4
|
const DEFAULT_API_URL = 'https://affiliateo.com';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const LS_VISITOR_ID = 'affiliateo_visitor_id';
|
|
6
|
+
const LS_REF = 'affiliateo_ref';
|
|
7
|
+
const LS_CAMPAIGN_ID = 'affiliateo_campaign_id';
|
|
8
|
+
// localStorage helpers
|
|
9
|
+
function lsGet(key) {
|
|
10
|
+
try {
|
|
11
|
+
return localStorage.getItem(key);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
8
14
|
return null;
|
|
9
|
-
|
|
10
|
-
return m ? m[2] : null;
|
|
15
|
+
}
|
|
11
16
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const secure = window.location.protocol === 'https:' ? ';Secure' : '';
|
|
18
|
-
document.cookie = `${name}=${value};expires=${dt.toUTCString()};path=/;SameSite=Lax${secure}`;
|
|
17
|
+
function lsSet(key, value) {
|
|
18
|
+
try {
|
|
19
|
+
localStorage.setItem(key, value);
|
|
20
|
+
}
|
|
21
|
+
catch { }
|
|
19
22
|
}
|
|
20
23
|
// Generate UUID
|
|
21
24
|
function uuid() {
|
|
@@ -37,6 +40,32 @@ const AffiliateoContext = createContext({
|
|
|
37
40
|
export function useAffiliateRef() {
|
|
38
41
|
return useContext(AffiliateoContext);
|
|
39
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Returns attribution data from localStorage for checkout flows.
|
|
45
|
+
* Call this client-side and include the result in your checkout request body.
|
|
46
|
+
*
|
|
47
|
+
* Example:
|
|
48
|
+
* ```ts
|
|
49
|
+
* const attribution = getAttribution()
|
|
50
|
+
* const res = await fetch('/api/checkout', {
|
|
51
|
+
* method: 'POST',
|
|
52
|
+
* body: JSON.stringify({ ...checkoutData, ...attribution }),
|
|
53
|
+
* })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export function getAttribution() {
|
|
57
|
+
const data = {};
|
|
58
|
+
const vid = lsGet(LS_VISITOR_ID);
|
|
59
|
+
const ref = lsGet(LS_REF);
|
|
60
|
+
const cid = lsGet(LS_CAMPAIGN_ID);
|
|
61
|
+
if (vid)
|
|
62
|
+
data.affiliateo_visitor_id = vid;
|
|
63
|
+
if (ref)
|
|
64
|
+
data.affiliateo_ref = ref;
|
|
65
|
+
if (cid)
|
|
66
|
+
data.affiliateo_campaign_id = cid;
|
|
67
|
+
return data;
|
|
68
|
+
}
|
|
40
69
|
export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
41
70
|
const [state, setState] = useState({
|
|
42
71
|
refCode: null,
|
|
@@ -49,22 +78,22 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
49
78
|
if (typeof window === 'undefined')
|
|
50
79
|
return;
|
|
51
80
|
// Get or create visitor ID
|
|
52
|
-
let vid =
|
|
81
|
+
let vid = lsGet(LS_VISITOR_ID);
|
|
53
82
|
if (!vid) {
|
|
54
83
|
vid = uuid();
|
|
55
84
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Read ref from URL params
|
|
85
|
+
lsSet(LS_VISITOR_ID, vid);
|
|
86
|
+
lsSet(LS_CAMPAIGN_ID, campaignIdRef.current);
|
|
87
|
+
// Read ref from URL params or localStorage
|
|
59
88
|
const params = new URLSearchParams(window.location.search);
|
|
60
|
-
const ref = params.get('ref') || params.get('via') || params.get('source')
|
|
89
|
+
const ref = params.get('ref') || params.get('via') || params.get('source')
|
|
90
|
+
|| lsGet(LS_REF) || null;
|
|
61
91
|
if (ref) {
|
|
62
|
-
|
|
92
|
+
lsSet(LS_REF, ref);
|
|
63
93
|
}
|
|
64
94
|
setState({ refCode: ref, visitorId: vid });
|
|
65
95
|
// Throttle: max 1 pageview per second
|
|
66
96
|
let lastSendTime = 0;
|
|
67
|
-
// Send pageview
|
|
68
97
|
function sendPageview() {
|
|
69
98
|
const now = Date.now();
|
|
70
99
|
if (now - lastSendTime < 1000)
|
|
@@ -78,31 +107,32 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
78
107
|
path: window.location.pathname,
|
|
79
108
|
hostname: window.location.hostname,
|
|
80
109
|
referrer: document.referrer || '',
|
|
81
|
-
ref: ref ||
|
|
110
|
+
ref: ref || lsGet(LS_REF) || '',
|
|
82
111
|
utm_source: params.get('utm_source') || '',
|
|
83
112
|
utm_medium: params.get('utm_medium') || '',
|
|
84
113
|
utm_campaign: params.get('utm_campaign') || '',
|
|
85
114
|
screen_width: window.innerWidth,
|
|
86
115
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
fetch(`${apiBase}/api/v1/web/event`, {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: { 'Content-Type': 'application/json' },
|
|
119
|
+
body: JSON.stringify(payload),
|
|
120
|
+
keepalive: true,
|
|
121
|
+
}).then(async (r) => {
|
|
122
|
+
if (!r.ok) {
|
|
123
|
+
const text = await r.text().catch(() => '');
|
|
124
|
+
console.error(`[Affiliateo] Event failed (${r.status}):`, text);
|
|
125
|
+
}
|
|
126
|
+
}).catch((err) => {
|
|
127
|
+
console.error('[Affiliateo] Event send error:', err);
|
|
128
|
+
});
|
|
99
129
|
}
|
|
100
|
-
// Send pageview on mount
|
|
130
|
+
// Send pageview on mount
|
|
101
131
|
if (!sentRef.current) {
|
|
102
132
|
sentRef.current = true;
|
|
103
133
|
sendPageview();
|
|
104
134
|
}
|
|
105
|
-
//
|
|
135
|
+
// SPA support: detect URL changes
|
|
106
136
|
let lastPath = window.location.pathname;
|
|
107
137
|
function onUrlChange() {
|
|
108
138
|
if (window.location.pathname !== lastPath) {
|
|
@@ -110,9 +140,7 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
110
140
|
sendPageview();
|
|
111
141
|
}
|
|
112
142
|
}
|
|
113
|
-
// Listen for browser back/forward
|
|
114
143
|
window.addEventListener('popstate', onUrlChange);
|
|
115
|
-
// Patch pushState/replaceState to detect SPA navigations
|
|
116
144
|
const origPushState = history.pushState;
|
|
117
145
|
const origReplaceState = history.replaceState;
|
|
118
146
|
history.pushState = function (...args) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@affiliateo/web",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Affiliateo web SDK — affiliate attribution and
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Affiliateo web SDK — affiliate attribution and tracking for web apps",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -10,11 +10,6 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
|
-
},
|
|
14
|
-
"./server": {
|
|
15
|
-
"types": "./dist/server.d.ts",
|
|
16
|
-
"import": "./dist/server.js",
|
|
17
|
-
"require": "./dist/server.js"
|
|
18
13
|
}
|
|
19
14
|
},
|
|
20
15
|
"scripts": {
|
package/dist/metadata.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extract affiliateo cookies from an incoming request.
|
|
3
|
-
* Works with Next.js (App Router & Pages Router), Express, and any framework
|
|
4
|
-
* that exposes cookies on the request object.
|
|
5
|
-
*
|
|
6
|
-
* Returns metadata object to pass to Stripe checkout session.
|
|
7
|
-
*/
|
|
8
|
-
export declare function getMetadata(req: {
|
|
9
|
-
cookies?: Record<string, string> | {
|
|
10
|
-
get?: (name: string) => {
|
|
11
|
-
value: string;
|
|
12
|
-
} | undefined;
|
|
13
|
-
};
|
|
14
|
-
headers?: {
|
|
15
|
-
cookie?: string;
|
|
16
|
-
} | Headers;
|
|
17
|
-
}): {
|
|
18
|
-
affiliateo_visitor_id?: string;
|
|
19
|
-
affiliateo_ref?: string;
|
|
20
|
-
campaign_id?: string;
|
|
21
|
-
};
|
package/dist/metadata.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extract affiliateo cookies from an incoming request.
|
|
3
|
-
* Works with Next.js (App Router & Pages Router), Express, and any framework
|
|
4
|
-
* that exposes cookies on the request object.
|
|
5
|
-
*
|
|
6
|
-
* Returns metadata object to pass to Stripe checkout session.
|
|
7
|
-
*/
|
|
8
|
-
export function getMetadata(req) {
|
|
9
|
-
const metadata = {};
|
|
10
|
-
// Try Next.js App Router cookies (ReadonlyRequestCookies with .get())
|
|
11
|
-
if (req.cookies && typeof req.cookies === 'object' && 'get' in req.cookies && typeof req.cookies.get === 'function') {
|
|
12
|
-
const visitorId = req.cookies.get('affiliateo_visitor_id');
|
|
13
|
-
const ref = req.cookies.get('affiliateo_ref');
|
|
14
|
-
const campaignId = req.cookies.get('affiliateo_campaign_id');
|
|
15
|
-
if (visitorId?.value)
|
|
16
|
-
metadata.affiliateo_visitor_id = visitorId.value;
|
|
17
|
-
if (ref?.value)
|
|
18
|
-
metadata.affiliateo_ref = ref.value;
|
|
19
|
-
if (campaignId?.value)
|
|
20
|
-
metadata.campaign_id = campaignId.value;
|
|
21
|
-
return metadata;
|
|
22
|
-
}
|
|
23
|
-
// Try plain object cookies (Express, Pages Router, etc.)
|
|
24
|
-
if (req.cookies && typeof req.cookies === 'object') {
|
|
25
|
-
const cookies = req.cookies;
|
|
26
|
-
if (cookies.affiliateo_visitor_id)
|
|
27
|
-
metadata.affiliateo_visitor_id = cookies.affiliateo_visitor_id;
|
|
28
|
-
if (cookies.affiliateo_ref)
|
|
29
|
-
metadata.affiliateo_ref = cookies.affiliateo_ref;
|
|
30
|
-
if (cookies.affiliateo_campaign_id)
|
|
31
|
-
metadata.campaign_id = cookies.affiliateo_campaign_id;
|
|
32
|
-
return metadata;
|
|
33
|
-
}
|
|
34
|
-
// Fallback: parse cookie header manually
|
|
35
|
-
const cookieHeader = req.headers instanceof Headers
|
|
36
|
-
? req.headers.get('cookie')
|
|
37
|
-
: req.headers?.cookie;
|
|
38
|
-
if (cookieHeader) {
|
|
39
|
-
const cookies = parseCookies(cookieHeader);
|
|
40
|
-
if (cookies.affiliateo_visitor_id)
|
|
41
|
-
metadata.affiliateo_visitor_id = cookies.affiliateo_visitor_id;
|
|
42
|
-
if (cookies.affiliateo_ref)
|
|
43
|
-
metadata.affiliateo_ref = cookies.affiliateo_ref;
|
|
44
|
-
if (cookies.affiliateo_campaign_id)
|
|
45
|
-
metadata.campaign_id = cookies.affiliateo_campaign_id;
|
|
46
|
-
}
|
|
47
|
-
return metadata;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Parse a cookie header string into key-value pairs.
|
|
51
|
-
*/
|
|
52
|
-
function parseCookies(cookieHeader) {
|
|
53
|
-
const cookies = {};
|
|
54
|
-
for (const pair of cookieHeader.split(';')) {
|
|
55
|
-
const [key, ...rest] = pair.trim().split('=');
|
|
56
|
-
if (key)
|
|
57
|
-
cookies[key.trim()] = rest.join('=').trim();
|
|
58
|
-
}
|
|
59
|
-
return cookies;
|
|
60
|
-
}
|
package/dist/server.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { getMetadata } from './metadata';
|
package/dist/server.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { getMetadata } from './metadata';
|