spaps 0.4.3 → 0.5.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 CHANGED
@@ -199,11 +199,74 @@ npm install --save-dev spaps
199
199
 
200
200
  - 📖 **Full Documentation**: [sweetpotato.dev](https://sweetpotato.dev)
201
201
  - 🔧 **Production Setup**: See deployment guides
202
- - 💬 **Get Help**: [GitHub Issues](https://github.com/yourusername/sweet-potato/issues)
202
+ - 💬 **Get Help**: [GitHub Issues](https://github.com/build000r/sweet-potato/issues)
203
203
  - 🚀 **Examples**: Check `/examples` directory
204
204
 
205
+ ## 🚀 Production Deployment
206
+
207
+ Ready to go live? SPAPS supports seamless migration from local to production:
208
+
209
+ ### Local → Production Workflow
210
+
211
+ 1. **Export Local Data**:
212
+ ```bash
213
+ # Export your products, orders, and customers
214
+ curl http://localhost:3456/api/admin/export > spaps-data.json
215
+ ```
216
+
217
+ 2. **Set Up Production Server**:
218
+ ```bash
219
+ # Deploy to your server (DigitalOcean, AWS, etc.)
220
+ # Example production server: http://104.131.188.214:3000
221
+ git clone https://github.com/build000r/sweet-potato
222
+ cd sweet-potato
223
+ npm install
224
+ ```
225
+
226
+ 3. **Configure Environment**:
227
+ ```bash
228
+ # Set production environment variables
229
+ SUPABASE_URL=https://your-project.supabase.co
230
+ SUPABASE_SERVICE_KEY=eyJhb...your-service-key
231
+ STRIPE_SECRET_KEY=sk_live_... # Your live Stripe key
232
+ JWT_SECRET=your-32-char-secure-secret
233
+ ```
234
+
235
+ 4. **Sync Products to Production Stripe**:
236
+ ```bash
237
+ # Import your local products to production Stripe
238
+ curl -X POST http://104.131.188.214:3000/api/v1/admin/products/sync \
239
+ -H "Content-Type: application/json" \
240
+ -d @spaps-data.json
241
+ ```
242
+
243
+ 5. **Update Frontend Config**:
244
+ ```javascript
245
+ // Change from local to production endpoint
246
+ const SPAPS_URL = 'http://104.131.188.214:3000'; // Your production server
247
+ ```
248
+
249
+ ### Production Features
250
+
251
+ The production SPAPS server includes:
252
+ - ✅ **Real Supabase integration** with RLS policies
253
+ - ✅ **Live Stripe webhooks** with signature verification
254
+ - ✅ **Multi-wallet authentication** (Solana, Ethereum, Base, Bitcoin)
255
+ - ✅ **JWT authentication** with refresh tokens
256
+ - ✅ **Rate limiting** and security middleware
257
+ - ✅ **Usage tracking** and analytics
258
+ - ✅ **Multi-tenant support** for multiple client apps
259
+
260
+ ### Health Check
261
+
262
+ Check if your production server is running:
263
+ ```bash
264
+ curl http://104.131.188.214:3000/health
265
+ # Returns: {"status":"healthy","mode":"production"}
266
+ ```
267
+
205
268
  ---
206
269
 
207
- **Current Version**: v0.3.9
270
+ **Current Version**: v0.4.3
208
271
  **License**: MIT
209
272
  **Node.js**: >=16.0.0 required
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "spaps",
3
- "version": "0.4.3",
4
- "description": "Sweet Potato Authentication & Payment Service CLI - Zero-config local development and project scaffolding",
5
- "main": "bin/spaps.js",
3
+ "version": "0.5.0",
4
+ "description": "Sweet Potato Authentication & Payment Service CLI - Zero-config local development with built-in admin middleware and permission utilities",
5
+ "main": "src/index.js",
6
6
  "bin": {
7
7
  "spaps": "./bin/spaps.js"
8
8
  },
9
9
  "exports": {
10
- ".": "./bin/spaps.js",
11
- "./client": "./client.js"
10
+ ".": "./src/index.js",
11
+ "./cli": "./bin/spaps.js",
12
+ "./client": "./client.js",
13
+ "./middleware": "./src/middleware/admin.js"
12
14
  },
13
15
  "scripts": {
14
16
  "test": "echo \"No tests yet\""
@@ -30,10 +32,10 @@
30
32
  "license": "MIT",
31
33
  "repository": {
32
34
  "type": "git",
33
- "url": "https://github.com/yourusername/sweet-potato"
35
+ "url": "https://github.com/build000r/sweet-potato"
34
36
  },
35
37
  "bugs": {
36
- "url": "https://github.com/yourusername/sweet-potato/issues"
38
+ "url": "https://github.com/build000r/sweet-potato/issues"
37
39
  },
38
40
  "homepage": "https://sweetpotato.dev",
39
41
  "dependencies": {
package/src/index.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * SPAPS Package Main Export
3
+ * Provides middleware, utilities, and client functionality
4
+ */
5
+
6
+ const adminMiddleware = require('./middleware/admin');
7
+
8
+ // Export admin middleware and utilities
9
+ module.exports = {
10
+ // Admin middleware functions
11
+ requireAdmin: adminMiddleware.requireAdmin,
12
+ requirePermission: adminMiddleware.requirePermission,
13
+
14
+ // Permission checking utilities
15
+ isAdminAccount: adminMiddleware.isAdminAccount,
16
+ getUserRole: adminMiddleware.getUserRole,
17
+ hasPermission: adminMiddleware.hasPermission,
18
+ getRoleAwareErrorMessage: adminMiddleware.getRoleAwareErrorMessage,
19
+
20
+ // Constants
21
+ DEFAULT_ADMIN_ACCOUNTS: adminMiddleware.DEFAULT_ADMIN_ACCOUNTS,
22
+
23
+ // Factory function for custom admin configurations
24
+ createPermissionChecker: adminMiddleware.createPermissionChecker,
25
+
26
+ // Express middleware aliases for convenience
27
+ admin: adminMiddleware.requireAdmin,
28
+ permission: adminMiddleware.requirePermission,
29
+
30
+ // Version and metadata
31
+ version: require('../package.json').version,
32
+ name: 'spaps'
33
+ };
34
+
35
+ // Named exports for ES6 compatibility
36
+ module.exports.requireAdmin = adminMiddleware.requireAdmin;
37
+ module.exports.requirePermission = adminMiddleware.requirePermission;
38
+ module.exports.isAdminAccount = adminMiddleware.isAdminAccount;
39
+ module.exports.getUserRole = adminMiddleware.getUserRole;
40
+ module.exports.hasPermission = adminMiddleware.hasPermission;
41
+ module.exports.getRoleAwareErrorMessage = adminMiddleware.getRoleAwareErrorMessage;
42
+ module.exports.createPermissionChecker = adminMiddleware.createPermissionChecker;
@@ -0,0 +1,238 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * Admin middleware for SPAPS applications
5
+ * Provides built-in admin role checking and permission validation
6
+ */
7
+
8
+ // Default admin configuration
9
+ const DEFAULT_ADMIN_ACCOUNTS = {
10
+ email: 'buildooor@gmail.com',
11
+ wallets: {
12
+ ethereum: '0xa72bb7CeF1e4B2Cc144373d8dE0Add7CCc8DF4Ba',
13
+ solana: 'HVEbdiYU3Rr34NHBSgKs7q8cvdTeZLqNL77Z1FB2vjLy',
14
+ }
15
+ };
16
+
17
+ /**
18
+ * Check if an identifier (email/wallet) is an admin account
19
+ */
20
+ function isAdminAccount(identifier, customAdmins = []) {
21
+ if (!identifier) return false;
22
+
23
+ const normalized = identifier.toLowerCase();
24
+
25
+ // Check default admin accounts
26
+ if (normalized === DEFAULT_ADMIN_ACCOUNTS.email.toLowerCase() ||
27
+ normalized === DEFAULT_ADMIN_ACCOUNTS.wallets.ethereum.toLowerCase() ||
28
+ normalized === DEFAULT_ADMIN_ACCOUNTS.wallets.solana.toLowerCase()) {
29
+ return true;
30
+ }
31
+
32
+ // Check custom admin accounts
33
+ return customAdmins.some(admin => {
34
+ if (typeof admin === 'string') {
35
+ return admin.toLowerCase() === normalized;
36
+ }
37
+ if (admin.email && admin.email.toLowerCase() === normalized) {
38
+ return true;
39
+ }
40
+ if (admin.wallet_address && admin.wallet_address.toLowerCase() === normalized) {
41
+ return true;
42
+ }
43
+ return false;
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Get user role based on identifier
49
+ */
50
+ function getUserRole(identifier, customAdmins = []) {
51
+ if (isAdminAccount(identifier, customAdmins)) {
52
+ return 'admin';
53
+ }
54
+ return 'user';
55
+ }
56
+
57
+ /**
58
+ * Get role-aware error message
59
+ */
60
+ function getRoleAwareErrorMessage(requiredRole, userRole, action = 'perform this action') {
61
+ const messages = {
62
+ admin: {
63
+ user: `🔒 Admin privileges required to ${action}. Please authenticate with an admin account.`,
64
+ guest: `🔐 Authentication required. Please sign in with an admin account to ${action}.`
65
+ },
66
+ user: {
67
+ guest: `🔐 Authentication required. Please sign in to ${action}.`
68
+ }
69
+ };
70
+
71
+ return messages[requiredRole]?.[userRole] || `Access denied. Required role: ${requiredRole}, current role: ${userRole}`;
72
+ }
73
+
74
+ /**
75
+ * Express middleware for admin authentication
76
+ */
77
+ function requireAdmin(options = {}) {
78
+ const {
79
+ customAdmins = [],
80
+ errorMessage,
81
+ onUnauthorized,
82
+ allowLocalBypass = true
83
+ } = options;
84
+
85
+ return (req, res, next) => {
86
+ // Check if in local development mode
87
+ if (allowLocalBypass && req.isLocalMode) {
88
+ console.log(chalk.yellow('🏠 Local mode: Admin check bypassed'));
89
+ req.isAdmin = true;
90
+ req.userRole = 'admin';
91
+ return next();
92
+ }
93
+
94
+ // Extract user information from request
95
+ const userEmail = req.user?.email || req.body?.email;
96
+ const walletAddress = req.user?.wallet_address || req.body?.wallet_address;
97
+ const identifier = userEmail || walletAddress;
98
+
99
+ if (!identifier) {
100
+ const message = errorMessage || getRoleAwareErrorMessage('admin', 'guest');
101
+
102
+ if (onUnauthorized) {
103
+ return onUnauthorized(req, res, { reason: 'no_identifier', message });
104
+ }
105
+
106
+ return res.status(401).json({
107
+ success: false,
108
+ error: {
109
+ code: 'AUTHENTICATION_REQUIRED',
110
+ message
111
+ }
112
+ });
113
+ }
114
+
115
+ const isAdmin = isAdminAccount(identifier, customAdmins);
116
+ const userRole = getUserRole(identifier, customAdmins);
117
+
118
+ if (!isAdmin) {
119
+ const message = errorMessage || getRoleAwareErrorMessage('admin', userRole);
120
+
121
+ if (onUnauthorized) {
122
+ return onUnauthorized(req, res, {
123
+ reason: 'insufficient_privileges',
124
+ message,
125
+ userRole,
126
+ identifier
127
+ });
128
+ }
129
+
130
+ return res.status(403).json({
131
+ success: false,
132
+ error: {
133
+ code: 'INSUFFICIENT_PRIVILEGES',
134
+ message
135
+ }
136
+ });
137
+ }
138
+
139
+ // Add admin information to request
140
+ req.isAdmin = true;
141
+ req.userRole = userRole;
142
+ req.adminAccount = identifier;
143
+
144
+ console.log(chalk.green(`👑 Admin authenticated: ${identifier}`));
145
+ next();
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Permission checking utility
151
+ */
152
+ function hasPermission(user, requiredPermissions, customAdmins = []) {
153
+ if (!user) return false;
154
+
155
+ const identifier = user.email || user.wallet_address;
156
+ const userRole = getUserRole(identifier, customAdmins);
157
+
158
+ // Admins have all permissions
159
+ if (userRole === 'admin') {
160
+ return true;
161
+ }
162
+
163
+ // Check specific permissions
164
+ if (Array.isArray(requiredPermissions)) {
165
+ return requiredPermissions.every(permission =>
166
+ user.permissions?.includes(permission)
167
+ );
168
+ }
169
+
170
+ return user.permissions?.includes(requiredPermissions);
171
+ }
172
+
173
+ /**
174
+ * Express middleware for permission checking
175
+ */
176
+ function requirePermission(permissions, options = {}) {
177
+ const {
178
+ customAdmins = [],
179
+ errorMessage,
180
+ onUnauthorized
181
+ } = options;
182
+
183
+ return (req, res, next) => {
184
+ const user = req.user;
185
+ const hasRequiredPermission = hasPermission(user, permissions, customAdmins);
186
+
187
+ if (!hasRequiredPermission) {
188
+ const userRole = user ? getUserRole(user.email || user.wallet_address, customAdmins) : 'guest';
189
+ const message = errorMessage || getRoleAwareErrorMessage('permission', userRole, `access this resource`);
190
+
191
+ if (onUnauthorized) {
192
+ return onUnauthorized(req, res, {
193
+ reason: 'insufficient_permissions',
194
+ message,
195
+ requiredPermissions: permissions,
196
+ userPermissions: user?.permissions || []
197
+ });
198
+ }
199
+
200
+ return res.status(403).json({
201
+ success: false,
202
+ error: {
203
+ code: 'INSUFFICIENT_PERMISSIONS',
204
+ message,
205
+ details: {
206
+ required: permissions,
207
+ current: user?.permissions || []
208
+ }
209
+ }
210
+ });
211
+ }
212
+
213
+ next();
214
+ };
215
+ }
216
+
217
+ module.exports = {
218
+ // Middleware functions
219
+ requireAdmin,
220
+ requirePermission,
221
+
222
+ // Utility functions
223
+ isAdminAccount,
224
+ getUserRole,
225
+ hasPermission,
226
+ getRoleAwareErrorMessage,
227
+
228
+ // Constants
229
+ DEFAULT_ADMIN_ACCOUNTS,
230
+
231
+ // Helper for client-side checking
232
+ createPermissionChecker: (customAdmins = []) => ({
233
+ isAdmin: (identifier) => isAdminAccount(identifier, customAdmins),
234
+ getRole: (identifier) => getUserRole(identifier, customAdmins),
235
+ hasPermission: (user, permissions) => hasPermission(user, permissions, customAdmins),
236
+ getErrorMessage: (requiredRole, userRole, action) => getRoleAwareErrorMessage(requiredRole, userRole, action)
237
+ })
238
+ };