spaps 0.2.2 → 0.2.4

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/bin/spaps.js CHANGED
@@ -12,6 +12,7 @@ const { program } = require('commander');
12
12
  const { spawn } = require('child_process');
13
13
  const path = require('path');
14
14
  const fs = require('fs');
15
+ const { handleError } = require('../src/error-handler');
15
16
 
16
17
  const version = require('../package.json').version;
17
18
 
@@ -86,37 +87,7 @@ program
86
87
  });
87
88
 
88
89
  } catch (error) {
89
- if (isJson) {
90
- console.log(JSON.stringify({
91
- success: false,
92
- command: 'local',
93
- error: {
94
- message: error.message,
95
- code: error.code,
96
- suggestion: error.code === 'EADDRINUSE' ?
97
- 'Try a different port with --port option' :
98
- 'Check error message for details'
99
- }
100
- }));
101
- } else {
102
- console.error(chalk.red('āŒ Failed to start server:'), error.message);
103
-
104
- if (error.code === 'MODULE_NOT_FOUND') {
105
- console.log(chalk.yellow('\nšŸ’” Installing dependencies...'));
106
- const { execSync } = require('child_process');
107
- try {
108
- execSync('npm install express cors', {
109
- cwd: path.join(__dirname, '..'),
110
- stdio: 'inherit'
111
- });
112
- console.log(chalk.green('āœ… Dependencies installed! Please run the command again.'));
113
- } catch (installError) {
114
- console.error(chalk.red('Failed to install dependencies. Please run: npm install express cors'));
115
- }
116
- }
117
- }
118
-
119
- process.exit(1);
90
+ handleError(error, { port: options.port, command: 'local' }, { json: isJson });
120
91
  }
121
92
  });
122
93
 
package/client.js CHANGED
@@ -5,7 +5,16 @@
5
5
 
6
6
  try {
7
7
  // Try to load spaps-sdk if it's installed
8
- module.exports = require('spaps-sdk');
8
+ const sdk = require('spaps-sdk');
9
+
10
+ // Support both default export and named export
11
+ const SPAPSClient = sdk.SPAPSClient || sdk.default || sdk;
12
+
13
+ module.exports = SPAPSClient;
14
+ module.exports.SPAPSClient = SPAPSClient;
15
+ module.exports.default = SPAPSClient;
16
+ module.exports.SPAPS = SPAPSClient;
17
+ module.exports.SweetPotatoSDK = SPAPSClient;
9
18
  } catch (error) {
10
19
  // Fallback to a simple client implementation for local development
11
20
  const axios = require('axios');
@@ -94,9 +103,45 @@ try {
94
103
  isLocalMode() {
95
104
  return this.isLocalMode;
96
105
  }
106
+
107
+ async health() {
108
+ return this.client.get('/health');
109
+ }
110
+
111
+ async logout() {
112
+ await this.client.post('/api/auth/logout', {}, {
113
+ headers: { Authorization: `Bearer ${this.accessToken}` }
114
+ });
115
+ this.accessToken = null;
116
+ this.refreshToken = null;
117
+ }
118
+
119
+ async refresh(refreshToken) {
120
+ const response = await this.client.post('/api/auth/refresh', {
121
+ refresh_token: refreshToken || this.refreshToken
122
+ });
123
+ this.accessToken = response.data.access_token;
124
+ this.refreshToken = response.data.refresh_token;
125
+ return response;
126
+ }
127
+
128
+ async recordUsage(feature, amount) {
129
+ return this.client.post('/api/usage/record',
130
+ { feature, amount },
131
+ { headers: { Authorization: `Bearer ${this.accessToken}` } }
132
+ );
133
+ }
134
+
135
+ async cancelSubscription() {
136
+ return this.client.delete('/api/stripe/subscription', {
137
+ headers: { Authorization: `Bearer ${this.accessToken}` }
138
+ });
139
+ }
97
140
  }
98
141
 
99
142
  module.exports = SPAPSClient;
100
143
  module.exports.SPAPSClient = SPAPSClient;
101
144
  module.exports.default = SPAPSClient;
145
+ module.exports.SPAPS = SPAPSClient;
146
+ module.exports.SweetPotatoSDK = SPAPSClient;
102
147
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spaps",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Sweet Potato Authentication & Payment Service CLI - Zero-config local development and project scaffolding",
5
5
  "main": "bin/spaps.js",
6
6
  "bin": {
@@ -0,0 +1,271 @@
1
+ /**
2
+ * SPAPS CLI Error Handler
3
+ * Provides verbose error messages with exact fix commands
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+
8
+ const ERROR_FIXES = {
9
+ // Port errors
10
+ EADDRINUSE: (error, context = {}) => ({
11
+ title: 'Port Already In Use',
12
+ description: `Port ${context.port || 3300} is being used by another process`,
13
+ causes: [
14
+ 'Another SPAPS server is already running',
15
+ 'Another application is using this port',
16
+ 'A previous SPAPS process didn\'t shut down cleanly'
17
+ ],
18
+ fixes: [
19
+ {
20
+ command: `npx spaps local --port ${(parseInt(context.port || 3300) + 1)}`,
21
+ description: 'Use a different port'
22
+ },
23
+ {
24
+ command: `lsof -ti:${context.port || 3300} | xargs kill -9`,
25
+ description: 'Kill the process using this port (macOS/Linux)',
26
+ platform: ['darwin', 'linux']
27
+ },
28
+ {
29
+ command: `netstat -ano | findstr :${context.port || 3300}`,
30
+ description: 'Find process using this port (Windows)',
31
+ platform: ['win32']
32
+ },
33
+ {
34
+ command: 'npx spaps local --port 0',
35
+ description: 'Let the system choose an available port'
36
+ }
37
+ ]
38
+ }),
39
+
40
+ // Module errors
41
+ MODULE_NOT_FOUND: (error, context = {}) => {
42
+ const module = error.message.match(/Cannot find module '(.+?)'/)?.[1] || 'unknown';
43
+ return {
44
+ title: 'Missing Dependencies',
45
+ description: `Required module "${module}" is not installed`,
46
+ causes: [
47
+ 'Dependencies were not installed',
48
+ 'Package installation was interrupted',
49
+ 'Node modules were deleted or corrupted'
50
+ ],
51
+ fixes: [
52
+ {
53
+ command: 'npm install',
54
+ description: 'Install all dependencies'
55
+ },
56
+ {
57
+ command: `npm install ${module}`,
58
+ description: `Install missing module "${module}"`
59
+ },
60
+ {
61
+ command: 'rm -rf node_modules package-lock.json && npm install',
62
+ description: 'Clean reinstall all dependencies'
63
+ }
64
+ ]
65
+ };
66
+ },
67
+
68
+ // Permission errors
69
+ EACCES: (error, context = {}) => ({
70
+ title: 'Permission Denied',
71
+ description: 'Insufficient permissions to perform this operation',
72
+ causes: [
73
+ 'Trying to bind to a privileged port (< 1024)',
74
+ 'File system permissions issue',
75
+ 'Node.js doesn\'t have necessary permissions'
76
+ ],
77
+ fixes: [
78
+ {
79
+ command: 'npx spaps local --port 3000',
80
+ description: 'Use a non-privileged port (>= 1024)'
81
+ },
82
+ {
83
+ command: `sudo npx spaps ${process.argv.slice(2).join(' ')}`,
84
+ description: 'Run with elevated permissions (use with caution)',
85
+ warning: true
86
+ },
87
+ {
88
+ command: 'ls -la ./',
89
+ description: 'Check file permissions in current directory'
90
+ }
91
+ ]
92
+ }),
93
+
94
+ // Network errors
95
+ ECONNREFUSED: (error, context = {}) => ({
96
+ title: 'Connection Refused',
97
+ description: `Cannot connect to ${context.url || 'server'}`,
98
+ causes: [
99
+ 'Server is not running',
100
+ 'Server is running on a different port',
101
+ 'Firewall is blocking the connection'
102
+ ],
103
+ fixes: [
104
+ {
105
+ command: 'npx spaps local',
106
+ description: 'Start the local SPAPS server'
107
+ },
108
+ {
109
+ command: 'curl http://localhost:3300/health',
110
+ description: 'Check if server is responding'
111
+ },
112
+ {
113
+ command: 'netstat -an | grep LISTEN',
114
+ description: 'List all listening ports'
115
+ }
116
+ ]
117
+ }),
118
+
119
+ // File system errors
120
+ ENOENT: (error, context = {}) => {
121
+ const file = error.path || context.file || 'file';
122
+ return {
123
+ title: 'File or Directory Not Found',
124
+ description: `Cannot find "${file}"`,
125
+ causes: [
126
+ 'File does not exist',
127
+ 'Wrong directory',
128
+ 'File was deleted or moved'
129
+ ],
130
+ fixes: [
131
+ {
132
+ command: 'pwd',
133
+ description: 'Check current directory'
134
+ },
135
+ {
136
+ command: 'ls -la',
137
+ description: 'List files in current directory'
138
+ },
139
+ {
140
+ command: 'npx spaps init',
141
+ description: 'Initialize SPAPS in this directory'
142
+ }
143
+ ]
144
+ };
145
+ },
146
+
147
+ // Generic errors
148
+ DEFAULT: (error, context = {}) => ({
149
+ title: 'Unexpected Error',
150
+ description: error.message || 'An unexpected error occurred',
151
+ causes: [
152
+ 'Unknown issue',
153
+ 'Corrupted installation',
154
+ 'System-specific problem'
155
+ ],
156
+ fixes: [
157
+ {
158
+ command: 'npm cache clean --force && npm install',
159
+ description: 'Clear npm cache and reinstall'
160
+ },
161
+ {
162
+ command: 'node --version && npm --version',
163
+ description: 'Check Node.js and npm versions'
164
+ },
165
+ {
166
+ command: 'npx spaps@latest --version',
167
+ description: 'Check SPAPS version'
168
+ },
169
+ {
170
+ command: 'npm update spaps',
171
+ description: 'Update SPAPS to latest version'
172
+ }
173
+ ]
174
+ })
175
+ };
176
+
177
+ function formatError(error, context = {}) {
178
+ const errorCode = error.code || 'DEFAULT';
179
+ const errorInfo = ERROR_FIXES[errorCode]
180
+ ? ERROR_FIXES[errorCode](error, context)
181
+ : ERROR_FIXES.DEFAULT(error, context);
182
+
183
+ const output = [];
184
+
185
+ // Title
186
+ output.push(chalk.red.bold(`\nāŒ ${errorInfo.title}`));
187
+ output.push(chalk.white(errorInfo.description));
188
+
189
+ // Possible causes
190
+ if (errorInfo.causes && errorInfo.causes.length > 0) {
191
+ output.push(chalk.yellow('\nšŸ“‹ Possible causes:'));
192
+ errorInfo.causes.forEach(cause => {
193
+ output.push(chalk.gray(` • ${cause}`));
194
+ });
195
+ }
196
+
197
+ // Fixes
198
+ if (errorInfo.fixes && errorInfo.fixes.length > 0) {
199
+ output.push(chalk.green('\n✨ How to fix:'));
200
+ errorInfo.fixes.forEach((fix, index) => {
201
+ // Filter by platform if specified
202
+ if (fix.platform && !fix.platform.includes(process.platform)) {
203
+ return;
204
+ }
205
+
206
+ output.push(chalk.cyan(`\n ${index + 1}. ${fix.description}`));
207
+ output.push(chalk.bgBlack.white(` $ ${fix.command}`));
208
+
209
+ if (fix.warning) {
210
+ output.push(chalk.yellow(` āš ļø Use with caution`));
211
+ }
212
+ });
213
+ }
214
+
215
+ // Additional help
216
+ output.push(chalk.gray('\nšŸ“š For more help:'));
217
+ output.push(chalk.gray(' • Documentation: https://sweetpotato.dev/docs'));
218
+ output.push(chalk.gray(' • GitHub Issues: https://github.com/yourusername/sweet-potato/issues'));
219
+ output.push(chalk.gray(' • Discord: https://discord.gg/sweetpotato\n'));
220
+
221
+ return output.join('\n');
222
+ }
223
+
224
+ function formatJsonError(error, context = {}) {
225
+ const errorCode = error.code || 'DEFAULT';
226
+ const errorInfo = ERROR_FIXES[errorCode]
227
+ ? ERROR_FIXES[errorCode](error, context)
228
+ : ERROR_FIXES.DEFAULT(error, context);
229
+
230
+ return {
231
+ success: false,
232
+ error: {
233
+ code: errorCode,
234
+ title: errorInfo.title,
235
+ message: errorInfo.description,
236
+ causes: errorInfo.causes,
237
+ fixes: errorInfo.fixes.map(fix => ({
238
+ command: fix.command,
239
+ description: fix.description,
240
+ warning: fix.warning || false
241
+ })),
242
+ stack: process.env.DEBUG ? error.stack : undefined
243
+ },
244
+ help: {
245
+ docs: 'https://sweetpotato.dev/docs',
246
+ issues: 'https://github.com/yourusername/sweet-potato/issues',
247
+ discord: 'https://discord.gg/sweetpotato'
248
+ }
249
+ };
250
+ }
251
+
252
+ module.exports = {
253
+ formatError,
254
+ formatJsonError,
255
+ handleError: (error, context = {}, options = {}) => {
256
+ if (options.json) {
257
+ console.log(JSON.stringify(formatJsonError(error, context), null, 2));
258
+ } else {
259
+ console.error(formatError(error, context));
260
+ }
261
+
262
+ // Exit with appropriate code
263
+ const exitCode = error.code === 'EADDRINUSE' ? 98 :
264
+ error.code === 'EACCES' ? 77 :
265
+ error.code === 'ENOENT' ? 66 :
266
+ error.code === 'MODULE_NOT_FOUND' ? 127 :
267
+ 1;
268
+
269
+ process.exit(exitCode);
270
+ }
271
+ };