@followgate/js 0.5.0 → 0.7.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/README.md +274 -86
- package/dist/index.d.mts +43 -56
- package/dist/index.d.ts +43 -56
- package/dist/index.js +785 -69
- package/dist/index.mjs +785 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,141 +10,336 @@ FollowGate is inspired by [Hypeddit](https://hypeddit.com) (for musicians), but
|
|
|
10
10
|
npm install @followgate/js
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
## Quick Start
|
|
13
|
+
## Quick Start (Built-in Modal)
|
|
14
|
+
|
|
15
|
+
Just 10 lines of code - no custom UI needed:
|
|
14
16
|
|
|
15
17
|
```typescript
|
|
16
18
|
import { FollowGate } from '@followgate/js';
|
|
17
19
|
|
|
18
|
-
// Initialize
|
|
20
|
+
// Initialize once (e.g., in your app's entry point)
|
|
19
21
|
FollowGate.init({
|
|
20
22
|
appId: 'your-app-id',
|
|
21
23
|
apiKey: 'fg_live_xxx',
|
|
24
|
+
twitter: {
|
|
25
|
+
handle: 'your_twitter_handle',
|
|
26
|
+
tweetId: '1234567890', // Optional: require repost
|
|
27
|
+
},
|
|
28
|
+
onComplete: () => {
|
|
29
|
+
// User completed all actions - redirect to your app
|
|
30
|
+
router.push('/dashboard');
|
|
31
|
+
},
|
|
22
32
|
});
|
|
23
33
|
|
|
24
|
-
//
|
|
25
|
-
FollowGate.
|
|
26
|
-
platform: 'twitter',
|
|
27
|
-
action: 'follow',
|
|
28
|
-
target: 'yourusername',
|
|
29
|
-
userId: 'user-123', // Optional: your app's user ID for tracking
|
|
30
|
-
});
|
|
34
|
+
// Show the modal (that's it!)
|
|
35
|
+
FollowGate.show();
|
|
31
36
|
```
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
The SDK renders a beautiful, fully-functional modal with:
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
- Username input step
|
|
41
|
+
- Follow action with intent URL
|
|
42
|
+
- Repost action (optional)
|
|
43
|
+
- Confirmation step
|
|
44
|
+
- All styling included (no CSS needed)
|
|
40
45
|
|
|
41
|
-
##
|
|
46
|
+
## When to Show the Modal
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
```typescript
|
|
49
|
+
// After sign-up (recommended)
|
|
50
|
+
const handleSignUpSuccess = () => {
|
|
51
|
+
FollowGate.show();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Or check if already unlocked
|
|
55
|
+
if (!FollowGate.isUnlocked()) {
|
|
56
|
+
FollowGate.show();
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Handling Success (Important!)
|
|
44
61
|
|
|
45
|
-
|
|
62
|
+
**The `onComplete` callback is called ONLY after the user successfully completes all required actions.** This is the right place to:
|
|
63
|
+
|
|
64
|
+
- Create the user account in your database
|
|
65
|
+
- Grant access to premium features
|
|
66
|
+
- Redirect to your app
|
|
46
67
|
|
|
47
68
|
```typescript
|
|
48
69
|
FollowGate.init({
|
|
49
|
-
appId: 'your-app-id',
|
|
50
|
-
apiKey: 'fg_live_xxx',
|
|
51
|
-
|
|
52
|
-
|
|
70
|
+
appId: 'your-app-id',
|
|
71
|
+
apiKey: 'fg_live_xxx',
|
|
72
|
+
twitter: { handle: 'your_handle' },
|
|
73
|
+
|
|
74
|
+
onComplete: async () => {
|
|
75
|
+
// ✅ User completed all steps - NOW create the account!
|
|
76
|
+
const user = FollowGate.getUser();
|
|
77
|
+
|
|
78
|
+
await fetch('/api/create-account', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: { 'Content-Type': 'application/json' },
|
|
81
|
+
body: JSON.stringify({
|
|
82
|
+
xUsername: user?.username, // Their X/Twitter username
|
|
83
|
+
platform: user?.platform, // 'twitter'
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Then redirect to your app
|
|
88
|
+
router.push('/dashboard');
|
|
89
|
+
},
|
|
53
90
|
});
|
|
54
91
|
```
|
|
55
92
|
|
|
56
|
-
|
|
93
|
+
**Why this matters:** Don't create accounts before `onComplete` is called. Users might close the modal without completing the actions. Only when `onComplete` fires, you know they actually followed/reposted.
|
|
57
94
|
|
|
58
|
-
|
|
95
|
+
### Event Listeners for Fine-Grained Control
|
|
59
96
|
|
|
60
97
|
```typescript
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
// Fired when a SINGLE action is completed (follow OR repost)
|
|
99
|
+
FollowGate.on('complete', (data) => {
|
|
100
|
+
console.log('Action completed:', data);
|
|
101
|
+
// { platform: 'twitter', action: 'follow', target: 'your_handle', username: 'their_username' }
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Fired when ALL actions are completed (same timing as onComplete)
|
|
105
|
+
FollowGate.on('unlocked', (data) => {
|
|
106
|
+
console.log('Gate unlocked:', data);
|
|
107
|
+
// { username: 'their_username', actions: [{ platform, action, target }, ...] }
|
|
66
108
|
});
|
|
67
109
|
```
|
|
68
110
|
|
|
69
|
-
|
|
111
|
+
## Configuration Options
|
|
70
112
|
|
|
71
|
-
|
|
113
|
+
```typescript
|
|
114
|
+
FollowGate.init({
|
|
115
|
+
// Required
|
|
116
|
+
appId: 'your-app-id', // Your App ID from the dashboard
|
|
117
|
+
apiKey: 'fg_live_xxx', // Your API key (starts with fg_live_ or fg_test_)
|
|
118
|
+
|
|
119
|
+
// Twitter/X Configuration
|
|
120
|
+
twitter: {
|
|
121
|
+
handle: 'your_handle', // Your Twitter username (without @)
|
|
122
|
+
tweetId: '1234567890', // Tweet ID to repost (optional)
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Callback when user completes all actions
|
|
126
|
+
onComplete: () => {
|
|
127
|
+
// Called after the user finishes all steps and clicks "Got it"
|
|
128
|
+
// Typically used to redirect to your app
|
|
129
|
+
router.push('/dashboard');
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// Optional
|
|
133
|
+
userId: 'clerk_user_123', // User ID for per-user unlock status (recommended with auth)
|
|
134
|
+
debug: false, // Enable console logging for debugging
|
|
135
|
+
accentColor: '#6366f1', // Customize primary button color (hex)
|
|
136
|
+
theme: 'dark', // 'dark' | 'light' - modal appearance
|
|
137
|
+
apiUrl: 'https://...', // Custom API URL (for self-hosted)
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Handle & Target Formats
|
|
142
|
+
|
|
143
|
+
The SDK automatically normalizes usernames - you can use `@username` or `username`, both work:
|
|
144
|
+
|
|
145
|
+
| Platform | Action | Target Format | Example |
|
|
146
|
+
| ------------ | ------ | ----------------------------------- | ------------------------------------ |
|
|
147
|
+
| **Twitter** | follow | Username (without @) | `lukasvanuden` |
|
|
148
|
+
| **Twitter** | repost | Tweet ID (numbers only) | `1234567890123456789` |
|
|
149
|
+
| **Twitter** | like | Tweet ID (numbers only) | `1234567890123456789` |
|
|
150
|
+
| **Bluesky** | follow | Handle (with or without @) | `user.bsky.social` |
|
|
151
|
+
| **Bluesky** | repost | AT URI or post path | `user.bsky.social/post/xyz` |
|
|
152
|
+
| **LinkedIn** | follow | Company name or prefixed identifier | `company:anthropic` or `in:username` |
|
|
153
|
+
|
|
154
|
+
**Tip:** For Twitter, you can find the Tweet ID in the URL: `https://x.com/user/status/1234567890123456789`
|
|
155
|
+
|
|
156
|
+
## API Reference
|
|
157
|
+
|
|
158
|
+
### Modal Methods
|
|
72
159
|
|
|
73
160
|
```typescript
|
|
74
|
-
|
|
161
|
+
// Show the FollowGate modal
|
|
162
|
+
// If user is already unlocked, calls onComplete immediately
|
|
163
|
+
FollowGate.show();
|
|
164
|
+
|
|
165
|
+
// Hide the modal programmatically
|
|
166
|
+
FollowGate.hide();
|
|
167
|
+
|
|
168
|
+
// Check if user has completed all actions
|
|
169
|
+
FollowGate.isUnlocked(); // true | false
|
|
170
|
+
|
|
171
|
+
// Reset user's session (for testing)
|
|
172
|
+
FollowGate.reset();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Advanced Usage
|
|
176
|
+
|
|
177
|
+
For custom UI implementations (when you don't want to use the built-in modal):
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Set username manually (@ is automatically removed)
|
|
181
|
+
FollowGate.setUsername('your_username'); // or '@your_username' - both work!
|
|
182
|
+
|
|
183
|
+
// Check if username is set
|
|
184
|
+
FollowGate.hasUsername(); // true | false
|
|
185
|
+
|
|
186
|
+
// Open intent URLs directly (opens in new window)
|
|
187
|
+
// For follow: target = username (without @)
|
|
188
|
+
await FollowGate.openIntent({
|
|
75
189
|
platform: 'twitter',
|
|
76
190
|
action: 'follow',
|
|
77
|
-
target: '
|
|
78
|
-
|
|
191
|
+
target: 'lukasvanuden', // NOT @lukasvanuden
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// For repost: target = tweet ID
|
|
195
|
+
await FollowGate.openIntent({
|
|
196
|
+
platform: 'twitter',
|
|
197
|
+
action: 'repost',
|
|
198
|
+
target: '1234567890123456789', // Tweet ID from URL
|
|
79
199
|
});
|
|
80
|
-
```
|
|
81
200
|
|
|
82
|
-
|
|
201
|
+
// Mark action as completed (tracks locally + sends to API)
|
|
202
|
+
await FollowGate.complete({
|
|
203
|
+
platform: 'twitter',
|
|
204
|
+
action: 'follow',
|
|
205
|
+
target: 'lukasvanuden',
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Mark gate as unlocked (user has completed all required actions)
|
|
209
|
+
await FollowGate.unlock();
|
|
210
|
+
|
|
211
|
+
// Get current user info
|
|
212
|
+
FollowGate.getUser();
|
|
213
|
+
// Returns: { username: 'their_username', platform: 'twitter' } | null
|
|
214
|
+
|
|
215
|
+
// Get completed actions
|
|
216
|
+
FollowGate.getCompletedActions();
|
|
217
|
+
// Returns: [{ platform: 'twitter', action: 'follow', target: 'lukasvanuden' }, ...]
|
|
218
|
+
|
|
219
|
+
// Get full unlock status
|
|
220
|
+
FollowGate.getUnlockStatus();
|
|
221
|
+
// Returns: {
|
|
222
|
+
// unlocked: boolean,
|
|
223
|
+
// username?: string,
|
|
224
|
+
// completedActions?: CompleteOptions[]
|
|
225
|
+
// }
|
|
226
|
+
```
|
|
83
227
|
|
|
84
|
-
|
|
228
|
+
### Event Listeners
|
|
85
229
|
|
|
86
230
|
```typescript
|
|
87
231
|
FollowGate.on('complete', (data) => {
|
|
88
|
-
console.log('
|
|
89
|
-
|
|
232
|
+
console.log('Action completed:', data);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
FollowGate.on('unlocked', (data) => {
|
|
236
|
+
console.log('Gate unlocked:', data);
|
|
90
237
|
});
|
|
91
238
|
|
|
92
239
|
FollowGate.on('error', (error) => {
|
|
93
240
|
console.error('Error:', error);
|
|
94
241
|
});
|
|
242
|
+
|
|
243
|
+
// Remove listener
|
|
244
|
+
FollowGate.off('complete', handler);
|
|
95
245
|
```
|
|
96
246
|
|
|
97
|
-
##
|
|
247
|
+
## Supported Platforms
|
|
98
248
|
|
|
99
|
-
|
|
249
|
+
| Platform | Actions |
|
|
250
|
+
| --------- | -------------------------- |
|
|
251
|
+
| Twitter/X | `follow`, `repost`, `like` |
|
|
252
|
+
| Bluesky | `follow`, `repost`, `like` |
|
|
253
|
+
| LinkedIn | `follow` |
|
|
100
254
|
|
|
101
|
-
|
|
102
|
-
|
|
255
|
+
## Framework Examples
|
|
256
|
+
|
|
257
|
+
### Next.js (App Router)
|
|
103
258
|
|
|
104
259
|
```typescript
|
|
105
|
-
//
|
|
106
|
-
|
|
260
|
+
// app/welcome/page.tsx
|
|
261
|
+
'use client';
|
|
107
262
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
263
|
+
import { FollowGate } from '@followgate/js';
|
|
264
|
+
import { useRouter } from 'next/navigation';
|
|
265
|
+
import { useEffect } from 'react';
|
|
266
|
+
|
|
267
|
+
export default function WelcomePage() {
|
|
268
|
+
const router = useRouter();
|
|
269
|
+
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
FollowGate.init({
|
|
272
|
+
appId: process.env.NEXT_PUBLIC_FOLLOWGATE_APP_ID!,
|
|
273
|
+
apiKey: process.env.NEXT_PUBLIC_FOLLOWGATE_API_KEY!,
|
|
274
|
+
twitter: { handle: 'your_handle' },
|
|
275
|
+
onComplete: () => router.push('/dashboard'),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Show modal if not already unlocked
|
|
279
|
+
if (!FollowGate.isUnlocked()) {
|
|
280
|
+
FollowGate.show();
|
|
281
|
+
} else {
|
|
282
|
+
router.push('/dashboard');
|
|
283
|
+
}
|
|
284
|
+
}, [router]);
|
|
285
|
+
|
|
286
|
+
return <div>Loading...</div>;
|
|
287
|
+
}
|
|
114
288
|
```
|
|
115
289
|
|
|
116
|
-
###
|
|
117
|
-
|
|
118
|
-
- `target` for `follow`: Bluesky handle (e.g., `alice.bsky.social`)
|
|
119
|
-
- `target` for `repost`/`like`: Post path (e.g., `alice.bsky.social/post/xxx`)
|
|
290
|
+
### With Clerk Auth
|
|
120
291
|
|
|
121
292
|
```typescript
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
293
|
+
// app/welcome/page.tsx
|
|
294
|
+
'use client';
|
|
295
|
+
|
|
296
|
+
import { FollowGate } from '@followgate/js';
|
|
297
|
+
import { useRouter } from 'next/navigation';
|
|
298
|
+
import { useUser } from '@clerk/nextjs';
|
|
299
|
+
import { useEffect } from 'react';
|
|
300
|
+
|
|
301
|
+
export default function WelcomePage() {
|
|
302
|
+
const router = useRouter();
|
|
303
|
+
const { user } = useUser();
|
|
304
|
+
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
if (!user) return;
|
|
307
|
+
|
|
308
|
+
FollowGate.init({
|
|
309
|
+
appId: process.env.NEXT_PUBLIC_FOLLOWGATE_APP_ID!,
|
|
310
|
+
apiKey: process.env.NEXT_PUBLIC_FOLLOWGATE_API_KEY!,
|
|
311
|
+
userId: user.id, // Per-user unlock status (recommended!)
|
|
312
|
+
twitter: { handle: 'lukasvanuden' },
|
|
313
|
+
onComplete: () => router.push('/dashboard'),
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
if (!FollowGate.isUnlocked()) {
|
|
317
|
+
FollowGate.show();
|
|
318
|
+
} else {
|
|
319
|
+
router.push('/dashboard');
|
|
320
|
+
}
|
|
321
|
+
}, [user, router]);
|
|
322
|
+
|
|
323
|
+
return <div>Loading...</div>;
|
|
324
|
+
}
|
|
128
325
|
```
|
|
129
326
|
|
|
130
|
-
|
|
327
|
+
**Why use `userId`?** Without it, unlock status is stored per-browser. If User A completes the gate on a shared computer, User B would also be "unlocked". With `userId`, each user has their own unlock status.
|
|
131
328
|
|
|
132
|
-
|
|
329
|
+
## TypeScript
|
|
133
330
|
|
|
134
|
-
|
|
135
|
-
// Follow a company
|
|
136
|
-
FollowGate.open({
|
|
137
|
-
platform: 'linkedin',
|
|
138
|
-
action: 'follow',
|
|
139
|
-
target: 'microsoft',
|
|
140
|
-
});
|
|
331
|
+
Full TypeScript support included:
|
|
141
332
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
333
|
+
```typescript
|
|
334
|
+
import type {
|
|
335
|
+
Platform,
|
|
336
|
+
SocialAction,
|
|
337
|
+
FollowGateConfig,
|
|
338
|
+
TwitterConfig,
|
|
339
|
+
CompleteOptions,
|
|
340
|
+
UserInfo,
|
|
341
|
+
UnlockStatus,
|
|
342
|
+
} from '@followgate/js';
|
|
148
343
|
```
|
|
149
344
|
|
|
150
345
|
## Pricing
|
|
@@ -156,19 +351,12 @@ FollowGate.open({
|
|
|
156
351
|
| Pro | $49/mo | 2,000 | OAuth verification |
|
|
157
352
|
| Business | $99/mo | 5,000+ | Daily verification |
|
|
158
353
|
|
|
159
|
-
## TypeScript
|
|
160
|
-
|
|
161
|
-
Full TypeScript support included. Types are exported:
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
import type { Platform, SocialAction, FollowGateConfig } from '@followgate/js';
|
|
165
|
-
```
|
|
166
|
-
|
|
167
354
|
## Links
|
|
168
355
|
|
|
169
|
-
- [Dashboard](https://
|
|
170
|
-
- [Documentation](https://followgate.
|
|
356
|
+
- [Dashboard](https://followgate.app)
|
|
357
|
+
- [Documentation](https://docs.followgate.app)
|
|
171
358
|
- [GitHub](https://github.com/JustFF5/FollowGate)
|
|
359
|
+
- [Live Demo](https://follow-gate-web-demo.vercel.app)
|
|
172
360
|
|
|
173
361
|
## License
|
|
174
362
|
|
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,13 @@ type Platform = 'twitter' | 'bluesky' | 'linkedin';
|
|
|
6
6
|
* Supported social actions
|
|
7
7
|
*/
|
|
8
8
|
type SocialAction = 'follow' | 'repost' | 'like';
|
|
9
|
+
/**
|
|
10
|
+
* Twitter/X configuration
|
|
11
|
+
*/
|
|
12
|
+
interface TwitterConfig {
|
|
13
|
+
handle: string;
|
|
14
|
+
tweetId?: string;
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* SDK Configuration
|
|
11
18
|
*/
|
|
@@ -14,6 +21,11 @@ interface FollowGateConfig {
|
|
|
14
21
|
apiKey: string;
|
|
15
22
|
apiUrl?: string;
|
|
16
23
|
debug?: boolean;
|
|
24
|
+
userId?: string;
|
|
25
|
+
twitter?: TwitterConfig;
|
|
26
|
+
onComplete?: () => void;
|
|
27
|
+
theme?: 'dark' | 'light';
|
|
28
|
+
accentColor?: string;
|
|
17
29
|
}
|
|
18
30
|
/**
|
|
19
31
|
* SDK Error class with helpful messages
|
|
@@ -56,28 +68,45 @@ interface UnlockStatus {
|
|
|
56
68
|
}
|
|
57
69
|
/**
|
|
58
70
|
* FollowGate SDK Client
|
|
59
|
-
*
|
|
60
|
-
* Simple username-based flow:
|
|
61
|
-
* 1. User enters username
|
|
62
|
-
* 2. User clicks intent URLs to follow/repost
|
|
63
|
-
* 3. User confirms they did it
|
|
64
|
-
* 4. App is unlocked
|
|
65
|
-
*
|
|
66
|
-
* No OAuth required!
|
|
67
71
|
*/
|
|
68
72
|
declare class FollowGateClient {
|
|
69
73
|
private config;
|
|
70
74
|
private listeners;
|
|
71
75
|
private currentUser;
|
|
72
76
|
private completedActions;
|
|
77
|
+
private modalElement;
|
|
78
|
+
private stylesInjected;
|
|
73
79
|
/**
|
|
74
80
|
* Initialize the SDK
|
|
75
|
-
* @throws {FollowGateError} If configuration is invalid
|
|
76
81
|
*/
|
|
77
82
|
init(config: FollowGateConfig): void;
|
|
83
|
+
/**
|
|
84
|
+
* Show the FollowGate modal
|
|
85
|
+
* If user is already unlocked, calls onComplete immediately
|
|
86
|
+
*/
|
|
87
|
+
show(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Hide the modal
|
|
90
|
+
*/
|
|
91
|
+
hide(): void;
|
|
92
|
+
private injectStyles;
|
|
93
|
+
private createModal;
|
|
94
|
+
private getContentElement;
|
|
95
|
+
private renderUsernameStep;
|
|
96
|
+
private handleUsernameSubmit;
|
|
97
|
+
private renderFollowStep;
|
|
98
|
+
private handleFollowClick;
|
|
99
|
+
private showFollowConfirmation;
|
|
100
|
+
private handleFollowConfirm;
|
|
101
|
+
private renderRepostStep;
|
|
102
|
+
private handleRepostClick;
|
|
103
|
+
private showRepostConfirmation;
|
|
104
|
+
private handleRepostConfirm;
|
|
105
|
+
private renderConfirmStep;
|
|
106
|
+
private handleFinish;
|
|
107
|
+
private renderStepIndicator;
|
|
78
108
|
/**
|
|
79
109
|
* Set the user's social username
|
|
80
|
-
* This is the main entry point - no OAuth needed!
|
|
81
110
|
*/
|
|
82
111
|
setUsername(username: string, platform?: Platform): void;
|
|
83
112
|
/**
|
|
@@ -92,73 +121,31 @@ declare class FollowGateClient {
|
|
|
92
121
|
* Clear stored session
|
|
93
122
|
*/
|
|
94
123
|
reset(): void;
|
|
95
|
-
/**
|
|
96
|
-
* Get follow intent URL for a platform
|
|
97
|
-
*/
|
|
98
124
|
getFollowUrl(platform: Platform, target: string): string;
|
|
99
|
-
/**
|
|
100
|
-
* Get repost/retweet intent URL for a platform
|
|
101
|
-
*/
|
|
102
125
|
getRepostUrl(platform: Platform, target: string): string;
|
|
103
|
-
/**
|
|
104
|
-
* Get like intent URL for a platform
|
|
105
|
-
*/
|
|
106
126
|
getLikeUrl(platform: Platform, target: string): string;
|
|
107
|
-
/**
|
|
108
|
-
* Open intent URL in new window
|
|
109
|
-
*/
|
|
110
127
|
openIntent(options: CompleteOptions): Promise<void>;
|
|
111
|
-
/**
|
|
112
|
-
* Mark an action as completed (trust-first)
|
|
113
|
-
* Call this when user confirms they did the action
|
|
114
|
-
*/
|
|
115
128
|
complete(options: CompleteOptions): Promise<void>;
|
|
116
|
-
/**
|
|
117
|
-
* Mark the gate as unlocked
|
|
118
|
-
* Call this when all required actions are done
|
|
119
|
-
*/
|
|
120
129
|
unlock(): Promise<void>;
|
|
121
|
-
/**
|
|
122
|
-
* Check if gate is unlocked
|
|
123
|
-
*/
|
|
124
130
|
isUnlocked(): boolean;
|
|
125
|
-
/**
|
|
126
|
-
* Get unlock status with details
|
|
127
|
-
*/
|
|
128
131
|
getUnlockStatus(): UnlockStatus;
|
|
129
|
-
/**
|
|
130
|
-
* Get completed actions
|
|
131
|
-
*/
|
|
132
132
|
getCompletedActions(): CompleteOptions[];
|
|
133
|
-
/**
|
|
134
|
-
* Register event listener
|
|
135
|
-
*/
|
|
136
133
|
on(event: EventType, callback: EventCallback): void;
|
|
137
|
-
/**
|
|
138
|
-
* Remove event listener
|
|
139
|
-
*/
|
|
140
134
|
off(event: EventType, callback: EventCallback): void;
|
|
141
135
|
/**
|
|
142
|
-
*
|
|
136
|
+
* Get storage key with optional userId suffix
|
|
137
|
+
* This ensures unlock status is per-user, not per-browser
|
|
143
138
|
*/
|
|
139
|
+
private getStorageKey;
|
|
144
140
|
private restoreSession;
|
|
145
|
-
/**
|
|
146
|
-
* Save completed actions to localStorage
|
|
147
|
-
*/
|
|
148
141
|
private saveCompletedActions;
|
|
149
|
-
/**
|
|
150
|
-
* Build intent URL for platform
|
|
151
|
-
*/
|
|
152
142
|
private buildIntentUrl;
|
|
153
143
|
private buildTwitterUrl;
|
|
154
144
|
private buildBlueskyUrl;
|
|
155
145
|
private buildLinkedInUrl;
|
|
156
|
-
/**
|
|
157
|
-
* Track analytics event
|
|
158
|
-
*/
|
|
159
146
|
private trackEvent;
|
|
160
147
|
private emit;
|
|
161
148
|
}
|
|
162
149
|
declare const FollowGate: FollowGateClient;
|
|
163
150
|
|
|
164
|
-
export { type CompleteOptions, type EventCallback, type EventType, FollowGate, FollowGateClient, type FollowGateConfig, FollowGateError, type Platform, type SocialAction, type UnlockStatus, type UserInfo };
|
|
151
|
+
export { type CompleteOptions, type EventCallback, type EventType, FollowGate, FollowGateClient, type FollowGateConfig, FollowGateError, type Platform, type SocialAction, type TwitterConfig, type UnlockStatus, type UserInfo };
|