@shoppexio/storefront 1.0.77 → 1.0.78
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/CHANGELOG.md +9 -0
- package/dist/index.cjs +38 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +38 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1576,7 +1576,20 @@ interface SearchOptions {
|
|
|
1576
1576
|
declare function searchCatalogItems(query: string, options?: SearchOptions): Promise<SDKResponse<StorefrontCatalogSearchItem[]>>;
|
|
1577
1577
|
declare function searchProducts(query: string, options?: SearchOptions): Promise<SDKResponse<Product[]>>;
|
|
1578
1578
|
|
|
1579
|
-
|
|
1579
|
+
type AffiliateAttributionMode = 'LAST_CLICK' | 'FIRST_CLICK';
|
|
1580
|
+
declare function setAffiliateCode(code: string | null | undefined, ttlDays?: number, mode?: AffiliateAttributionMode): string | null;
|
|
1581
|
+
/**
|
|
1582
|
+
* The stored attribution, or null when nothing valid is held.
|
|
1583
|
+
*
|
|
1584
|
+
* Unlike `getAffiliateCode()` this also reports the mode the entry was written
|
|
1585
|
+
* under, which is what `captureAffiliateFromUrl` needs BEFORE it decides
|
|
1586
|
+
* whether it may overwrite.
|
|
1587
|
+
*/
|
|
1588
|
+
declare function getStoredAffiliate(): {
|
|
1589
|
+
code: string;
|
|
1590
|
+
mode: AffiliateAttributionMode;
|
|
1591
|
+
windowDays: number;
|
|
1592
|
+
} | null;
|
|
1580
1593
|
declare function clearAffiliateCode(): void;
|
|
1581
1594
|
declare function getAffiliateCode(): string | null;
|
|
1582
1595
|
declare function trackAffiliateEvent(eventType: 'add_to_cart' | 'checkout_started', options?: {
|
|
@@ -1599,11 +1612,25 @@ declare function trackAffiliateEvent(eventType: 'add_to_cart' | 'checkout_starte
|
|
|
1599
1612
|
declare function validateAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>>;
|
|
1600
1613
|
declare function applyAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>>;
|
|
1601
1614
|
/**
|
|
1602
|
-
* Capture an affiliate code from the current URL and store it
|
|
1615
|
+
* Capture an affiliate code from the current URL and store it (ADR-0067).
|
|
1603
1616
|
*
|
|
1604
1617
|
* Example:
|
|
1605
1618
|
* - URL: https://mystore.com/product/abc?ref=deadbeef
|
|
1606
1619
|
* - captureAffiliateFromUrl() stores "deadbeef" and returns it.
|
|
1620
|
+
*
|
|
1621
|
+
* Under LAST_CLICK (the default, and the only behaviour before ADR-0067) a new
|
|
1622
|
+
* `?ref=` replaces whatever was stored. Under FIRST_CLICK an existing,
|
|
1623
|
+
* unexpired attribution wins and the new code is NOT stored — the landing is
|
|
1624
|
+
* still reported to the server so the affiliate's click statistics stay
|
|
1625
|
+
* honest, but the credit stays with whoever was there first.
|
|
1626
|
+
*
|
|
1627
|
+
* The mode comes from the server, which means the FIRST landing in a browser
|
|
1628
|
+
* can never be blocked by it — correct, because there is nothing to protect
|
|
1629
|
+
* yet. From then on the mode travels with the stored entry.
|
|
1630
|
+
*
|
|
1631
|
+
* Enforcement is client-side. A buyer who edits localStorage can re-attribute
|
|
1632
|
+
* their own visit; this is the same trust level as the window itself and must
|
|
1633
|
+
* not be presented to merchants as fraud protection.
|
|
1607
1634
|
*/
|
|
1608
1635
|
declare function captureAffiliateFromUrl(param?: string): Promise<string | null>;
|
|
1609
1636
|
|
|
@@ -1926,6 +1953,7 @@ declare const shoppex: {
|
|
|
1926
1953
|
validateAffiliateCode: typeof validateAffiliateCode;
|
|
1927
1954
|
applyAffiliateCode: typeof applyAffiliateCode;
|
|
1928
1955
|
getAffiliateCode: typeof getAffiliateCode;
|
|
1956
|
+
getStoredAffiliate: typeof getStoredAffiliate;
|
|
1929
1957
|
setAffiliateCode: typeof setAffiliateCode;
|
|
1930
1958
|
clearAffiliateCode: typeof clearAffiliateCode;
|
|
1931
1959
|
trackAffiliateEvent: typeof trackAffiliateEvent;
|
package/dist/index.d.ts
CHANGED
|
@@ -1576,7 +1576,20 @@ interface SearchOptions {
|
|
|
1576
1576
|
declare function searchCatalogItems(query: string, options?: SearchOptions): Promise<SDKResponse<StorefrontCatalogSearchItem[]>>;
|
|
1577
1577
|
declare function searchProducts(query: string, options?: SearchOptions): Promise<SDKResponse<Product[]>>;
|
|
1578
1578
|
|
|
1579
|
-
|
|
1579
|
+
type AffiliateAttributionMode = 'LAST_CLICK' | 'FIRST_CLICK';
|
|
1580
|
+
declare function setAffiliateCode(code: string | null | undefined, ttlDays?: number, mode?: AffiliateAttributionMode): string | null;
|
|
1581
|
+
/**
|
|
1582
|
+
* The stored attribution, or null when nothing valid is held.
|
|
1583
|
+
*
|
|
1584
|
+
* Unlike `getAffiliateCode()` this also reports the mode the entry was written
|
|
1585
|
+
* under, which is what `captureAffiliateFromUrl` needs BEFORE it decides
|
|
1586
|
+
* whether it may overwrite.
|
|
1587
|
+
*/
|
|
1588
|
+
declare function getStoredAffiliate(): {
|
|
1589
|
+
code: string;
|
|
1590
|
+
mode: AffiliateAttributionMode;
|
|
1591
|
+
windowDays: number;
|
|
1592
|
+
} | null;
|
|
1580
1593
|
declare function clearAffiliateCode(): void;
|
|
1581
1594
|
declare function getAffiliateCode(): string | null;
|
|
1582
1595
|
declare function trackAffiliateEvent(eventType: 'add_to_cart' | 'checkout_started', options?: {
|
|
@@ -1599,11 +1612,25 @@ declare function trackAffiliateEvent(eventType: 'add_to_cart' | 'checkout_starte
|
|
|
1599
1612
|
declare function validateAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>>;
|
|
1600
1613
|
declare function applyAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>>;
|
|
1601
1614
|
/**
|
|
1602
|
-
* Capture an affiliate code from the current URL and store it
|
|
1615
|
+
* Capture an affiliate code from the current URL and store it (ADR-0067).
|
|
1603
1616
|
*
|
|
1604
1617
|
* Example:
|
|
1605
1618
|
* - URL: https://mystore.com/product/abc?ref=deadbeef
|
|
1606
1619
|
* - captureAffiliateFromUrl() stores "deadbeef" and returns it.
|
|
1620
|
+
*
|
|
1621
|
+
* Under LAST_CLICK (the default, and the only behaviour before ADR-0067) a new
|
|
1622
|
+
* `?ref=` replaces whatever was stored. Under FIRST_CLICK an existing,
|
|
1623
|
+
* unexpired attribution wins and the new code is NOT stored — the landing is
|
|
1624
|
+
* still reported to the server so the affiliate's click statistics stay
|
|
1625
|
+
* honest, but the credit stays with whoever was there first.
|
|
1626
|
+
*
|
|
1627
|
+
* The mode comes from the server, which means the FIRST landing in a browser
|
|
1628
|
+
* can never be blocked by it — correct, because there is nothing to protect
|
|
1629
|
+
* yet. From then on the mode travels with the stored entry.
|
|
1630
|
+
*
|
|
1631
|
+
* Enforcement is client-side. A buyer who edits localStorage can re-attribute
|
|
1632
|
+
* their own visit; this is the same trust level as the window itself and must
|
|
1633
|
+
* not be presented to merchants as fraud protection.
|
|
1607
1634
|
*/
|
|
1608
1635
|
declare function captureAffiliateFromUrl(param?: string): Promise<string | null>;
|
|
1609
1636
|
|
|
@@ -1926,6 +1953,7 @@ declare const shoppex: {
|
|
|
1926
1953
|
validateAffiliateCode: typeof validateAffiliateCode;
|
|
1927
1954
|
applyAffiliateCode: typeof applyAffiliateCode;
|
|
1928
1955
|
getAffiliateCode: typeof getAffiliateCode;
|
|
1956
|
+
getStoredAffiliate: typeof getStoredAffiliate;
|
|
1929
1957
|
setAffiliateCode: typeof setAffiliateCode;
|
|
1930
1958
|
clearAffiliateCode: typeof clearAffiliateCode;
|
|
1931
1959
|
trackAffiliateEvent: typeof trackAffiliateEvent;
|
package/dist/index.js
CHANGED
|
@@ -3890,6 +3890,9 @@ var SESSION_STORAGE_KEY = "shoppex:affiliate_session:v1";
|
|
|
3890
3890
|
var DEFAULT_TTL_DAYS = 30;
|
|
3891
3891
|
var FALLBACK_SESSION_KEY_LENGTH = 24;
|
|
3892
3892
|
var SESSION_KEY_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
3893
|
+
function normalizeMode(value) {
|
|
3894
|
+
return value === "FIRST_CLICK" ? "FIRST_CLICK" : "LAST_CLICK";
|
|
3895
|
+
}
|
|
3893
3896
|
function nowMs() {
|
|
3894
3897
|
return Date.now();
|
|
3895
3898
|
}
|
|
@@ -3907,7 +3910,7 @@ function safeRead() {
|
|
|
3907
3910
|
if (!raw) return null;
|
|
3908
3911
|
const parsed = JSON.parse(raw);
|
|
3909
3912
|
if (!parsed || typeof parsed.code !== "string" || typeof parsed.expiresAt !== "number") return null;
|
|
3910
|
-
return parsed;
|
|
3913
|
+
return parsed.mode === void 0 ? parsed : { ...parsed, mode: normalizeMode(parsed.mode) };
|
|
3911
3914
|
} catch {
|
|
3912
3915
|
return null;
|
|
3913
3916
|
}
|
|
@@ -3919,15 +3922,32 @@ function safeWrite(value) {
|
|
|
3919
3922
|
} catch {
|
|
3920
3923
|
}
|
|
3921
3924
|
}
|
|
3922
|
-
function setAffiliateCode(code, ttlDays = DEFAULT_TTL_DAYS) {
|
|
3925
|
+
function setAffiliateCode(code, ttlDays = DEFAULT_TTL_DAYS, mode) {
|
|
3923
3926
|
const normalized = normalizeAffiliateCode(code);
|
|
3924
3927
|
if (!normalized) {
|
|
3925
3928
|
clearAffiliateCode();
|
|
3926
3929
|
return null;
|
|
3927
3930
|
}
|
|
3928
|
-
safeWrite({
|
|
3931
|
+
safeWrite({
|
|
3932
|
+
code: normalized,
|
|
3933
|
+
expiresAt: nowMs() + ttlMs(ttlDays),
|
|
3934
|
+
windowDays: ttlDays,
|
|
3935
|
+
...mode ? { mode } : {}
|
|
3936
|
+
});
|
|
3929
3937
|
return normalized;
|
|
3930
3938
|
}
|
|
3939
|
+
function getStoredAffiliate() {
|
|
3940
|
+
const stored = safeRead();
|
|
3941
|
+
if (!stored) return null;
|
|
3942
|
+
if (stored.expiresAt <= nowMs()) {
|
|
3943
|
+
clearAffiliateCode();
|
|
3944
|
+
return null;
|
|
3945
|
+
}
|
|
3946
|
+
const code = normalizeAffiliateCode(stored.code);
|
|
3947
|
+
if (!code) return null;
|
|
3948
|
+
const windowDays = typeof stored.windowDays === "number" && stored.windowDays > 0 ? stored.windowDays : DEFAULT_TTL_DAYS;
|
|
3949
|
+
return { code, mode: normalizeMode(stored.mode), windowDays };
|
|
3950
|
+
}
|
|
3931
3951
|
function clearAffiliateCode() {
|
|
3932
3952
|
if (typeof window === "undefined") return;
|
|
3933
3953
|
try {
|
|
@@ -4073,7 +4093,11 @@ async function captureAffiliateFromUrl(param = "ref") {
|
|
|
4073
4093
|
}
|
|
4074
4094
|
code = normalizeAffiliateCode(code);
|
|
4075
4095
|
if (!code) return null;
|
|
4076
|
-
|
|
4096
|
+
const held = getStoredAffiliate();
|
|
4097
|
+
const mayHoldFirstClick = held !== null && held.mode === "FIRST_CLICK" && held.code !== code;
|
|
4098
|
+
if (!mayHoldFirstClick) {
|
|
4099
|
+
setAffiliateCode(code, held?.windowDays ?? DEFAULT_TTL_DAYS, held?.mode);
|
|
4100
|
+
}
|
|
4077
4101
|
if (isInitialized()) {
|
|
4078
4102
|
try {
|
|
4079
4103
|
const config = getConfig();
|
|
@@ -4082,8 +4106,14 @@ async function captureAffiliateFromUrl(param = "ref") {
|
|
|
4082
4106
|
{ shop_slug: config.storeSlug, code },
|
|
4083
4107
|
{ retries: 0 }
|
|
4084
4108
|
);
|
|
4109
|
+
const serverMode = res.success && res.data?.attribution_mode ? normalizeMode(res.data.attribution_mode) : null;
|
|
4110
|
+
const serverWindow = res.success && typeof res.data?.attribution_window_days === "number" ? res.data.attribution_window_days : DEFAULT_TTL_DAYS;
|
|
4111
|
+
const holdsFirstClick = mayHoldFirstClick && serverMode !== "LAST_CLICK";
|
|
4112
|
+
if (holdsFirstClick) {
|
|
4113
|
+
return held.code;
|
|
4114
|
+
}
|
|
4085
4115
|
if (res.success && res.data?.accepted && res.data.affiliate_code) {
|
|
4086
|
-
setAffiliateCode(res.data.affiliate_code);
|
|
4116
|
+
setAffiliateCode(res.data.affiliate_code, serverWindow, serverMode ?? void 0);
|
|
4087
4117
|
return res.data.affiliate_code;
|
|
4088
4118
|
}
|
|
4089
4119
|
if (res.success && res.data && res.data.accepted === false) {
|
|
@@ -4092,10 +4122,10 @@ async function captureAffiliateFromUrl(param = "ref") {
|
|
|
4092
4122
|
}
|
|
4093
4123
|
return code;
|
|
4094
4124
|
} catch {
|
|
4095
|
-
return code;
|
|
4125
|
+
return mayHoldFirstClick ? held.code : code;
|
|
4096
4126
|
}
|
|
4097
4127
|
}
|
|
4098
|
-
return code;
|
|
4128
|
+
return mayHoldFirstClick ? held.code : code;
|
|
4099
4129
|
}
|
|
4100
4130
|
|
|
4101
4131
|
// ../sdk/src/utils/cart-line-id.ts
|
|
@@ -6180,6 +6210,7 @@ var shoppex = {
|
|
|
6180
6210
|
validateAffiliateCode,
|
|
6181
6211
|
applyAffiliateCode,
|
|
6182
6212
|
getAffiliateCode,
|
|
6213
|
+
getStoredAffiliate,
|
|
6183
6214
|
setAffiliateCode,
|
|
6184
6215
|
clearAffiliateCode,
|
|
6185
6216
|
trackAffiliateEvent,
|