@followgate/js 0.8.1 → 0.9.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.mts CHANGED
@@ -83,6 +83,8 @@ interface VerificationStatus {
83
83
  */
84
84
  declare class FollowGateClient {
85
85
  private config;
86
+ private serverConfig;
87
+ private configFetched;
86
88
  private listeners;
87
89
  private currentUser;
88
90
  private completedActions;
@@ -92,11 +94,15 @@ declare class FollowGateClient {
92
94
  * Initialize the SDK
93
95
  */
94
96
  init(config: FollowGateConfig): void;
97
+ /**
98
+ * Fetch app configuration from server
99
+ */
100
+ private fetchServerConfig;
95
101
  /**
96
102
  * Show the FollowGate modal
97
103
  * If user is already unlocked, calls onComplete immediately
98
104
  */
99
- show(): void;
105
+ show(): Promise<void>;
100
106
  /**
101
107
  * Hide the modal
102
108
  */
@@ -107,6 +113,7 @@ declare class FollowGateClient {
107
113
  private renderUsernameStep;
108
114
  private handleUsernameSubmit;
109
115
  private renderFollowStep;
116
+ private handleSkipFollow;
110
117
  private handleFollowClick;
111
118
  private showFollowConfirmation;
112
119
  private handleFollowConfirm;
package/dist/index.d.ts CHANGED
@@ -83,6 +83,8 @@ interface VerificationStatus {
83
83
  */
84
84
  declare class FollowGateClient {
85
85
  private config;
86
+ private serverConfig;
87
+ private configFetched;
86
88
  private listeners;
87
89
  private currentUser;
88
90
  private completedActions;
@@ -92,11 +94,15 @@ declare class FollowGateClient {
92
94
  * Initialize the SDK
93
95
  */
94
96
  init(config: FollowGateConfig): void;
97
+ /**
98
+ * Fetch app configuration from server
99
+ */
100
+ private fetchServerConfig;
95
101
  /**
96
102
  * Show the FollowGate modal
97
103
  * If user is already unlocked, calls onComplete immediately
98
104
  */
99
- show(): void;
105
+ show(): Promise<void>;
100
106
  /**
101
107
  * Hide the modal
102
108
  */
@@ -107,6 +113,7 @@ declare class FollowGateClient {
107
113
  private renderUsernameStep;
108
114
  private handleUsernameSubmit;
109
115
  private renderFollowStep;
116
+ private handleSkipFollow;
110
117
  private handleFollowClick;
111
118
  private showFollowConfirmation;
112
119
  private handleFollowConfirm;
package/dist/index.js CHANGED
@@ -313,32 +313,35 @@ var MODAL_STYLES = `
313
313
  background: rgba(59, 130, 246, 0.05);
314
314
  border: 1px solid rgba(96, 165, 250, 0.5);
315
315
  border-radius: 12px;
316
- padding: 12px 16px;
316
+ padding: 10px 14px;
317
317
  margin-bottom: 8px;
318
318
  display: flex;
319
319
  align-items: center;
320
320
  justify-content: space-between;
321
- gap: 12px;
321
+ gap: 10px;
322
322
  }
323
323
 
324
324
  .fg-verify-box-left {
325
325
  display: flex;
326
326
  align-items: center;
327
327
  gap: 8px;
328
+ flex-shrink: 0;
328
329
  }
329
330
 
330
331
  .fg-verify-spinner {
331
- width: 20px;
332
- height: 20px;
332
+ width: 18px;
333
+ height: 18px;
333
334
  border: 2px solid rgba(96, 165, 250, 0.3);
334
335
  border-top-color: #60a5fa;
335
336
  border-radius: 50%;
336
337
  animation: fg-spin 1s linear infinite;
338
+ flex-shrink: 0;
337
339
  }
338
340
 
339
341
  .fg-verify-text {
340
- font-size: 14px;
342
+ font-size: 13px;
341
343
  color: #93c5fd;
344
+ white-space: nowrap;
342
345
  }
343
346
 
344
347
  .fg-verify-hint {
@@ -349,6 +352,20 @@ var MODAL_STYLES = `
349
352
  margin-top: 2px;
350
353
  }
351
354
 
355
+ .fg-skip-link {
356
+ display: block;
357
+ text-align: center;
358
+ font-size: 12px;
359
+ color: #64748b;
360
+ margin-top: 16px;
361
+ cursor: pointer;
362
+ transition: color 0.2s;
363
+ }
364
+
365
+ .fg-skip-link:hover {
366
+ color: #94a3b8;
367
+ }
368
+
352
369
  .fg-warning-box p {
353
370
  font-size: 14px;
354
371
  color: #fde68a;
@@ -447,6 +464,8 @@ var ICONS = {
447
464
  };
448
465
  var FollowGateClient = class {
449
466
  config = null;
467
+ serverConfig = null;
468
+ configFetched = false;
450
469
  listeners = /* @__PURE__ */ new Map();
451
470
  currentUser = null;
452
471
  completedActions = [];
@@ -508,11 +527,46 @@ var FollowGateClient = class {
508
527
  // ============================================
509
528
  // Modal UI Methods
510
529
  // ============================================
530
+ /**
531
+ * Fetch app configuration from server
532
+ */
533
+ async fetchServerConfig() {
534
+ if (!this.config || this.configFetched) return;
535
+ try {
536
+ const response = await fetch(`${this.config.apiUrl}/api/v1/config`, {
537
+ headers: {
538
+ Authorization: `Bearer ${this.config.apiKey}`
539
+ }
540
+ });
541
+ if (response.ok) {
542
+ const data = await response.json();
543
+ if (data.success && data.data) {
544
+ this.serverConfig = data.data;
545
+ if (this.config.debug) {
546
+ console.log(
547
+ "[FollowGate] Server config loaded:",
548
+ this.serverConfig
549
+ );
550
+ }
551
+ }
552
+ } else if (this.config.debug) {
553
+ console.warn(
554
+ "[FollowGate] Failed to fetch server config:",
555
+ response.status
556
+ );
557
+ }
558
+ } catch (error) {
559
+ if (this.config.debug) {
560
+ console.warn("[FollowGate] Failed to fetch server config:", error);
561
+ }
562
+ }
563
+ this.configFetched = true;
564
+ }
511
565
  /**
512
566
  * Show the FollowGate modal
513
567
  * If user is already unlocked, calls onComplete immediately
514
568
  */
515
- show() {
569
+ async show() {
516
570
  if (!this.config) {
517
571
  throw new Error("[FollowGate] SDK not initialized. Call init() first.");
518
572
  }
@@ -523,6 +577,7 @@ var FollowGateClient = class {
523
577
  this.config.onComplete?.();
524
578
  return;
525
579
  }
580
+ await this.fetchServerConfig();
526
581
  this.injectStyles();
527
582
  this.createModal();
528
583
  }
@@ -652,10 +707,22 @@ var FollowGateClient = class {
652
707
  </button>
653
708
  </div>
654
709
  <p class="fg-hint">A new window will open. Return here after following.</p>
710
+ ${this.serverConfig?.allowSkip ? '<span class="fg-skip-link" id="fg-skip-follow">skip this step</span>' : ""}
655
711
  `;
656
712
  document.getElementById("fg-follow-btn")?.addEventListener("click", () => {
657
713
  this.handleFollowClick();
658
714
  });
715
+ document.getElementById("fg-skip-follow")?.addEventListener("click", () => {
716
+ this.handleSkipFollow();
717
+ });
718
+ }
719
+ handleSkipFollow() {
720
+ if (!this.config?.twitter) return;
721
+ if (this.config.twitter.tweetId) {
722
+ this.renderRepostStep();
723
+ } else {
724
+ this.renderConfirmStep();
725
+ }
659
726
  }
660
727
  handleFollowClick() {
661
728
  if (!this.config?.twitter) return;
@@ -751,10 +818,14 @@ var FollowGateClient = class {
751
818
  </button>
752
819
  </div>
753
820
  <p class="fg-hint">A new window will open. Return here after reposting.</p>
821
+ ${this.serverConfig?.allowSkip ? '<span class="fg-skip-link" id="fg-skip-repost">skip this step</span>' : ""}
754
822
  `;
755
823
  document.getElementById("fg-repost-btn")?.addEventListener("click", () => {
756
824
  this.handleRepostClick();
757
825
  });
826
+ document.getElementById("fg-skip-repost")?.addEventListener("click", () => {
827
+ this.renderConfirmStep();
828
+ });
758
829
  }
759
830
  handleRepostClick() {
760
831
  if (!this.config?.twitter?.tweetId) return;
@@ -832,9 +903,9 @@ var FollowGateClient = class {
832
903
  <span class="fg-verify-text">Verifying follow & repost</span>
833
904
  </div>
834
905
  ${username ? `
835
- <div class="fg-user-badge" style="margin: 0;">
836
- <div class="fg-user-badge-dot" style="background: #facc15;"></div>
837
- <span class="fg-user-badge-text">@${username}</span>
906
+ <div class="fg-user-badge" style="margin: 0; padding: 4px 10px; gap: 6px;">
907
+ <div class="fg-user-badge-dot" style="background: #facc15; width: 6px; height: 6px;"></div>
908
+ <span class="fg-user-badge-text" style="font-size: 12px;">@${username}</span>
838
909
  </div>
839
910
  ` : ""}
840
911
  </div>
package/dist/index.mjs CHANGED
@@ -287,32 +287,35 @@ var MODAL_STYLES = `
287
287
  background: rgba(59, 130, 246, 0.05);
288
288
  border: 1px solid rgba(96, 165, 250, 0.5);
289
289
  border-radius: 12px;
290
- padding: 12px 16px;
290
+ padding: 10px 14px;
291
291
  margin-bottom: 8px;
292
292
  display: flex;
293
293
  align-items: center;
294
294
  justify-content: space-between;
295
- gap: 12px;
295
+ gap: 10px;
296
296
  }
297
297
 
298
298
  .fg-verify-box-left {
299
299
  display: flex;
300
300
  align-items: center;
301
301
  gap: 8px;
302
+ flex-shrink: 0;
302
303
  }
303
304
 
304
305
  .fg-verify-spinner {
305
- width: 20px;
306
- height: 20px;
306
+ width: 18px;
307
+ height: 18px;
307
308
  border: 2px solid rgba(96, 165, 250, 0.3);
308
309
  border-top-color: #60a5fa;
309
310
  border-radius: 50%;
310
311
  animation: fg-spin 1s linear infinite;
312
+ flex-shrink: 0;
311
313
  }
312
314
 
313
315
  .fg-verify-text {
314
- font-size: 14px;
316
+ font-size: 13px;
315
317
  color: #93c5fd;
318
+ white-space: nowrap;
316
319
  }
317
320
 
318
321
  .fg-verify-hint {
@@ -323,6 +326,20 @@ var MODAL_STYLES = `
323
326
  margin-top: 2px;
324
327
  }
325
328
 
329
+ .fg-skip-link {
330
+ display: block;
331
+ text-align: center;
332
+ font-size: 12px;
333
+ color: #64748b;
334
+ margin-top: 16px;
335
+ cursor: pointer;
336
+ transition: color 0.2s;
337
+ }
338
+
339
+ .fg-skip-link:hover {
340
+ color: #94a3b8;
341
+ }
342
+
326
343
  .fg-warning-box p {
327
344
  font-size: 14px;
328
345
  color: #fde68a;
@@ -421,6 +438,8 @@ var ICONS = {
421
438
  };
422
439
  var FollowGateClient = class {
423
440
  config = null;
441
+ serverConfig = null;
442
+ configFetched = false;
424
443
  listeners = /* @__PURE__ */ new Map();
425
444
  currentUser = null;
426
445
  completedActions = [];
@@ -482,11 +501,46 @@ var FollowGateClient = class {
482
501
  // ============================================
483
502
  // Modal UI Methods
484
503
  // ============================================
504
+ /**
505
+ * Fetch app configuration from server
506
+ */
507
+ async fetchServerConfig() {
508
+ if (!this.config || this.configFetched) return;
509
+ try {
510
+ const response = await fetch(`${this.config.apiUrl}/api/v1/config`, {
511
+ headers: {
512
+ Authorization: `Bearer ${this.config.apiKey}`
513
+ }
514
+ });
515
+ if (response.ok) {
516
+ const data = await response.json();
517
+ if (data.success && data.data) {
518
+ this.serverConfig = data.data;
519
+ if (this.config.debug) {
520
+ console.log(
521
+ "[FollowGate] Server config loaded:",
522
+ this.serverConfig
523
+ );
524
+ }
525
+ }
526
+ } else if (this.config.debug) {
527
+ console.warn(
528
+ "[FollowGate] Failed to fetch server config:",
529
+ response.status
530
+ );
531
+ }
532
+ } catch (error) {
533
+ if (this.config.debug) {
534
+ console.warn("[FollowGate] Failed to fetch server config:", error);
535
+ }
536
+ }
537
+ this.configFetched = true;
538
+ }
485
539
  /**
486
540
  * Show the FollowGate modal
487
541
  * If user is already unlocked, calls onComplete immediately
488
542
  */
489
- show() {
543
+ async show() {
490
544
  if (!this.config) {
491
545
  throw new Error("[FollowGate] SDK not initialized. Call init() first.");
492
546
  }
@@ -497,6 +551,7 @@ var FollowGateClient = class {
497
551
  this.config.onComplete?.();
498
552
  return;
499
553
  }
554
+ await this.fetchServerConfig();
500
555
  this.injectStyles();
501
556
  this.createModal();
502
557
  }
@@ -626,10 +681,22 @@ var FollowGateClient = class {
626
681
  </button>
627
682
  </div>
628
683
  <p class="fg-hint">A new window will open. Return here after following.</p>
684
+ ${this.serverConfig?.allowSkip ? '<span class="fg-skip-link" id="fg-skip-follow">skip this step</span>' : ""}
629
685
  `;
630
686
  document.getElementById("fg-follow-btn")?.addEventListener("click", () => {
631
687
  this.handleFollowClick();
632
688
  });
689
+ document.getElementById("fg-skip-follow")?.addEventListener("click", () => {
690
+ this.handleSkipFollow();
691
+ });
692
+ }
693
+ handleSkipFollow() {
694
+ if (!this.config?.twitter) return;
695
+ if (this.config.twitter.tweetId) {
696
+ this.renderRepostStep();
697
+ } else {
698
+ this.renderConfirmStep();
699
+ }
633
700
  }
634
701
  handleFollowClick() {
635
702
  if (!this.config?.twitter) return;
@@ -725,10 +792,14 @@ var FollowGateClient = class {
725
792
  </button>
726
793
  </div>
727
794
  <p class="fg-hint">A new window will open. Return here after reposting.</p>
795
+ ${this.serverConfig?.allowSkip ? '<span class="fg-skip-link" id="fg-skip-repost">skip this step</span>' : ""}
728
796
  `;
729
797
  document.getElementById("fg-repost-btn")?.addEventListener("click", () => {
730
798
  this.handleRepostClick();
731
799
  });
800
+ document.getElementById("fg-skip-repost")?.addEventListener("click", () => {
801
+ this.renderConfirmStep();
802
+ });
732
803
  }
733
804
  handleRepostClick() {
734
805
  if (!this.config?.twitter?.tweetId) return;
@@ -806,9 +877,9 @@ var FollowGateClient = class {
806
877
  <span class="fg-verify-text">Verifying follow & repost</span>
807
878
  </div>
808
879
  ${username ? `
809
- <div class="fg-user-badge" style="margin: 0;">
810
- <div class="fg-user-badge-dot" style="background: #facc15;"></div>
811
- <span class="fg-user-badge-text">@${username}</span>
880
+ <div class="fg-user-badge" style="margin: 0; padding: 4px 10px; gap: 6px;">
881
+ <div class="fg-user-badge-dot" style="background: #facc15; width: 6px; height: 6px;"></div>
882
+ <span class="fg-user-badge-text" style="font-size: 12px;">@${username}</span>
812
883
  </div>
813
884
  ` : ""}
814
885
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@followgate/js",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
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",