@affiliateo/web 1.6.1 → 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 +52 -27
- 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,18 +107,16 @@ 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
|
-
const data = JSON.stringify(payload);
|
|
88
|
-
// Always use fetch so we can see responses in DevTools Network tab
|
|
89
116
|
fetch(`${apiBase}/api/v1/web/event`, {
|
|
90
117
|
method: 'POST',
|
|
91
118
|
headers: { 'Content-Type': 'application/json' },
|
|
92
|
-
body:
|
|
119
|
+
body: JSON.stringify(payload),
|
|
93
120
|
keepalive: true,
|
|
94
121
|
}).then(async (r) => {
|
|
95
122
|
if (!r.ok) {
|
|
@@ -100,12 +127,12 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
100
127
|
console.error('[Affiliateo] Event send error:', err);
|
|
101
128
|
});
|
|
102
129
|
}
|
|
103
|
-
// Send pageview on mount
|
|
130
|
+
// Send pageview on mount
|
|
104
131
|
if (!sentRef.current) {
|
|
105
132
|
sentRef.current = true;
|
|
106
133
|
sendPageview();
|
|
107
134
|
}
|
|
108
|
-
//
|
|
135
|
+
// SPA support: detect URL changes
|
|
109
136
|
let lastPath = window.location.pathname;
|
|
110
137
|
function onUrlChange() {
|
|
111
138
|
if (window.location.pathname !== lastPath) {
|
|
@@ -113,9 +140,7 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
113
140
|
sendPageview();
|
|
114
141
|
}
|
|
115
142
|
}
|
|
116
|
-
// Listen for browser back/forward
|
|
117
143
|
window.addEventListener('popstate', onUrlChange);
|
|
118
|
-
// Patch pushState/replaceState to detect SPA navigations
|
|
119
144
|
const origPushState = history.pushState;
|
|
120
145
|
const origReplaceState = history.replaceState;
|
|
121
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';
|