spaps-sdk 0.1.0 → 1.0.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/admin-utils.ts ADDED
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Admin utilities for Sweet Potato
3
+ * These are helper functions for admin operations that require JWT authentication
4
+ * NOT included in main SDK for security reasons
5
+ */
6
+
7
+ export interface WhitelistEntry {
8
+ application_id: string;
9
+ email: string;
10
+ tier: 'basic' | 'premium' | 'enterprise';
11
+ bypass_payment: boolean;
12
+ metadata?: Record<string, any>;
13
+ created_at?: string;
14
+ updated_at?: string;
15
+ }
16
+
17
+ export interface WhitelistClient {
18
+ apiUrl: string;
19
+ apiKey: string;
20
+ adminToken: string;
21
+ }
22
+
23
+ /**
24
+ * Create a whitelist management client
25
+ * Requires admin JWT token from authentication
26
+ */
27
+ export class WhitelistManager {
28
+ private headers: HeadersInit;
29
+
30
+ constructor(private config: WhitelistClient) {
31
+ this.headers = {
32
+ 'Authorization': `Bearer ${config.adminToken}`,
33
+ 'X-API-Key': config.apiKey,
34
+ 'Content-Type': 'application/json'
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Check if email is whitelisted
40
+ */
41
+ async check(email: string): Promise<WhitelistEntry | null> {
42
+ const response = await fetch(
43
+ `${this.config.apiUrl}/api/v1/whitelist/check?email=${encodeURIComponent(email)}`,
44
+ { headers: { 'X-API-Key': this.config.apiKey } }
45
+ );
46
+
47
+ const result = await response.json();
48
+ return result.data?.entry || null;
49
+ }
50
+
51
+ /**
52
+ * Add email to whitelist
53
+ */
54
+ async add(
55
+ email: string,
56
+ tier: 'basic' | 'premium' | 'enterprise' = 'premium',
57
+ options?: {
58
+ bypass_payment?: boolean;
59
+ metadata?: Record<string, any>;
60
+ }
61
+ ): Promise<WhitelistEntry> {
62
+ const response = await fetch(`${this.config.apiUrl}/api/v1/whitelist`, {
63
+ method: 'POST',
64
+ headers: this.headers,
65
+ body: JSON.stringify({
66
+ email,
67
+ tier,
68
+ bypass_payment: options?.bypass_payment ?? true,
69
+ metadata: options?.metadata
70
+ })
71
+ });
72
+
73
+ if (!response.ok) {
74
+ const error = await response.json();
75
+ throw new Error(error.error?.message || 'Failed to add to whitelist');
76
+ }
77
+
78
+ const result = await response.json();
79
+ return result.data.entry;
80
+ }
81
+
82
+ /**
83
+ * Bulk add emails to whitelist
84
+ */
85
+ async bulkAdd(
86
+ emails: Array<{
87
+ email: string;
88
+ tier?: 'basic' | 'premium' | 'enterprise';
89
+ metadata?: Record<string, any>;
90
+ }>
91
+ ): Promise<{
92
+ successful: WhitelistEntry[];
93
+ failed: Array<{ email: string; error: string }>;
94
+ total: number;
95
+ }> {
96
+ const response = await fetch(`${this.config.apiUrl}/api/v1/whitelist/bulk`, {
97
+ method: 'POST',
98
+ headers: this.headers,
99
+ body: JSON.stringify({ emails })
100
+ });
101
+
102
+ const result = await response.json();
103
+ return result.data;
104
+ }
105
+
106
+ /**
107
+ * List whitelisted emails
108
+ */
109
+ async list(options?: {
110
+ limit?: number;
111
+ offset?: number;
112
+ tier?: string;
113
+ }): Promise<{
114
+ entries: WhitelistEntry[];
115
+ total: number;
116
+ }> {
117
+ const params = new URLSearchParams();
118
+ if (options?.limit) params.append('limit', options.limit.toString());
119
+ if (options?.offset) params.append('offset', options.offset.toString());
120
+ if (options?.tier) params.append('tier', options.tier);
121
+
122
+ const response = await fetch(
123
+ `${this.config.apiUrl}/api/v1/whitelist?${params}`,
124
+ { headers: this.headers }
125
+ );
126
+
127
+ const result = await response.json();
128
+ return result.data;
129
+ }
130
+
131
+ /**
132
+ * Update whitelist entry
133
+ */
134
+ async update(
135
+ email: string,
136
+ updates: {
137
+ tier?: 'basic' | 'premium' | 'enterprise';
138
+ bypass_payment?: boolean;
139
+ metadata?: Record<string, any>;
140
+ }
141
+ ): Promise<WhitelistEntry> {
142
+ const response = await fetch(
143
+ `${this.config.apiUrl}/api/v1/whitelist/${encodeURIComponent(email)}`,
144
+ {
145
+ method: 'PUT',
146
+ headers: this.headers,
147
+ body: JSON.stringify(updates)
148
+ }
149
+ );
150
+
151
+ if (!response.ok) {
152
+ const error = await response.json();
153
+ throw new Error(error.error?.message || 'Failed to update whitelist');
154
+ }
155
+
156
+ const result = await response.json();
157
+ return result.data.entry;
158
+ }
159
+
160
+ /**
161
+ * Remove email from whitelist
162
+ */
163
+ async remove(email: string): Promise<void> {
164
+ const response = await fetch(
165
+ `${this.config.apiUrl}/api/v1/whitelist/${encodeURIComponent(email)}`,
166
+ {
167
+ method: 'DELETE',
168
+ headers: this.headers
169
+ }
170
+ );
171
+
172
+ if (!response.ok) {
173
+ const error = await response.json();
174
+ throw new Error(error.error?.message || 'Failed to remove from whitelist');
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Get whitelist statistics
180
+ */
181
+ async getStats(): Promise<{
182
+ enabled: boolean;
183
+ total: number;
184
+ tierBreakdown: Array<{ tier: string; count: number }>;
185
+ }> {
186
+ const response = await fetch(
187
+ `${this.config.apiUrl}/api/v1/whitelist/stats`,
188
+ { headers: this.headers }
189
+ );
190
+
191
+ const result = await response.json();
192
+ return result.data.stats;
193
+ }
194
+
195
+ /**
196
+ * Clear all whitelist entries (use with caution!)
197
+ */
198
+ async clearAll(): Promise<number> {
199
+ const response = await fetch(
200
+ `${this.config.apiUrl}/api/v1/whitelist/all`,
201
+ {
202
+ method: 'DELETE',
203
+ headers: this.headers
204
+ }
205
+ );
206
+
207
+ if (!response.ok) {
208
+ const error = await response.json();
209
+ throw new Error(error.error?.message || 'Failed to clear whitelist');
210
+ }
211
+
212
+ const result = await response.json();
213
+ const match = result.data.message.match(/Cleared (\d+) entries/);
214
+ return match ? parseInt(match[1]) : 0;
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Example usage:
220
+ *
221
+ * ```typescript
222
+ * import { SweetPotatoSDK } from '@sweet-potato/sdk';
223
+ * import { WhitelistManager } from '@sweet-potato/sdk/admin-utils';
224
+ *
225
+ * // First authenticate as admin
226
+ * const sdk = new SweetPotatoSDK({ apiUrl, apiKey });
227
+ * const auth = await sdk.auth.signInWithPassword({
228
+ * email: 'admin@example.com',
229
+ * password: 'admin_password'
230
+ * });
231
+ *
232
+ * // Create whitelist manager
233
+ * const whitelist = new WhitelistManager({
234
+ * apiUrl,
235
+ * apiKey,
236
+ * adminToken: auth.access_token
237
+ * });
238
+ *
239
+ * // Use whitelist operations
240
+ * await whitelist.add('vip@example.com', 'premium');
241
+ * const stats = await whitelist.getStats();
242
+ * ```
243
+ */