spaps-sdk 1.6.1 โ†’ 1.6.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ - No changes yet.
10
+
11
+ ## [1.6.2] - 2026-03-29
12
+
13
+ ### Added
14
+
15
+ - Added canonical issue-reporting client methods for end-user create, list, detail, status, update, and reply flows.
16
+
17
+ ## [1.6.1] - 2026-02-16
18
+
19
+ ### Fixed
20
+
21
+ - Made the SDK `tsconfig` self-contained after root-config removal.
22
+ - Restored API-key header injection behavior for axios v1+ interceptor semantics.
23
+
24
+ ## [1.6.0] - 2026-02-14
25
+
26
+ ### Added
27
+
28
+ - CFO roles, `company_id`, and affiliate-referral domain support.
29
+
30
+ ### Changed
31
+
32
+ - Consolidated SPAPS integration patterns into published SDK packages.
33
+
34
+ ## [1.5.1] - 2026-02-11
35
+
36
+ ### Changed
37
+
38
+ - Standardized local/dev config defaults, including port `3301`.
39
+
40
+ ## [1.5.0] - 2026-01-10
41
+
42
+ ### Added
43
+
44
+ - Set-password endpoint support for authenticated users.
45
+
46
+ ## [1.4.0] - 2026-01-10
47
+
48
+ ### Added
49
+
50
+ - Email service integration with Mailgun support.
51
+
52
+ ## [1.2.1] - 2025-12-31
53
+
54
+ ### Added
55
+
56
+ - Stripe webhook admin tooling for entitlement operations.
57
+ - CFO auth integration helpers.
58
+
59
+ ## [1.1.52] - 2025-10-15
60
+
61
+ ### Fixed
62
+
63
+ - Build and type-export stability across iterative CI packaging fixes.
64
+
65
+ ## [1.1.0] - 2025-10-12
66
+
67
+ ### Added
68
+
69
+ - Admin API methods for Stripe product/price management and sync flows.
70
+ - Built-in permission utilities: `isAdminAccount`, `canAccessAdmin`, `getUserRole`.
71
+
72
+ ### Changed
73
+
74
+ - Subsequent patch iterations through `1.1.52` focused on CI and type-export stabilization.
75
+
76
+ ## [1.0.0] - 2025-10-08
77
+
78
+ ### Added
79
+
80
+ - Initial npm release as `spaps-sdk`.
81
+ - Zero-config client for SPAPS auth, payments, and permission checks.
82
+ - Local-mode auto-detection (`localhost`/`127.0.0.1`).
83
+ - Email/password, wallet, and magic-link authentication flows.
84
+ - Stripe checkout helpers with legal-consent support.
85
+ - Usage tracking and secure messaging helpers.
86
+ - TypeScript definitions with CJS/ESM dual exports.
87
+ - Node/browser/Next.js/React Native compatibility.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sweet Potato Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/PERMISSIONS.md ADDED
@@ -0,0 +1,390 @@
1
+ # ๐Ÿ” SPAPS SDK Permission Utilities
2
+
3
+ Client-side permission checking and role management utilities for SPAPS applications.
4
+
5
+ ## ๐Ÿš€ Quick Start
6
+
7
+ ```typescript
8
+ import {
9
+ isAdminAccount,
10
+ getUserRole,
11
+ hasPermission,
12
+ canAccessAdmin,
13
+ PermissionChecker,
14
+ createPermissionChecker
15
+ } from 'spaps-sdk';
16
+
17
+ // Check if user is admin
18
+ const isAdmin = isAdminAccount('buildooor@gmail.com'); // true
19
+
20
+ // Get user role
21
+ const role = getUserRole('user@example.com'); // 'user' | 'admin' | 'guest'
22
+
23
+ // Check admin access
24
+ const adminCheck = canAccessAdmin(user);
25
+ if (adminCheck.allowed) {
26
+ // Show admin features
27
+ }
28
+
29
+ // Check specific permissions
30
+ const canEdit = hasPermission(user, 'edit');
31
+ const canManage = hasPermission(user, ['create', 'delete']);
32
+ ```
33
+
34
+ ## ๐Ÿ“‹ Default Admin Accounts
35
+
36
+ ```typescript
37
+ const DEFAULT_ADMIN_ACCOUNTS = {
38
+ email: 'buildooor@gmail.com',
39
+ wallets: {
40
+ ethereum: '0xa72bb7CeF1e4B2Cc144373d8dE0Add7CCc8DF4Ba',
41
+ solana: 'HVEbdiYU3Rr34NHBSgKs7q8cvdTeZLqNL77Z1FB2vjLy'
42
+ }
43
+ };
44
+ ```
45
+
46
+ ## ๐ŸŽฏ React Component Examples
47
+
48
+ ### Admin Button with Permission Checking
49
+
50
+ ```tsx
51
+ import React from 'react';
52
+ import { canAccessAdmin, getUserDisplay } from 'spaps-sdk';
53
+
54
+ interface AdminButtonProps {
55
+ user: User | null;
56
+ onClick: () => void;
57
+ }
58
+
59
+ export function AdminButton({ user, onClick }: AdminButtonProps) {
60
+ const permissionCheck = canAccessAdmin(user);
61
+ const userDisplay = getUserDisplay(user);
62
+
63
+ if (!permissionCheck.allowed) {
64
+ return (
65
+ <button
66
+ disabled
67
+ title={permissionCheck.reason}
68
+ className="btn-disabled"
69
+ >
70
+ Admin Panel
71
+ </button>
72
+ );
73
+ }
74
+
75
+ return (
76
+ <button onClick={onClick} className="btn-primary">
77
+ {userDisplay.badge} Admin Panel
78
+ </button>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ### Protected Route Component
84
+
85
+ ```tsx
86
+ import React from 'react';
87
+ import { canAccessAdmin, getRoleAwareErrorMessage } from 'spaps-sdk';
88
+
89
+ interface ProtectedRouteProps {
90
+ user: User | null;
91
+ children: React.ReactNode;
92
+ }
93
+
94
+ export function AdminRoute({ user, children }: ProtectedRouteProps) {
95
+ const permissionCheck = canAccessAdmin(user);
96
+
97
+ if (!permissionCheck.allowed) {
98
+ const errorMessage = getRoleAwareErrorMessage(
99
+ 'admin',
100
+ permissionCheck.userRole,
101
+ 'access this page'
102
+ );
103
+
104
+ return (
105
+ <div className="error-container">
106
+ <h2>Access Denied</h2>
107
+ <p>{errorMessage}</p>
108
+ </div>
109
+ );
110
+ }
111
+
112
+ return <>{children}</>;
113
+ }
114
+ ```
115
+
116
+ ### User Display with Role Badge
117
+
118
+ ```tsx
119
+ import React from 'react';
120
+ import { getUserDisplay } from 'spaps-sdk';
121
+
122
+ export function UserProfile({ user }: { user: User | null }) {
123
+ const display = getUserDisplay(user);
124
+
125
+ return (
126
+ <div className="user-profile">
127
+ <span>{display.displayName}</span>
128
+ {display.badge && (
129
+ <span className="role-badge">{display.badge}</span>
130
+ )}
131
+ <span className="role-text">({display.role})</span>
132
+ </div>
133
+ );
134
+ }
135
+ ```
136
+
137
+ ## ๐Ÿ› ๏ธ Advanced Usage
138
+
139
+ ### Custom Permission Checker
140
+
141
+ ```typescript
142
+ import { createPermissionChecker } from 'spaps-sdk';
143
+
144
+ // Create checker with custom admin accounts
145
+ const customAdmins = [
146
+ 'admin@mycompany.com',
147
+ '0x1234567890abcdef...',
148
+ {
149
+ email: 'ceo@company.com',
150
+ wallets: {
151
+ ethereum: '0xabcdef...',
152
+ solana: 'ABC123...'
153
+ }
154
+ }
155
+ ];
156
+
157
+ const checker = createPermissionChecker(customAdmins);
158
+
159
+ // Use the checker
160
+ const isAdmin = checker.isAdmin('admin@mycompany.com'); // true
161
+ const userDisplay = checker.getUserDisplay(user);
162
+ const canAccess = checker.canAccessAdmin(user);
163
+ ```
164
+
165
+ ### Permission-Based UI Rendering
166
+
167
+ ```tsx
168
+ import React from 'react';
169
+ import { hasPermission, PermissionChecker } from 'spaps-sdk';
170
+
171
+ const checker = new PermissionChecker();
172
+
173
+ function Dashboard({ user }: { user: User | null }) {
174
+ return (
175
+ <div>
176
+ <h1>Dashboard</h1>
177
+
178
+ {/* Show admin panel for admins only */}
179
+ {!checker.requiresAdmin(user) && (
180
+ <AdminPanel />
181
+ )}
182
+
183
+ {/* Show billing section for users with billing permission */}
184
+ {hasPermission(user, 'billing') && (
185
+ <BillingSection />
186
+ )}
187
+
188
+ {/* Show different content based on role */}
189
+ {checker.getRole(user?.email) === 'admin' ? (
190
+ <AdminDashboard />
191
+ ) : (
192
+ <UserDashboard />
193
+ )}
194
+ </div>
195
+ );
196
+ }
197
+ ```
198
+
199
+ ### Form with Permission Validation
200
+
201
+ ```tsx
202
+ import React, { useState } from 'react';
203
+ import { hasPermission, getRoleAwareErrorMessage } from 'spaps-sdk';
204
+
205
+ function ProductForm({ user }: { user: User | null }) {
206
+ const [product, setProduct] = useState({ name: '', price: '' });
207
+ const canCreate = hasPermission(user, 'create');
208
+
209
+ const handleSubmit = (e: React.FormEvent) => {
210
+ e.preventDefault();
211
+
212
+ if (!canCreate) {
213
+ const errorMessage = getRoleAwareErrorMessage(
214
+ 'permission',
215
+ user ? 'user' : 'guest',
216
+ 'create products'
217
+ );
218
+ alert(errorMessage);
219
+ return;
220
+ }
221
+
222
+ // Submit product
223
+ createProduct(product);
224
+ };
225
+
226
+ return (
227
+ <form onSubmit={handleSubmit}>
228
+ <input
229
+ value={product.name}
230
+ onChange={(e) => setProduct({ ...product, name: e.target.value })}
231
+ placeholder="Product name"
232
+ />
233
+ <input
234
+ value={product.price}
235
+ onChange={(e) => setProduct({ ...product, price: e.target.value })}
236
+ placeholder="Price"
237
+ />
238
+ <button
239
+ type="submit"
240
+ disabled={!canCreate}
241
+ title={!canCreate ? 'Insufficient permissions' : undefined}
242
+ >
243
+ {canCreate ? 'Create Product' : 'Create Product (No Permission)'}
244
+ </button>
245
+ </form>
246
+ );
247
+ }
248
+ ```
249
+
250
+ ## ๐Ÿงช Testing Examples
251
+
252
+ ```typescript
253
+ import {
254
+ isAdminAccount,
255
+ getUserRole,
256
+ canAccessAdmin,
257
+ createPermissionChecker
258
+ } from 'spaps-sdk';
259
+
260
+ describe('Permission Utilities', () => {
261
+ describe('isAdminAccount', () => {
262
+ it('should recognize default admin accounts', () => {
263
+ expect(isAdminAccount('buildooor@gmail.com')).toBe(true);
264
+ expect(isAdminAccount('0xa72bb7CeF1e4B2Cc144373d8dE0Add7CCc8DF4Ba')).toBe(true);
265
+ expect(isAdminAccount('user@example.com')).toBe(false);
266
+ });
267
+
268
+ it('should recognize custom admin accounts', () => {
269
+ const customAdmins = ['admin@test.com'];
270
+ expect(isAdminAccount('admin@test.com', customAdmins)).toBe(true);
271
+ expect(isAdminAccount('user@test.com', customAdmins)).toBe(false);
272
+ });
273
+ });
274
+
275
+ describe('getUserRole', () => {
276
+ it('should return correct roles', () => {
277
+ expect(getUserRole('buildooor@gmail.com')).toBe('admin');
278
+ expect(getUserRole('user@example.com')).toBe('user');
279
+ expect(getUserRole()).toBe('guest');
280
+ });
281
+ });
282
+
283
+ describe('canAccessAdmin', () => {
284
+ it('should check admin access correctly', () => {
285
+ const adminUser = { id: '1', email: 'buildooor@gmail.com' };
286
+ const regularUser = { id: '2', email: 'user@example.com' };
287
+
288
+ expect(canAccessAdmin(adminUser).allowed).toBe(true);
289
+ expect(canAccessAdmin(regularUser).allowed).toBe(false);
290
+ expect(canAccessAdmin(null).allowed).toBe(false);
291
+ });
292
+ });
293
+
294
+ describe('PermissionChecker', () => {
295
+ it('should work with custom admins', () => {
296
+ const checker = createPermissionChecker(['admin@test.com']);
297
+
298
+ expect(checker.isAdmin('admin@test.com')).toBe(true);
299
+ expect(checker.getRole('admin@test.com')).toBe('admin');
300
+ expect(checker.canAccessAdmin({
301
+ id: '1',
302
+ email: 'admin@test.com'
303
+ }).allowed).toBe(true);
304
+ });
305
+ });
306
+ });
307
+ ```
308
+
309
+ ## ๐Ÿ“š API Reference
310
+
311
+ ### Core Functions
312
+
313
+ #### `isAdminAccount(identifier: string, customAdmins?: AdminConfig[]): boolean`
314
+ Check if an identifier (email/wallet) is an admin account.
315
+
316
+ #### `getUserRole(identifier?: string, customAdmins?: AdminConfig[]): string`
317
+ Get user role: 'admin', 'user', or 'guest'.
318
+
319
+ #### `hasPermission(user: User | null, permissions: string | string[], customAdmins?: AdminConfig[]): boolean`
320
+ Check if user has specific permissions.
321
+
322
+ #### `canAccessAdmin(user: User | null, customAdmins?: AdminConfig[]): PermissionCheckResult`
323
+ Check if user can access admin features.
324
+
325
+ #### `getRoleAwareErrorMessage(requiredRole: string, userRole: string, action?: string): string`
326
+ Get contextual error message based on roles.
327
+
328
+ #### `getUserDisplay(user: User | null, customAdmins?: AdminConfig[])`
329
+ Get user display information with role indicators.
330
+
331
+ ### PermissionChecker Class
332
+
333
+ ```typescript
334
+ class PermissionChecker {
335
+ constructor(customAdmins?: AdminConfig[]);
336
+
337
+ isAdmin(identifier: string): boolean;
338
+ getRole(identifier?: string): string;
339
+ hasPermission(user: User | null, permissions: string | string[]): boolean;
340
+ canAccessAdmin(user: User | null): PermissionCheckResult;
341
+ getErrorMessage(requiredRole: string, userRole: string, action?: string): string;
342
+ getUserDisplay(user: User | null);
343
+
344
+ // Convenience methods
345
+ requiresAuth(user: User | null): boolean;
346
+ requiresAdmin(user: User | null): boolean;
347
+
348
+ // Admin management
349
+ addCustomAdmin(admin: string | AdminConfig): void;
350
+ removeCustomAdmin(admin: string | AdminConfig): void;
351
+ }
352
+ ```
353
+
354
+ ### Interfaces
355
+
356
+ ```typescript
357
+ interface User {
358
+ id: string;
359
+ email?: string;
360
+ wallet_address?: string;
361
+ role?: string;
362
+ permissions?: string[];
363
+ tier?: string;
364
+ }
365
+
366
+ interface AdminConfig {
367
+ email: string;
368
+ wallets: {
369
+ ethereum: string;
370
+ solana: string;
371
+ };
372
+ }
373
+
374
+ interface PermissionCheckResult {
375
+ allowed: boolean;
376
+ reason?: string;
377
+ userRole: string;
378
+ requiredRole?: string;
379
+ }
380
+ ```
381
+
382
+ ## ๐ŸŒŸ Best Practices
383
+
384
+ 1. **Server-side validation**: Always validate permissions on the server
385
+ 2. **Progressive enhancement**: Use client-side checks for UX, not security
386
+ 3. **Consistent error messages**: Use `getRoleAwareErrorMessage` for user-friendly errors
387
+ 4. **Role-based UI**: Show/hide features based on user permissions
388
+ 5. **Custom admin management**: Use custom admin lists for multi-tenant apps
389
+ 6. **Testing**: Test permission logic with various user states
390
+ 7. **Type safety**: Use TypeScript interfaces for better development experience