@followgate/js 0.15.3 → 0.15.5
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/README.md +41 -37
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +25 -27
- package/dist/index.mjs +25 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @followgate/js
|
|
|
12
12
|
|
|
13
13
|
## Quick Start (Built-in Modal)
|
|
14
14
|
|
|
15
|
-
Just
|
|
15
|
+
Just a few lines of code - no custom UI needed:
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
18
|
import { FollowGate } from '@followgate/js';
|
|
@@ -21,10 +21,8 @@ import { FollowGate } from '@followgate/js';
|
|
|
21
21
|
FollowGate.init({
|
|
22
22
|
appId: 'your-app-id',
|
|
23
23
|
apiKey: 'fg_live_xxx',
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
tweetId: '1234567890', // Optional: require repost
|
|
27
|
-
},
|
|
24
|
+
userId: user.id, // Recommended for server-side verification
|
|
25
|
+
// Target handle is configured in the Dashboard - no code needed!
|
|
28
26
|
onComplete: () => {
|
|
29
27
|
// User completed all actions - redirect to your app
|
|
30
28
|
router.push('/dashboard');
|
|
@@ -39,8 +37,10 @@ The SDK renders a beautiful, fully-functional modal with:
|
|
|
39
37
|
|
|
40
38
|
- Username input step
|
|
41
39
|
- Follow action with intent URL
|
|
42
|
-
- Repost action (optional)
|
|
43
|
-
- Confirmation step
|
|
40
|
+
- Repost action (optional, configured in Dashboard)
|
|
41
|
+
- Confirmation step with custom text support
|
|
42
|
+
- X button to close/cancel (redirects to `cancelUrl` if configured)
|
|
43
|
+
- Dark/light themes
|
|
44
44
|
- All styling included (no CSS needed)
|
|
45
45
|
|
|
46
46
|
## When to Show the Modal
|
|
@@ -69,10 +69,10 @@ if (!FollowGate.isUnlocked()) {
|
|
|
69
69
|
FollowGate.init({
|
|
70
70
|
appId: 'your-app-id',
|
|
71
71
|
apiKey: 'fg_live_xxx',
|
|
72
|
-
|
|
72
|
+
// Handle configured in Dashboard!
|
|
73
73
|
|
|
74
74
|
onComplete: async () => {
|
|
75
|
-
//
|
|
75
|
+
// User completed all steps - NOW create the account!
|
|
76
76
|
const user = FollowGate.getUser();
|
|
77
77
|
|
|
78
78
|
await fetch('/api/create-account', {
|
|
@@ -119,10 +119,10 @@ If no username is passed, the modal shows a Welcome step where the user types th
|
|
|
119
119
|
FollowGate.init({
|
|
120
120
|
appId: 'your-app-id',
|
|
121
121
|
apiKey: 'fg_live_xxx',
|
|
122
|
-
|
|
122
|
+
// Handle configured in Dashboard!
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
-
FollowGate.show(); //
|
|
125
|
+
FollowGate.show(); // Modal starts with username input step
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
**Method 2: App passes username via code (skips Welcome step)**
|
|
@@ -133,12 +133,11 @@ FollowGate.init({
|
|
|
133
133
|
appId: 'your-app-id',
|
|
134
134
|
apiKey: 'fg_live_xxx',
|
|
135
135
|
twitter: {
|
|
136
|
-
|
|
137
|
-
username: 'their_x_username', // ← skips Welcome step
|
|
136
|
+
username: 'their_x_username', // skips Welcome step
|
|
138
137
|
},
|
|
139
138
|
});
|
|
140
139
|
|
|
141
|
-
FollowGate.show(); //
|
|
140
|
+
FollowGate.show(); // Modal starts directly with Follow step
|
|
142
141
|
```
|
|
143
142
|
|
|
144
143
|
> **Note:** No Twitter API calls are made in either case. The SDK uses intent URLs only.
|
|
@@ -151,16 +150,15 @@ FollowGate.init({
|
|
|
151
150
|
appId: 'your-app-id', // Your App ID from the dashboard
|
|
152
151
|
apiKey: 'fg_live_xxx', // Your API key (starts with fg_live_ or fg_test_)
|
|
153
152
|
|
|
154
|
-
// Twitter/X Configuration
|
|
153
|
+
// Twitter/X Configuration (all optional - configure in Dashboard!)
|
|
155
154
|
twitter: {
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
overrideHandle: 'other_handle', // Override Dashboard handle (highest priority)
|
|
156
|
+
overridePostUrl: 'https://x.com/user/status/123', // Override Dashboard post URL for repost
|
|
157
|
+
username: 'their_username', // Pre-fill user's X username (skips Welcome step)
|
|
158
158
|
},
|
|
159
159
|
|
|
160
160
|
// Callback when user completes all actions
|
|
161
161
|
onComplete: () => {
|
|
162
|
-
// Called after the user finishes all steps and clicks "Got it"
|
|
163
|
-
// Typically used to redirect to your app
|
|
164
162
|
router.push('/dashboard');
|
|
165
163
|
},
|
|
166
164
|
|
|
@@ -170,9 +168,17 @@ FollowGate.init({
|
|
|
170
168
|
accentColor: '#6366f1', // Customize primary button color (hex)
|
|
171
169
|
theme: 'dark', // 'dark' | 'light' - modal appearance
|
|
172
170
|
apiUrl: 'https://...', // Custom API URL (for self-hosted)
|
|
171
|
+
forceShow: false, // Always show modal, even if user already unlocked
|
|
173
172
|
});
|
|
174
173
|
```
|
|
175
174
|
|
|
175
|
+
**Dashboard Configuration:** Target handle, required actions, custom texts, redirect URLs, and skip options are all configured in the [Dashboard](https://followgate.app) and fetched automatically by the SDK.
|
|
176
|
+
|
|
177
|
+
**Handle Priority:**
|
|
178
|
+
|
|
179
|
+
1. `twitter.overrideHandle` (explicit code override - highest priority)
|
|
180
|
+
2. Dashboard `targetHandle` (default)
|
|
181
|
+
|
|
176
182
|
### Handle & Target Formats
|
|
177
183
|
|
|
178
184
|
The SDK automatically normalizes usernames - you can use `@username` or `username`, both work:
|
|
@@ -180,31 +186,34 @@ The SDK automatically normalizes usernames - you can use `@username` or `usernam
|
|
|
180
186
|
| Platform | Action | Target Format | Example |
|
|
181
187
|
| ------------ | ------ | ----------------------------------- | ------------------------------------ |
|
|
182
188
|
| **Twitter** | follow | Username (without @) | `lukasvanuden` |
|
|
183
|
-
| **Twitter** | repost | Tweet ID
|
|
184
|
-
| **Twitter** | like | Tweet ID
|
|
189
|
+
| **Twitter** | repost | Post URL or Tweet ID | `https://x.com/user/status/123` |
|
|
190
|
+
| **Twitter** | like | Post URL or Tweet ID | `https://x.com/user/status/123` |
|
|
185
191
|
| **Bluesky** | follow | Handle (with or without @) | `user.bsky.social` |
|
|
186
192
|
| **Bluesky** | repost | AT URI or post path | `user.bsky.social/post/xyz` |
|
|
187
193
|
| **LinkedIn** | follow | Company name or prefixed identifier | `company:anthropic` or `in:username` |
|
|
188
194
|
|
|
189
|
-
**Tip:** For Twitter, you can find the Tweet ID in the URL: `https://x.com/user/status/1234567890123456789`
|
|
190
|
-
|
|
191
195
|
## API Reference
|
|
192
196
|
|
|
193
197
|
### Modal Methods
|
|
194
198
|
|
|
195
199
|
```typescript
|
|
196
|
-
// Show the FollowGate modal
|
|
200
|
+
// Show the FollowGate modal (async - fetches config first)
|
|
197
201
|
// If user is already unlocked, calls onComplete immediately
|
|
198
|
-
FollowGate.show();
|
|
202
|
+
await FollowGate.show();
|
|
199
203
|
|
|
200
204
|
// Hide the modal programmatically
|
|
205
|
+
// Pass true to redirect to cancelUrl (if configured)
|
|
201
206
|
FollowGate.hide();
|
|
207
|
+
FollowGate.hide(true); // redirect to cancelUrl
|
|
202
208
|
|
|
203
209
|
// Check if user has completed all actions
|
|
204
210
|
FollowGate.isUnlocked(); // true | false
|
|
205
211
|
|
|
206
212
|
// Reset user's session (for testing)
|
|
207
213
|
FollowGate.reset();
|
|
214
|
+
|
|
215
|
+
// Clear only unlock status, keep user data (v0.13.0+)
|
|
216
|
+
FollowGate.clearUnlockStatus();
|
|
208
217
|
```
|
|
209
218
|
|
|
210
219
|
### Advanced Usage
|
|
@@ -287,16 +296,16 @@ FollowGate.init({
|
|
|
287
296
|
appId: 'your-app-id',
|
|
288
297
|
apiKey: 'fg_live_xxx',
|
|
289
298
|
userId: clerkUserId,
|
|
290
|
-
|
|
299
|
+
// Handle configured in Dashboard!
|
|
291
300
|
});
|
|
292
301
|
|
|
293
302
|
const isVerified = await FollowGate.isVerified();
|
|
294
303
|
|
|
295
304
|
if (isVerified) {
|
|
296
|
-
// User completed FollowGate
|
|
305
|
+
// User completed FollowGate - Full access
|
|
297
306
|
enableAllFeatures();
|
|
298
307
|
} else {
|
|
299
|
-
// User hasn't completed
|
|
308
|
+
// User hasn't completed - Limited access
|
|
300
309
|
enableTrialMode();
|
|
301
310
|
}
|
|
302
311
|
```
|
|
@@ -347,7 +356,7 @@ export default function WelcomePage() {
|
|
|
347
356
|
FollowGate.init({
|
|
348
357
|
appId: process.env.NEXT_PUBLIC_FOLLOWGATE_APP_ID!,
|
|
349
358
|
apiKey: process.env.NEXT_PUBLIC_FOLLOWGATE_API_KEY!,
|
|
350
|
-
|
|
359
|
+
// Handle configured in Dashboard!
|
|
351
360
|
onComplete: () => router.push('/dashboard'),
|
|
352
361
|
});
|
|
353
362
|
|
|
@@ -385,7 +394,7 @@ export default function WelcomePage() {
|
|
|
385
394
|
appId: process.env.NEXT_PUBLIC_FOLLOWGATE_APP_ID!,
|
|
386
395
|
apiKey: process.env.NEXT_PUBLIC_FOLLOWGATE_API_KEY!,
|
|
387
396
|
userId: user.id, // Per-user unlock status (recommended!)
|
|
388
|
-
|
|
397
|
+
// Handle configured in Dashboard!
|
|
389
398
|
onComplete: () => router.push('/dashboard'),
|
|
390
399
|
});
|
|
391
400
|
|
|
@@ -421,17 +430,12 @@ import type {
|
|
|
421
430
|
|
|
422
431
|
## Pricing
|
|
423
432
|
|
|
424
|
-
|
|
425
|
-
| -------- | ------ | ------ | ------------------ |
|
|
426
|
-
| Free | $0 | 100 | Intent-URL only |
|
|
427
|
-
| Starter | $15/mo | 500 | Weekly sampling |
|
|
428
|
-
| Pro | $49/mo | 2,000 | OAuth verification |
|
|
429
|
-
| Business | $99/mo | 5,000+ | Daily verification |
|
|
433
|
+
**FollowGate is 100% free.** No tiers, no limits, no billing. Use it for as many apps and users as you want.
|
|
430
434
|
|
|
431
435
|
## Links
|
|
432
436
|
|
|
433
437
|
- [Dashboard](https://followgate.app)
|
|
434
|
-
- [Documentation](https://
|
|
438
|
+
- [Documentation](https://followgate.app/docs)
|
|
435
439
|
- [GitHub](https://github.com/JustFF5/FollowGate)
|
|
436
440
|
- [Live Demo](https://follow-gate-web-demo.vercel.app)
|
|
437
441
|
|
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ type Platform = 'twitter' | 'bluesky' | 'linkedin';
|
|
|
5
5
|
/**
|
|
6
6
|
* Supported social actions
|
|
7
7
|
*/
|
|
8
|
-
type SocialAction = 'follow' | 'repost'
|
|
8
|
+
type SocialAction = 'follow' | 'repost';
|
|
9
9
|
/**
|
|
10
10
|
* Twitter/X configuration
|
|
11
11
|
*/
|
|
@@ -178,7 +178,6 @@ declare class FollowGateClient {
|
|
|
178
178
|
clearUnlockStatus(): void;
|
|
179
179
|
getFollowUrl(platform: Platform, target: string): string;
|
|
180
180
|
getRepostUrl(platform: Platform, target: string): string;
|
|
181
|
-
getLikeUrl(platform: Platform, target: string): string;
|
|
182
181
|
openIntent(options: CompleteOptions): Promise<void>;
|
|
183
182
|
complete(options: CompleteOptions): Promise<void>;
|
|
184
183
|
unlock(): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ type Platform = 'twitter' | 'bluesky' | 'linkedin';
|
|
|
5
5
|
/**
|
|
6
6
|
* Supported social actions
|
|
7
7
|
*/
|
|
8
|
-
type SocialAction = 'follow' | 'repost'
|
|
8
|
+
type SocialAction = 'follow' | 'repost';
|
|
9
9
|
/**
|
|
10
10
|
* Twitter/X configuration
|
|
11
11
|
*/
|
|
@@ -178,7 +178,6 @@ declare class FollowGateClient {
|
|
|
178
178
|
clearUnlockStatus(): void;
|
|
179
179
|
getFollowUrl(platform: Platform, target: string): string;
|
|
180
180
|
getRepostUrl(platform: Platform, target: string): string;
|
|
181
|
-
getLikeUrl(platform: Platform, target: string): string;
|
|
182
181
|
openIntent(options: CompleteOptions): Promise<void>;
|
|
183
182
|
complete(options: CompleteOptions): Promise<void>;
|
|
184
183
|
unlock(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -614,11 +614,13 @@ var FollowGateClient = class {
|
|
|
614
614
|
);
|
|
615
615
|
}
|
|
616
616
|
} else {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
617
|
+
if (this.config.debug) {
|
|
618
|
+
console.warn(
|
|
619
|
+
"[FollowGate] Modal skipped - user already unlocked.",
|
|
620
|
+
"Use forceShow: true in init() to always show modal, or call FollowGate.reset() to clear.",
|
|
621
|
+
this.config.userId ? `(userId: ${this.config.userId})` : "(no userId set)"
|
|
622
|
+
);
|
|
623
|
+
}
|
|
622
624
|
this.config.onComplete?.();
|
|
623
625
|
return;
|
|
624
626
|
}
|
|
@@ -768,11 +770,13 @@ var FollowGateClient = class {
|
|
|
768
770
|
const postUrl = this.getTargetPostUrl();
|
|
769
771
|
const actionsIncludeRepost = this.serverConfig?.actions?.includes("repost");
|
|
770
772
|
if (actionsIncludeRepost && !postUrl) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
773
|
+
if (this.config?.debug) {
|
|
774
|
+
console.warn(
|
|
775
|
+
"[FollowGate] REPOST action configured but no targetPostUrl available.",
|
|
776
|
+
"Set targetPostUrl in Dashboard or use overridePostUrl in config.",
|
|
777
|
+
"Skipping repost step."
|
|
778
|
+
);
|
|
779
|
+
}
|
|
776
780
|
return false;
|
|
777
781
|
}
|
|
778
782
|
if (this.config?.twitter?.tweetId) {
|
|
@@ -846,16 +850,16 @@ var FollowGateClient = class {
|
|
|
846
850
|
this.trackEvent("step_viewed", { step: "follow" });
|
|
847
851
|
const handle = this.getTargetHandle();
|
|
848
852
|
if (!handle) {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
853
|
+
if (this.config?.debug) {
|
|
854
|
+
console.error(
|
|
855
|
+
"[FollowGate] No target handle configured. Set it in Dashboard or use overrideHandle."
|
|
856
|
+
);
|
|
857
|
+
}
|
|
852
858
|
return;
|
|
853
859
|
}
|
|
854
860
|
const hasRepost = this.shouldShowRepostStep();
|
|
855
|
-
const
|
|
856
|
-
const
|
|
857
|
-
const title = this.serverConfig?.welcomeTitle || defaultTitle;
|
|
858
|
-
const message = this.serverConfig?.welcomeMessage || defaultMessage;
|
|
861
|
+
const title = hasRepost ? "Step 1: Follow" : "Follow to Continue";
|
|
862
|
+
const message = `Follow @${handle} on X`;
|
|
859
863
|
content.innerHTML = `
|
|
860
864
|
${hasRepost ? this.renderStepIndicator(1) : ""}
|
|
861
865
|
<div class="fg-icon-box">
|
|
@@ -1100,14 +1104,14 @@ var FollowGateClient = class {
|
|
|
1100
1104
|
</div>
|
|
1101
1105
|
` : ""}
|
|
1102
1106
|
</div>
|
|
1103
|
-
<p class="fg-verify-hint">Verification may take some time</p>
|
|
1104
|
-
<p style="color: rgba(250, 204, 21, 0.85); font-size: 11px; margin:
|
|
1107
|
+
<p class="fg-verify-hint" style="margin-bottom: 32px;">Verification may take some time</p>
|
|
1108
|
+
<p style="color: rgba(250, 204, 21, 0.85); font-size: 11px; margin: 0 0 10px; text-align: center;">Access may be revoked if actions are not completed.</p>
|
|
1105
1109
|
<button class="fg-btn fg-btn-green" id="fg-finish-btn">
|
|
1106
1110
|
${ICONS.check}
|
|
1107
|
-
Got it - Get access
|
|
1111
|
+
Got it - Get access now!
|
|
1108
1112
|
</button>
|
|
1109
1113
|
${hasFollow || hasRepost ? `
|
|
1110
|
-
<p style="color: rgba(255,255,255,0.4); font-size: 11px; margin: 24px 0
|
|
1114
|
+
<p style="color: rgba(255,255,255,0.4); font-size: 11px; margin: 24px 0 0; text-align: center;">Missed something? Open again:</p>
|
|
1111
1115
|
<div class="fg-btn-row">
|
|
1112
1116
|
${hasFollow ? `
|
|
1113
1117
|
<button class="fg-btn fg-btn-secondary" id="fg-redo-follow">
|
|
@@ -1242,9 +1246,6 @@ var FollowGateClient = class {
|
|
|
1242
1246
|
getRepostUrl(platform, target) {
|
|
1243
1247
|
return this.buildIntentUrl({ platform, action: "repost", target });
|
|
1244
1248
|
}
|
|
1245
|
-
getLikeUrl(platform, target) {
|
|
1246
|
-
return this.buildIntentUrl({ platform, action: "like", target });
|
|
1247
|
-
}
|
|
1248
1249
|
async openIntent(options) {
|
|
1249
1250
|
if (!this.config) {
|
|
1250
1251
|
throw new Error("[FollowGate] SDK not initialized. Call init() first.");
|
|
@@ -1523,8 +1524,6 @@ var FollowGateClient = class {
|
|
|
1523
1524
|
return `https://twitter.com/intent/follow?screen_name=${encodeURIComponent(target)}`;
|
|
1524
1525
|
case "repost":
|
|
1525
1526
|
return `https://twitter.com/intent/retweet?tweet_id=${encodeURIComponent(target)}`;
|
|
1526
|
-
case "like":
|
|
1527
|
-
return `https://twitter.com/intent/like?tweet_id=${encodeURIComponent(target)}`;
|
|
1528
1527
|
default:
|
|
1529
1528
|
throw new Error(`[FollowGate] Unsupported Twitter action: ${action}`);
|
|
1530
1529
|
}
|
|
@@ -1535,7 +1534,6 @@ var FollowGateClient = class {
|
|
|
1535
1534
|
case "follow":
|
|
1536
1535
|
return `https://bsky.app/profile/${encodeURIComponent(normalizedTarget)}`;
|
|
1537
1536
|
case "repost":
|
|
1538
|
-
case "like":
|
|
1539
1537
|
if (target.startsWith("at://") || target.includes("/post/")) {
|
|
1540
1538
|
const postPath = target.replace("at://", "").replace("app.bsky.feed.post/", "post/");
|
|
1541
1539
|
return `https://bsky.app/profile/${postPath}`;
|
package/dist/index.mjs
CHANGED
|
@@ -588,11 +588,13 @@ var FollowGateClient = class {
|
|
|
588
588
|
);
|
|
589
589
|
}
|
|
590
590
|
} else {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
591
|
+
if (this.config.debug) {
|
|
592
|
+
console.warn(
|
|
593
|
+
"[FollowGate] Modal skipped - user already unlocked.",
|
|
594
|
+
"Use forceShow: true in init() to always show modal, or call FollowGate.reset() to clear.",
|
|
595
|
+
this.config.userId ? `(userId: ${this.config.userId})` : "(no userId set)"
|
|
596
|
+
);
|
|
597
|
+
}
|
|
596
598
|
this.config.onComplete?.();
|
|
597
599
|
return;
|
|
598
600
|
}
|
|
@@ -742,11 +744,13 @@ var FollowGateClient = class {
|
|
|
742
744
|
const postUrl = this.getTargetPostUrl();
|
|
743
745
|
const actionsIncludeRepost = this.serverConfig?.actions?.includes("repost");
|
|
744
746
|
if (actionsIncludeRepost && !postUrl) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
747
|
+
if (this.config?.debug) {
|
|
748
|
+
console.warn(
|
|
749
|
+
"[FollowGate] REPOST action configured but no targetPostUrl available.",
|
|
750
|
+
"Set targetPostUrl in Dashboard or use overridePostUrl in config.",
|
|
751
|
+
"Skipping repost step."
|
|
752
|
+
);
|
|
753
|
+
}
|
|
750
754
|
return false;
|
|
751
755
|
}
|
|
752
756
|
if (this.config?.twitter?.tweetId) {
|
|
@@ -820,16 +824,16 @@ var FollowGateClient = class {
|
|
|
820
824
|
this.trackEvent("step_viewed", { step: "follow" });
|
|
821
825
|
const handle = this.getTargetHandle();
|
|
822
826
|
if (!handle) {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
827
|
+
if (this.config?.debug) {
|
|
828
|
+
console.error(
|
|
829
|
+
"[FollowGate] No target handle configured. Set it in Dashboard or use overrideHandle."
|
|
830
|
+
);
|
|
831
|
+
}
|
|
826
832
|
return;
|
|
827
833
|
}
|
|
828
834
|
const hasRepost = this.shouldShowRepostStep();
|
|
829
|
-
const
|
|
830
|
-
const
|
|
831
|
-
const title = this.serverConfig?.welcomeTitle || defaultTitle;
|
|
832
|
-
const message = this.serverConfig?.welcomeMessage || defaultMessage;
|
|
835
|
+
const title = hasRepost ? "Step 1: Follow" : "Follow to Continue";
|
|
836
|
+
const message = `Follow @${handle} on X`;
|
|
833
837
|
content.innerHTML = `
|
|
834
838
|
${hasRepost ? this.renderStepIndicator(1) : ""}
|
|
835
839
|
<div class="fg-icon-box">
|
|
@@ -1074,14 +1078,14 @@ var FollowGateClient = class {
|
|
|
1074
1078
|
</div>
|
|
1075
1079
|
` : ""}
|
|
1076
1080
|
</div>
|
|
1077
|
-
<p class="fg-verify-hint">Verification may take some time</p>
|
|
1078
|
-
<p style="color: rgba(250, 204, 21, 0.85); font-size: 11px; margin:
|
|
1081
|
+
<p class="fg-verify-hint" style="margin-bottom: 32px;">Verification may take some time</p>
|
|
1082
|
+
<p style="color: rgba(250, 204, 21, 0.85); font-size: 11px; margin: 0 0 10px; text-align: center;">Access may be revoked if actions are not completed.</p>
|
|
1079
1083
|
<button class="fg-btn fg-btn-green" id="fg-finish-btn">
|
|
1080
1084
|
${ICONS.check}
|
|
1081
|
-
Got it - Get access
|
|
1085
|
+
Got it - Get access now!
|
|
1082
1086
|
</button>
|
|
1083
1087
|
${hasFollow || hasRepost ? `
|
|
1084
|
-
<p style="color: rgba(255,255,255,0.4); font-size: 11px; margin: 24px 0
|
|
1088
|
+
<p style="color: rgba(255,255,255,0.4); font-size: 11px; margin: 24px 0 0; text-align: center;">Missed something? Open again:</p>
|
|
1085
1089
|
<div class="fg-btn-row">
|
|
1086
1090
|
${hasFollow ? `
|
|
1087
1091
|
<button class="fg-btn fg-btn-secondary" id="fg-redo-follow">
|
|
@@ -1216,9 +1220,6 @@ var FollowGateClient = class {
|
|
|
1216
1220
|
getRepostUrl(platform, target) {
|
|
1217
1221
|
return this.buildIntentUrl({ platform, action: "repost", target });
|
|
1218
1222
|
}
|
|
1219
|
-
getLikeUrl(platform, target) {
|
|
1220
|
-
return this.buildIntentUrl({ platform, action: "like", target });
|
|
1221
|
-
}
|
|
1222
1223
|
async openIntent(options) {
|
|
1223
1224
|
if (!this.config) {
|
|
1224
1225
|
throw new Error("[FollowGate] SDK not initialized. Call init() first.");
|
|
@@ -1497,8 +1498,6 @@ var FollowGateClient = class {
|
|
|
1497
1498
|
return `https://twitter.com/intent/follow?screen_name=${encodeURIComponent(target)}`;
|
|
1498
1499
|
case "repost":
|
|
1499
1500
|
return `https://twitter.com/intent/retweet?tweet_id=${encodeURIComponent(target)}`;
|
|
1500
|
-
case "like":
|
|
1501
|
-
return `https://twitter.com/intent/like?tweet_id=${encodeURIComponent(target)}`;
|
|
1502
1501
|
default:
|
|
1503
1502
|
throw new Error(`[FollowGate] Unsupported Twitter action: ${action}`);
|
|
1504
1503
|
}
|
|
@@ -1509,7 +1508,6 @@ var FollowGateClient = class {
|
|
|
1509
1508
|
case "follow":
|
|
1510
1509
|
return `https://bsky.app/profile/${encodeURIComponent(normalizedTarget)}`;
|
|
1511
1510
|
case "repost":
|
|
1512
|
-
case "like":
|
|
1513
1511
|
if (target.startsWith("at://") || target.includes("/post/")) {
|
|
1514
1512
|
const postPath = target.replace("at://", "").replace("app.bsky.feed.post/", "post/");
|
|
1515
1513
|
return `https://bsky.app/profile/${postPath}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@followgate/js",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.5",
|
|
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",
|