@followgate/js 0.14.0 → 0.14.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/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +58 -12
- package/dist/index.mjs +58 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -29,6 +29,7 @@ interface FollowGateConfig {
|
|
|
29
29
|
onComplete?: () => void;
|
|
30
30
|
theme?: 'dark' | 'light';
|
|
31
31
|
accentColor?: string;
|
|
32
|
+
forceShow?: boolean;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* SDK Error class with helpful messages
|
|
@@ -93,6 +94,7 @@ declare class FollowGateClient {
|
|
|
93
94
|
private completedActions;
|
|
94
95
|
private modalElement;
|
|
95
96
|
private stylesInjected;
|
|
97
|
+
private currentStep;
|
|
96
98
|
/**
|
|
97
99
|
* Initialize the SDK
|
|
98
100
|
*/
|
|
@@ -103,7 +105,7 @@ declare class FollowGateClient {
|
|
|
103
105
|
private fetchServerConfig;
|
|
104
106
|
/**
|
|
105
107
|
* Show the FollowGate modal
|
|
106
|
-
* If user is already unlocked, calls onComplete immediately
|
|
108
|
+
* If user is already unlocked, calls onComplete immediately (unless forceShow is true)
|
|
107
109
|
*/
|
|
108
110
|
show(): Promise<void>;
|
|
109
111
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ interface FollowGateConfig {
|
|
|
29
29
|
onComplete?: () => void;
|
|
30
30
|
theme?: 'dark' | 'light';
|
|
31
31
|
accentColor?: string;
|
|
32
|
+
forceShow?: boolean;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* SDK Error class with helpful messages
|
|
@@ -93,6 +94,7 @@ declare class FollowGateClient {
|
|
|
93
94
|
private completedActions;
|
|
94
95
|
private modalElement;
|
|
95
96
|
private stylesInjected;
|
|
97
|
+
private currentStep;
|
|
96
98
|
/**
|
|
97
99
|
* Initialize the SDK
|
|
98
100
|
*/
|
|
@@ -103,7 +105,7 @@ declare class FollowGateClient {
|
|
|
103
105
|
private fetchServerConfig;
|
|
104
106
|
/**
|
|
105
107
|
* Show the FollowGate modal
|
|
106
|
-
* If user is already unlocked, calls onComplete immediately
|
|
108
|
+
* If user is already unlocked, calls onComplete immediately (unless forceShow is true)
|
|
107
109
|
*/
|
|
108
110
|
show(): Promise<void>;
|
|
109
111
|
/**
|
package/dist/index.js
CHANGED
|
@@ -503,6 +503,7 @@ var FollowGateClient = class {
|
|
|
503
503
|
completedActions = [];
|
|
504
504
|
modalElement = null;
|
|
505
505
|
stylesInjected = false;
|
|
506
|
+
currentStep = "welcome";
|
|
506
507
|
/**
|
|
507
508
|
* Initialize the SDK
|
|
508
509
|
*/
|
|
@@ -598,22 +599,29 @@ var FollowGateClient = class {
|
|
|
598
599
|
}
|
|
599
600
|
/**
|
|
600
601
|
* Show the FollowGate modal
|
|
601
|
-
* If user is already unlocked, calls onComplete immediately
|
|
602
|
+
* If user is already unlocked, calls onComplete immediately (unless forceShow is true)
|
|
602
603
|
*/
|
|
603
604
|
async show() {
|
|
604
605
|
if (!this.config) {
|
|
605
606
|
throw new Error("[FollowGate] SDK not initialized. Call init() first.");
|
|
606
607
|
}
|
|
607
608
|
if (this.isUnlocked()) {
|
|
608
|
-
if (this.config.
|
|
609
|
-
|
|
609
|
+
if (this.config.forceShow) {
|
|
610
|
+
this.clearUnlockStatus();
|
|
611
|
+
if (this.config.debug) {
|
|
612
|
+
console.log(
|
|
613
|
+
"[FollowGate] forceShow enabled - cleared unlock status, showing modal"
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
} else {
|
|
617
|
+
console.warn(
|
|
610
618
|
"[FollowGate] Modal skipped - user already unlocked.",
|
|
611
|
-
"
|
|
619
|
+
"Use forceShow: true in init() to always show modal, or call FollowGate.reset() to clear.",
|
|
612
620
|
this.config.userId ? `(userId: ${this.config.userId})` : "(no userId set)"
|
|
613
621
|
);
|
|
622
|
+
this.config.onComplete?.();
|
|
623
|
+
return;
|
|
614
624
|
}
|
|
615
|
-
this.config.onComplete?.();
|
|
616
|
-
return;
|
|
617
625
|
}
|
|
618
626
|
await this.fetchServerConfig();
|
|
619
627
|
if (this.config.twitter?.username && !this.hasUsername()) {
|
|
@@ -625,6 +633,7 @@ var FollowGateClient = class {
|
|
|
625
633
|
);
|
|
626
634
|
}
|
|
627
635
|
}
|
|
636
|
+
this.trackEvent("modal_opened");
|
|
628
637
|
this.injectStyles();
|
|
629
638
|
this.createModal();
|
|
630
639
|
}
|
|
@@ -681,6 +690,7 @@ var FollowGateClient = class {
|
|
|
681
690
|
document.body.appendChild(backdrop);
|
|
682
691
|
this.modalElement = backdrop;
|
|
683
692
|
document.getElementById("fg-close-btn")?.addEventListener("click", () => {
|
|
693
|
+
this.trackEvent("modal_closed", { step: this.currentStep });
|
|
684
694
|
this.hide(true);
|
|
685
695
|
});
|
|
686
696
|
requestAnimationFrame(() => {
|
|
@@ -773,6 +783,8 @@ var FollowGateClient = class {
|
|
|
773
783
|
renderUsernameStep() {
|
|
774
784
|
const content = this.getContentElement();
|
|
775
785
|
if (!content) return;
|
|
786
|
+
this.currentStep = "welcome";
|
|
787
|
+
this.trackEvent("step_viewed", { step: "welcome" });
|
|
776
788
|
const handle = this.getTargetHandle();
|
|
777
789
|
const hasRepost = this.shouldShowRepostStep();
|
|
778
790
|
const allowSkip = this.serverConfig?.allowSkip ?? false;
|
|
@@ -824,11 +836,14 @@ var FollowGateClient = class {
|
|
|
824
836
|
handleUsernameSubmit(username) {
|
|
825
837
|
const normalized = username.replace(/^@/, "");
|
|
826
838
|
this.setUsername(normalized);
|
|
839
|
+
this.trackEvent("username_submitted", { username: normalized });
|
|
827
840
|
this.renderFollowStep();
|
|
828
841
|
}
|
|
829
842
|
renderFollowStep() {
|
|
830
843
|
const content = this.getContentElement();
|
|
831
844
|
if (!content) return;
|
|
845
|
+
this.currentStep = "follow";
|
|
846
|
+
this.trackEvent("step_viewed", { step: "follow" });
|
|
832
847
|
const handle = this.getTargetHandle();
|
|
833
848
|
if (!handle) {
|
|
834
849
|
console.error(
|
|
@@ -871,6 +886,7 @@ var FollowGateClient = class {
|
|
|
871
886
|
});
|
|
872
887
|
}
|
|
873
888
|
handleSkipFollow() {
|
|
889
|
+
this.trackEvent("step_skipped", { step: "follow" });
|
|
874
890
|
if (this.shouldShowRepostStep()) {
|
|
875
891
|
this.renderRepostStep();
|
|
876
892
|
} else {
|
|
@@ -952,6 +968,8 @@ var FollowGateClient = class {
|
|
|
952
968
|
const content = this.getContentElement();
|
|
953
969
|
const postId = this.getTargetPostUrl();
|
|
954
970
|
if (!content || !postId) return;
|
|
971
|
+
this.currentStep = "repost";
|
|
972
|
+
this.trackEvent("step_viewed", { step: "repost" });
|
|
955
973
|
content.innerHTML = `
|
|
956
974
|
${this.renderStepIndicator(2)}
|
|
957
975
|
<div class="fg-icon-box fg-success">
|
|
@@ -978,6 +996,7 @@ var FollowGateClient = class {
|
|
|
978
996
|
this.handleRepostClick();
|
|
979
997
|
});
|
|
980
998
|
document.getElementById("fg-skip-repost")?.addEventListener("click", () => {
|
|
999
|
+
this.trackEvent("step_skipped", { step: "repost" });
|
|
981
1000
|
this.renderConfirmStep();
|
|
982
1001
|
});
|
|
983
1002
|
}
|
|
@@ -1049,6 +1068,8 @@ var FollowGateClient = class {
|
|
|
1049
1068
|
renderConfirmStep() {
|
|
1050
1069
|
const content = this.getContentElement();
|
|
1051
1070
|
if (!content) return;
|
|
1071
|
+
this.currentStep = "confirm";
|
|
1072
|
+
this.trackEvent("step_viewed", { step: "confirm" });
|
|
1052
1073
|
const username = this.currentUser?.username;
|
|
1053
1074
|
const targetHandle = this.getTargetHandle();
|
|
1054
1075
|
const postId = this.getTargetPostUrl();
|
|
@@ -1543,8 +1564,37 @@ var FollowGateClient = class {
|
|
|
1543
1564
|
throw new Error(`[FollowGate] Unsupported LinkedIn action: ${action}`);
|
|
1544
1565
|
}
|
|
1545
1566
|
}
|
|
1546
|
-
async trackEvent(event, data) {
|
|
1567
|
+
async trackEvent(event, data = {}) {
|
|
1547
1568
|
if (!this.config) return;
|
|
1569
|
+
const payload = {
|
|
1570
|
+
event
|
|
1571
|
+
};
|
|
1572
|
+
if (data.platform) {
|
|
1573
|
+
payload.platform = data.platform.toUpperCase();
|
|
1574
|
+
}
|
|
1575
|
+
if (data.action) {
|
|
1576
|
+
payload.action = data.action.toUpperCase();
|
|
1577
|
+
}
|
|
1578
|
+
if (data.target) {
|
|
1579
|
+
payload.target = data.target;
|
|
1580
|
+
}
|
|
1581
|
+
if (data.username || this.currentUser?.username) {
|
|
1582
|
+
payload.username = data.username || this.currentUser?.username;
|
|
1583
|
+
}
|
|
1584
|
+
if (data.externalUserId) {
|
|
1585
|
+
payload.externalUserId = data.externalUserId;
|
|
1586
|
+
}
|
|
1587
|
+
const {
|
|
1588
|
+
platform: _p,
|
|
1589
|
+
action: _a,
|
|
1590
|
+
target: _t,
|
|
1591
|
+
username: _u,
|
|
1592
|
+
externalUserId: _e,
|
|
1593
|
+
...rest
|
|
1594
|
+
} = data;
|
|
1595
|
+
if (Object.keys(rest).length > 0) {
|
|
1596
|
+
payload.metadata = rest;
|
|
1597
|
+
}
|
|
1548
1598
|
try {
|
|
1549
1599
|
await fetch(`${this.config.apiUrl}/api/v1/events`, {
|
|
1550
1600
|
method: "POST",
|
|
@@ -1552,11 +1602,7 @@ var FollowGateClient = class {
|
|
|
1552
1602
|
"Content-Type": "application/json",
|
|
1553
1603
|
"X-API-Key": this.config.apiKey
|
|
1554
1604
|
},
|
|
1555
|
-
body: JSON.stringify(
|
|
1556
|
-
event,
|
|
1557
|
-
appId: this.config.appId,
|
|
1558
|
-
...data
|
|
1559
|
-
})
|
|
1605
|
+
body: JSON.stringify(payload)
|
|
1560
1606
|
});
|
|
1561
1607
|
} catch (error) {
|
|
1562
1608
|
if (this.config.debug) {
|
package/dist/index.mjs
CHANGED
|
@@ -477,6 +477,7 @@ var FollowGateClient = class {
|
|
|
477
477
|
completedActions = [];
|
|
478
478
|
modalElement = null;
|
|
479
479
|
stylesInjected = false;
|
|
480
|
+
currentStep = "welcome";
|
|
480
481
|
/**
|
|
481
482
|
* Initialize the SDK
|
|
482
483
|
*/
|
|
@@ -572,22 +573,29 @@ var FollowGateClient = class {
|
|
|
572
573
|
}
|
|
573
574
|
/**
|
|
574
575
|
* Show the FollowGate modal
|
|
575
|
-
* If user is already unlocked, calls onComplete immediately
|
|
576
|
+
* If user is already unlocked, calls onComplete immediately (unless forceShow is true)
|
|
576
577
|
*/
|
|
577
578
|
async show() {
|
|
578
579
|
if (!this.config) {
|
|
579
580
|
throw new Error("[FollowGate] SDK not initialized. Call init() first.");
|
|
580
581
|
}
|
|
581
582
|
if (this.isUnlocked()) {
|
|
582
|
-
if (this.config.
|
|
583
|
-
|
|
583
|
+
if (this.config.forceShow) {
|
|
584
|
+
this.clearUnlockStatus();
|
|
585
|
+
if (this.config.debug) {
|
|
586
|
+
console.log(
|
|
587
|
+
"[FollowGate] forceShow enabled - cleared unlock status, showing modal"
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
} else {
|
|
591
|
+
console.warn(
|
|
584
592
|
"[FollowGate] Modal skipped - user already unlocked.",
|
|
585
|
-
"
|
|
593
|
+
"Use forceShow: true in init() to always show modal, or call FollowGate.reset() to clear.",
|
|
586
594
|
this.config.userId ? `(userId: ${this.config.userId})` : "(no userId set)"
|
|
587
595
|
);
|
|
596
|
+
this.config.onComplete?.();
|
|
597
|
+
return;
|
|
588
598
|
}
|
|
589
|
-
this.config.onComplete?.();
|
|
590
|
-
return;
|
|
591
599
|
}
|
|
592
600
|
await this.fetchServerConfig();
|
|
593
601
|
if (this.config.twitter?.username && !this.hasUsername()) {
|
|
@@ -599,6 +607,7 @@ var FollowGateClient = class {
|
|
|
599
607
|
);
|
|
600
608
|
}
|
|
601
609
|
}
|
|
610
|
+
this.trackEvent("modal_opened");
|
|
602
611
|
this.injectStyles();
|
|
603
612
|
this.createModal();
|
|
604
613
|
}
|
|
@@ -655,6 +664,7 @@ var FollowGateClient = class {
|
|
|
655
664
|
document.body.appendChild(backdrop);
|
|
656
665
|
this.modalElement = backdrop;
|
|
657
666
|
document.getElementById("fg-close-btn")?.addEventListener("click", () => {
|
|
667
|
+
this.trackEvent("modal_closed", { step: this.currentStep });
|
|
658
668
|
this.hide(true);
|
|
659
669
|
});
|
|
660
670
|
requestAnimationFrame(() => {
|
|
@@ -747,6 +757,8 @@ var FollowGateClient = class {
|
|
|
747
757
|
renderUsernameStep() {
|
|
748
758
|
const content = this.getContentElement();
|
|
749
759
|
if (!content) return;
|
|
760
|
+
this.currentStep = "welcome";
|
|
761
|
+
this.trackEvent("step_viewed", { step: "welcome" });
|
|
750
762
|
const handle = this.getTargetHandle();
|
|
751
763
|
const hasRepost = this.shouldShowRepostStep();
|
|
752
764
|
const allowSkip = this.serverConfig?.allowSkip ?? false;
|
|
@@ -798,11 +810,14 @@ var FollowGateClient = class {
|
|
|
798
810
|
handleUsernameSubmit(username) {
|
|
799
811
|
const normalized = username.replace(/^@/, "");
|
|
800
812
|
this.setUsername(normalized);
|
|
813
|
+
this.trackEvent("username_submitted", { username: normalized });
|
|
801
814
|
this.renderFollowStep();
|
|
802
815
|
}
|
|
803
816
|
renderFollowStep() {
|
|
804
817
|
const content = this.getContentElement();
|
|
805
818
|
if (!content) return;
|
|
819
|
+
this.currentStep = "follow";
|
|
820
|
+
this.trackEvent("step_viewed", { step: "follow" });
|
|
806
821
|
const handle = this.getTargetHandle();
|
|
807
822
|
if (!handle) {
|
|
808
823
|
console.error(
|
|
@@ -845,6 +860,7 @@ var FollowGateClient = class {
|
|
|
845
860
|
});
|
|
846
861
|
}
|
|
847
862
|
handleSkipFollow() {
|
|
863
|
+
this.trackEvent("step_skipped", { step: "follow" });
|
|
848
864
|
if (this.shouldShowRepostStep()) {
|
|
849
865
|
this.renderRepostStep();
|
|
850
866
|
} else {
|
|
@@ -926,6 +942,8 @@ var FollowGateClient = class {
|
|
|
926
942
|
const content = this.getContentElement();
|
|
927
943
|
const postId = this.getTargetPostUrl();
|
|
928
944
|
if (!content || !postId) return;
|
|
945
|
+
this.currentStep = "repost";
|
|
946
|
+
this.trackEvent("step_viewed", { step: "repost" });
|
|
929
947
|
content.innerHTML = `
|
|
930
948
|
${this.renderStepIndicator(2)}
|
|
931
949
|
<div class="fg-icon-box fg-success">
|
|
@@ -952,6 +970,7 @@ var FollowGateClient = class {
|
|
|
952
970
|
this.handleRepostClick();
|
|
953
971
|
});
|
|
954
972
|
document.getElementById("fg-skip-repost")?.addEventListener("click", () => {
|
|
973
|
+
this.trackEvent("step_skipped", { step: "repost" });
|
|
955
974
|
this.renderConfirmStep();
|
|
956
975
|
});
|
|
957
976
|
}
|
|
@@ -1023,6 +1042,8 @@ var FollowGateClient = class {
|
|
|
1023
1042
|
renderConfirmStep() {
|
|
1024
1043
|
const content = this.getContentElement();
|
|
1025
1044
|
if (!content) return;
|
|
1045
|
+
this.currentStep = "confirm";
|
|
1046
|
+
this.trackEvent("step_viewed", { step: "confirm" });
|
|
1026
1047
|
const username = this.currentUser?.username;
|
|
1027
1048
|
const targetHandle = this.getTargetHandle();
|
|
1028
1049
|
const postId = this.getTargetPostUrl();
|
|
@@ -1517,8 +1538,37 @@ var FollowGateClient = class {
|
|
|
1517
1538
|
throw new Error(`[FollowGate] Unsupported LinkedIn action: ${action}`);
|
|
1518
1539
|
}
|
|
1519
1540
|
}
|
|
1520
|
-
async trackEvent(event, data) {
|
|
1541
|
+
async trackEvent(event, data = {}) {
|
|
1521
1542
|
if (!this.config) return;
|
|
1543
|
+
const payload = {
|
|
1544
|
+
event
|
|
1545
|
+
};
|
|
1546
|
+
if (data.platform) {
|
|
1547
|
+
payload.platform = data.platform.toUpperCase();
|
|
1548
|
+
}
|
|
1549
|
+
if (data.action) {
|
|
1550
|
+
payload.action = data.action.toUpperCase();
|
|
1551
|
+
}
|
|
1552
|
+
if (data.target) {
|
|
1553
|
+
payload.target = data.target;
|
|
1554
|
+
}
|
|
1555
|
+
if (data.username || this.currentUser?.username) {
|
|
1556
|
+
payload.username = data.username || this.currentUser?.username;
|
|
1557
|
+
}
|
|
1558
|
+
if (data.externalUserId) {
|
|
1559
|
+
payload.externalUserId = data.externalUserId;
|
|
1560
|
+
}
|
|
1561
|
+
const {
|
|
1562
|
+
platform: _p,
|
|
1563
|
+
action: _a,
|
|
1564
|
+
target: _t,
|
|
1565
|
+
username: _u,
|
|
1566
|
+
externalUserId: _e,
|
|
1567
|
+
...rest
|
|
1568
|
+
} = data;
|
|
1569
|
+
if (Object.keys(rest).length > 0) {
|
|
1570
|
+
payload.metadata = rest;
|
|
1571
|
+
}
|
|
1522
1572
|
try {
|
|
1523
1573
|
await fetch(`${this.config.apiUrl}/api/v1/events`, {
|
|
1524
1574
|
method: "POST",
|
|
@@ -1526,11 +1576,7 @@ var FollowGateClient = class {
|
|
|
1526
1576
|
"Content-Type": "application/json",
|
|
1527
1577
|
"X-API-Key": this.config.apiKey
|
|
1528
1578
|
},
|
|
1529
|
-
body: JSON.stringify(
|
|
1530
|
-
event,
|
|
1531
|
-
appId: this.config.appId,
|
|
1532
|
-
...data
|
|
1533
|
-
})
|
|
1579
|
+
body: JSON.stringify(payload)
|
|
1534
1580
|
});
|
|
1535
1581
|
} catch (error) {
|
|
1536
1582
|
if (this.config.debug) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@followgate/js",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "FollowGate SDK - Grow your audience with every download. Require social actions (follow, repost) before users can access your app.",
|
|
5
5
|
"author": "FollowGate <hello@followgate.app>",
|
|
6
6
|
"homepage": "https://followgate.app",
|