spaps 0.5.0 → 0.5.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/README.md +175 -36
- package/bin/spaps.js +5 -312
- package/package.json +4 -3
- package/src/ai-helper.js +20 -20
- package/src/cli-dispatcher.js +139 -0
- package/src/config.js +5 -0
- package/src/docs-system.js +78 -129
- package/src/handlers.js +155 -0
- package/src/help-system.js +5 -3
package/src/ai-helper.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
const chalk = require('chalk');
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const { DEFAULT_PORT } = require('./config');
|
|
9
|
+
|
|
10
|
+
function getQuickStartInstructions(port = DEFAULT_PORT) {
|
|
9
11
|
return {
|
|
10
12
|
success: true,
|
|
11
13
|
instructions: {
|
|
@@ -17,22 +19,20 @@ function getQuickStartInstructions(port = 3300) {
|
|
|
17
19
|
step2: {
|
|
18
20
|
description: "Create test file",
|
|
19
21
|
filename: "test-spaps.js",
|
|
20
|
-
content: `const {
|
|
22
|
+
content: `const { SweetPotatoSDK } = require('spaps-sdk');
|
|
21
23
|
|
|
22
24
|
async function test() {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
console.log('✅ Login successful:', data.user.email);
|
|
30
|
-
|
|
25
|
+
const sdk = new SweetPotatoSDK({ apiUrl: 'http://localhost:${port}' });
|
|
26
|
+
|
|
27
|
+
// Test email/password auth (local mode accepts any credentials)
|
|
28
|
+
const auth = await sdk.auth.signInWithPassword({ email: 'test@example.com', password: 'password' });
|
|
29
|
+
console.log('✅ Login successful:', auth.user.email);
|
|
30
|
+
|
|
31
31
|
// Test authenticated request
|
|
32
|
-
const user = await
|
|
33
|
-
console.log('✅ Got user:', user.
|
|
34
|
-
|
|
35
|
-
return { success: true, user
|
|
32
|
+
const user = await sdk.auth.getCurrentUser();
|
|
33
|
+
console.log('✅ Got user:', user.email);
|
|
34
|
+
|
|
35
|
+
return { success: true, user };
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
test().then(console.log).catch(console.error);`
|
|
@@ -70,9 +70,9 @@ test().then(console.log).catch(console.error);`
|
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
method: "POST",
|
|
73
|
-
path: "/api/stripe/
|
|
74
|
-
body: { price_id: "string", success_url: "string" },
|
|
75
|
-
response: {
|
|
73
|
+
path: "/api/stripe/checkout-sessions",
|
|
74
|
+
body: { price_id: "string", success_url: "string", cancel_url: "string" },
|
|
75
|
+
response: { id: "string", url: "string", status: "string" }
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
method: "GET",
|
|
@@ -84,12 +84,12 @@ test().then(console.log).catch(console.error);`
|
|
|
84
84
|
test_commands: {
|
|
85
85
|
health_check: `curl http://localhost:${port}/health`,
|
|
86
86
|
login: `curl -X POST http://localhost:${port}/api/auth/login -H "Content-Type: application/json" -d '{"email":"test@example.com","password":"password"}'`,
|
|
87
|
-
with_sdk: `node -e "const {
|
|
87
|
+
with_sdk: `node -e "const {SweetPotatoSDK}=require('spaps-sdk');const sdk=new SweetPotatoSDK({apiUrl:'http://localhost:${port}'});sdk.auth.signInWithPassword({email:'test@example.com',password:'password'}).then(r=>console.log(JSON.stringify(r.user))).catch(console.error)"`
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
function getServerStatus(port =
|
|
92
|
+
function getServerStatus(port = DEFAULT_PORT) {
|
|
93
93
|
const http = require('http');
|
|
94
94
|
|
|
95
95
|
return new Promise((resolve) => {
|
|
@@ -270,4 +270,4 @@ module.exports = {
|
|
|
270
270
|
getQuickStartInstructions,
|
|
271
271
|
getServerStatus,
|
|
272
272
|
runQuickTest
|
|
273
|
-
};
|
|
273
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// CLI dispatcher: builds a Commander program with pluggable handlers
|
|
2
|
+
// Enables dry-run parsing for unit tests without executing side effects.
|
|
3
|
+
|
|
4
|
+
const { Command } = require('commander');
|
|
5
|
+
const { DEFAULT_PORT } = require('./config');
|
|
6
|
+
|
|
7
|
+
function defineProgram({ handlers = {}, dryRun = false, version = '0.0.0', logo = null } = {}) {
|
|
8
|
+
const intents = [];
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
if (dryRun) {
|
|
12
|
+
program.allowUnknownOption(true);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('spaps')
|
|
17
|
+
.description('CLI for Sweet Potato Authentication & Payment Service')
|
|
18
|
+
.version(version)
|
|
19
|
+
.option('--json', 'Output in JSON format for machine parsing');
|
|
20
|
+
|
|
21
|
+
function makeAction(name, shape) {
|
|
22
|
+
return async function actionWrapper(...args) {
|
|
23
|
+
// Commander 11 passes (options, command) for subcommands without args
|
|
24
|
+
// For commands with args, it passes (arg1, arg2, ..., options, command)
|
|
25
|
+
const cmd = args[args.length - 1];
|
|
26
|
+
const options = args[args.length - 2] || {};
|
|
27
|
+
const parentJson = program.opts().json;
|
|
28
|
+
const isJson = Boolean(options.json || parentJson);
|
|
29
|
+
|
|
30
|
+
const intent = { name, options: { ...shape(options, cmd, isJson) } };
|
|
31
|
+
intents.push(intent);
|
|
32
|
+
|
|
33
|
+
if (dryRun) return intent;
|
|
34
|
+
const handler = handlers[name];
|
|
35
|
+
if (typeof handler === 'function') {
|
|
36
|
+
return await handler(intent, { program, cmd });
|
|
37
|
+
}
|
|
38
|
+
return intent;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// spaps local
|
|
43
|
+
const cmdLocal = program
|
|
44
|
+
.command('local')
|
|
45
|
+
.description('Start local SPAPS server (no API keys required!)')
|
|
46
|
+
.option('-p, --port <port>', 'Port to run on', String(DEFAULT_PORT))
|
|
47
|
+
.option('-o, --open', 'Open browser automatically', false)
|
|
48
|
+
.option('--json', 'Output in JSON format')
|
|
49
|
+
.action(
|
|
50
|
+
makeAction('local', (opts, _cmd, isJson) => ({
|
|
51
|
+
port: Number(opts.port),
|
|
52
|
+
open: Boolean(opts.open),
|
|
53
|
+
json: isJson,
|
|
54
|
+
}))
|
|
55
|
+
);
|
|
56
|
+
if (dryRun) cmdLocal.allowUnknownOption(true);
|
|
57
|
+
|
|
58
|
+
// spaps quickstart
|
|
59
|
+
const cmdQuick = program
|
|
60
|
+
.command('quickstart')
|
|
61
|
+
.description('Get quick start instructions (for AI agents)')
|
|
62
|
+
.option('-p, --port <port>', 'Port to check', String(DEFAULT_PORT))
|
|
63
|
+
.option('--json', 'Output in JSON format')
|
|
64
|
+
.action(makeAction('quickstart', (opts, _cmd, isJson) => ({ port: Number(opts.port), json: isJson })));
|
|
65
|
+
if (dryRun) cmdQuick.allowUnknownOption(true);
|
|
66
|
+
|
|
67
|
+
// spaps status
|
|
68
|
+
const cmdStatus = program
|
|
69
|
+
.command('status')
|
|
70
|
+
.description('Check if SPAPS server is running')
|
|
71
|
+
.option('-p, --port <port>', 'Port to check', String(DEFAULT_PORT))
|
|
72
|
+
.option('--json', 'Output in JSON format')
|
|
73
|
+
.action(makeAction('status', (opts, _cmd, isJson) => ({ port: Number(opts.port), json: isJson })));
|
|
74
|
+
if (dryRun) cmdStatus.allowUnknownOption(true);
|
|
75
|
+
|
|
76
|
+
// spaps init
|
|
77
|
+
const cmdInit = program
|
|
78
|
+
.command('init')
|
|
79
|
+
.description('Initialize SPAPS in current project')
|
|
80
|
+
.option('--json', 'Output in JSON format')
|
|
81
|
+
.action(makeAction('init', (_opts, _cmd, isJson) => ({ json: isJson })));
|
|
82
|
+
if (dryRun) cmdInit.allowUnknownOption(true);
|
|
83
|
+
|
|
84
|
+
// spaps create <name>
|
|
85
|
+
const cmdCreate = program
|
|
86
|
+
.command('create <name>')
|
|
87
|
+
.description('Create a new project with SPAPS (coming soon)')
|
|
88
|
+
.action(makeAction('create', (optsOrName, cmd) => ({ name: typeof optsOrName === 'string' ? optsOrName : cmd.args[0] })));
|
|
89
|
+
if (dryRun) cmdCreate.allowUnknownOption(true);
|
|
90
|
+
|
|
91
|
+
// spaps types
|
|
92
|
+
const cmdTypes = program
|
|
93
|
+
.command('types')
|
|
94
|
+
.description('Generate TypeScript types (coming soon)')
|
|
95
|
+
.action(makeAction('types', () => ({})));
|
|
96
|
+
if (dryRun) cmdTypes.allowUnknownOption(true);
|
|
97
|
+
|
|
98
|
+
// spaps help
|
|
99
|
+
const cmdHelp = program
|
|
100
|
+
.command('help')
|
|
101
|
+
.description('Show help and guides')
|
|
102
|
+
.option('-i, --interactive', 'Interactive help mode')
|
|
103
|
+
.option('-q, --quick', 'Quick reference')
|
|
104
|
+
.action(
|
|
105
|
+
makeAction('help', (opts) => ({ interactive: Boolean(opts.interactive), quick: Boolean(opts.quick) }))
|
|
106
|
+
);
|
|
107
|
+
if (dryRun) cmdHelp.allowUnknownOption(true);
|
|
108
|
+
|
|
109
|
+
// spaps docs
|
|
110
|
+
const cmdDocs = program
|
|
111
|
+
.command('docs')
|
|
112
|
+
.description('Browse SDK documentation')
|
|
113
|
+
.option('-i, --interactive', 'Interactive documentation browser')
|
|
114
|
+
.option('-s, --search <query>', 'Search documentation')
|
|
115
|
+
.option('--json', 'Output in JSON format')
|
|
116
|
+
.action(
|
|
117
|
+
makeAction('docs', (opts, _cmd, isJson) => ({ interactive: Boolean(opts.interactive), search: opts.search || null, json: isJson }))
|
|
118
|
+
);
|
|
119
|
+
if (dryRun) cmdDocs.allowUnknownOption(true);
|
|
120
|
+
|
|
121
|
+
return { program, getIntents: () => intents };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function buildProgram(config = {}) {
|
|
125
|
+
return defineProgram(config).program;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function parseArgv(argv, config = {}) {
|
|
129
|
+
const { program, getIntents } = defineProgram({ ...config, dryRun: true });
|
|
130
|
+
program.exitOverride(() => { /* swallow exit in dry-run */ });
|
|
131
|
+
try {
|
|
132
|
+
program.parse(argv, { from: 'user' });
|
|
133
|
+
} catch (err) {
|
|
134
|
+
// Commander throws for help/version; we ignore in parse mode
|
|
135
|
+
}
|
|
136
|
+
return getIntents();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = { buildProgram, parseArgv };
|
package/src/config.js
ADDED
package/src/docs-system.js
CHANGED
|
@@ -16,21 +16,21 @@ ${chalk.green('Installation:')}
|
|
|
16
16
|
yarn add spaps-sdk
|
|
17
17
|
|
|
18
18
|
${chalk.green('Basic Usage:')}
|
|
19
|
-
${chalk.gray('//
|
|
20
|
-
import {
|
|
19
|
+
${chalk.gray('// ES Module')}
|
|
20
|
+
import { SweetPotatoSDK } from 'spaps-sdk'
|
|
21
21
|
|
|
22
22
|
${chalk.gray('// CommonJS')}
|
|
23
|
-
const {
|
|
23
|
+
const { SweetPotatoSDK } = require('spaps-sdk')
|
|
24
24
|
|
|
25
25
|
${chalk.gray('// Create client (auto-detects local mode)')}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
${chalk.gray('//
|
|
29
|
-
const spaps = new SPAPSClient({
|
|
30
|
-
apiUrl: 'http://localhost:3300',
|
|
31
|
-
apiKey: 'your-api-key', ${chalk.gray('// Not needed for localhost')}
|
|
32
|
-
timeout: 10000
|
|
26
|
+
const sdk = new SweetPotatoSDK({
|
|
27
|
+
apiUrl: process.env.SPAPS_API_URL || 'http://localhost:3300',
|
|
28
|
+
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('// Not required in local mode')}
|
|
33
29
|
})
|
|
30
|
+
|
|
31
|
+
${chalk.gray('// Sign in with email/password (local mode accepts any credentials)')}
|
|
32
|
+
const auth = await sdk.auth.signInWithPassword({ email: 'user@example.com', password: 'password' })
|
|
33
|
+
console.log('User:', auth.user)
|
|
34
34
|
`
|
|
35
35
|
},
|
|
36
36
|
|
|
@@ -39,48 +39,30 @@ ${chalk.green('Basic Usage:')}
|
|
|
39
39
|
content: `
|
|
40
40
|
${chalk.green('Email/Password Authentication:')}
|
|
41
41
|
${chalk.gray('// Register new user')}
|
|
42
|
-
const
|
|
43
|
-
console.log('User:',
|
|
44
|
-
console.log('Token:',
|
|
42
|
+
const registered = await sdk.auth.register({ email, password })
|
|
43
|
+
console.log('User:', registered.user)
|
|
44
|
+
console.log('Token:', registered.access_token)
|
|
45
45
|
|
|
46
46
|
${chalk.gray('// Login existing user')}
|
|
47
|
-
const
|
|
47
|
+
const auth = await sdk.auth.signInWithPassword({ email, password })
|
|
48
48
|
|
|
49
49
|
${chalk.gray('// Check authentication status')}
|
|
50
|
-
if (
|
|
51
|
-
const user = await
|
|
52
|
-
console.log('Current user:', user
|
|
50
|
+
if (sdk.auth.isAuthenticated()) {
|
|
51
|
+
const user = await sdk.auth.getCurrentUser()
|
|
52
|
+
console.log('Current user:', user)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
${chalk.gray('// Logout')}
|
|
56
|
-
await
|
|
56
|
+
await sdk.auth.logout()
|
|
57
57
|
|
|
58
58
|
${chalk.green('Wallet Authentication:')}
|
|
59
|
-
${chalk.gray('//
|
|
60
|
-
await
|
|
61
|
-
|
|
62
|
-
signature,
|
|
63
|
-
message,
|
|
64
|
-
'solana'
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
${chalk.gray('// Ethereum wallet')}
|
|
68
|
-
await spaps.walletSignIn(
|
|
69
|
-
walletAddress,
|
|
70
|
-
signature,
|
|
71
|
-
message,
|
|
72
|
-
'ethereum'
|
|
73
|
-
)
|
|
59
|
+
${chalk.gray('// One-call helper: authenticateWallet')}
|
|
60
|
+
const resp = await sdk.auth.authenticateWallet(walletAddress, signMessage, 'ethereum')
|
|
61
|
+
console.log('User:', resp.user)
|
|
74
62
|
|
|
75
63
|
${chalk.green('Token Management:')}
|
|
76
|
-
${chalk.gray('//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
${chalk.gray('// Set token manually')}
|
|
80
|
-
spaps.setAccessToken(token)
|
|
81
|
-
|
|
82
|
-
${chalk.gray('// Refresh token')}
|
|
83
|
-
await spaps.refresh()
|
|
64
|
+
${chalk.gray('// Access token is managed internally; you can also set it manually')}
|
|
65
|
+
sdk.setAccessToken('jwt-token')
|
|
84
66
|
`
|
|
85
67
|
},
|
|
86
68
|
|
|
@@ -89,33 +71,25 @@ ${chalk.green('Token Management:')}
|
|
|
89
71
|
content: `
|
|
90
72
|
${chalk.green('Stripe Checkout:')}
|
|
91
73
|
${chalk.gray('// Create checkout session')}
|
|
92
|
-
const session = await
|
|
93
|
-
'price_123abc',
|
|
94
|
-
'http://localhost:3000/success',
|
|
95
|
-
'http://localhost:3000/cancel'
|
|
96
|
-
)
|
|
74
|
+
const session = await sdk.payments.createCheckoutSession({
|
|
75
|
+
price_id: 'price_123abc',
|
|
76
|
+
success_url: 'http://localhost:3000/success',
|
|
77
|
+
cancel_url: 'http://localhost:3000/cancel'
|
|
78
|
+
})
|
|
97
79
|
|
|
98
80
|
${chalk.gray('// Redirect to Stripe')}
|
|
99
|
-
window.location.href = session.
|
|
81
|
+
window.location.href = session.url
|
|
100
82
|
|
|
101
83
|
${chalk.green('Subscription Management:')}
|
|
102
84
|
${chalk.gray('// Get current subscription')}
|
|
103
|
-
|
|
104
|
-
console.log('Status:', subscription.data.status)
|
|
105
|
-
console.log('Plan:', subscription.data.plan)
|
|
106
|
-
console.log('Renews:', subscription.data.current_period_end)
|
|
85
|
+
// Example subscription helpers would go here if enabled
|
|
107
86
|
|
|
108
87
|
${chalk.gray('// Cancel subscription')}
|
|
109
88
|
await spaps.cancelSubscription()
|
|
110
89
|
|
|
111
90
|
${chalk.green('Usage Tracking:')}
|
|
112
91
|
${chalk.gray('// Check balance')}
|
|
113
|
-
|
|
114
|
-
console.log('Credits:', balance.data.balance)
|
|
115
|
-
|
|
116
|
-
${chalk.gray('// Record usage')}
|
|
117
|
-
await spaps.recordUsage('api-call', 1)
|
|
118
|
-
await spaps.recordUsage('image-generation', 10)
|
|
92
|
+
// Usage APIs depend on your server config
|
|
119
93
|
`
|
|
120
94
|
},
|
|
121
95
|
|
|
@@ -132,18 +106,9 @@ ${chalk.green('Environment Variables:')}
|
|
|
132
106
|
NEXT_PUBLIC_SPAPS_API_KEY=spaps_live_abc123...
|
|
133
107
|
|
|
134
108
|
${chalk.green('Configuration Options:')}
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
${chalk.gray('// API key (not needed for localhost)')}
|
|
140
|
-
apiKey: 'spaps_live_abc123...',
|
|
141
|
-
|
|
142
|
-
${chalk.gray('// Request timeout in milliseconds')}
|
|
143
|
-
timeout: 10000,
|
|
144
|
-
|
|
145
|
-
${chalk.gray('// Auto-detect local mode (default: true)')}
|
|
146
|
-
autoDetect: true
|
|
109
|
+
const sdk = new SweetPotatoSDK({
|
|
110
|
+
apiUrl: process.env.SPAPS_API_URL || 'http://localhost:3300',
|
|
111
|
+
apiKey: process.env.SPAPS_API_KEY, ${chalk.gray('// Omit in local dev')}
|
|
147
112
|
})
|
|
148
113
|
|
|
149
114
|
${chalk.green('Local Mode Detection:')}
|
|
@@ -153,7 +118,7 @@ ${chalk.green('Local Mode Detection:')}
|
|
|
153
118
|
- No API URL is provided
|
|
154
119
|
|
|
155
120
|
${chalk.gray('// Check if in local mode')}
|
|
156
|
-
if (
|
|
121
|
+
if (sdk.isLocalMode) {
|
|
157
122
|
console.log('Running in local mode - no API key needed!')
|
|
158
123
|
}
|
|
159
124
|
`
|
|
@@ -165,14 +130,14 @@ ${chalk.green('Local Mode Detection:')}
|
|
|
165
130
|
${chalk.green('React Context Setup:')}
|
|
166
131
|
${chalk.gray('// contexts/SpapsContext.tsx')}
|
|
167
132
|
import { createContext, useContext } from 'react'
|
|
168
|
-
import {
|
|
133
|
+
import { SweetPotatoSDK } from 'spaps-sdk'
|
|
169
134
|
|
|
170
|
-
const
|
|
171
|
-
const SpapsContext = createContext(
|
|
135
|
+
const sdk = new SweetPotatoSDK({ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL || 'http://localhost:3300' })
|
|
136
|
+
const SpapsContext = createContext(sdk)
|
|
172
137
|
|
|
173
138
|
export function SpapsProvider({ children }) {
|
|
174
139
|
return (
|
|
175
|
-
<SpapsContext.Provider value={
|
|
140
|
+
<SpapsContext.Provider value={sdk}>
|
|
176
141
|
{children}
|
|
177
142
|
</SpapsContext.Provider>
|
|
178
143
|
)
|
|
@@ -273,26 +238,23 @@ ${chalk.green('Server Actions:')}
|
|
|
273
238
|
${chalk.gray('// app/actions/auth.ts')}
|
|
274
239
|
'use server'
|
|
275
240
|
|
|
276
|
-
import {
|
|
241
|
+
import { SweetPotatoSDK } from 'spaps-sdk'
|
|
277
242
|
import { cookies } from 'next/headers'
|
|
278
243
|
|
|
279
|
-
const
|
|
280
|
-
apiUrl: process.env.SPAPS_API_URL,
|
|
281
|
-
apiKey: process.env.SPAPS_API_KEY
|
|
282
|
-
})
|
|
244
|
+
const sdk = new SweetPotatoSDK({ apiUrl: process.env.SPAPS_API_URL, apiKey: process.env.SPAPS_API_KEY })
|
|
283
245
|
|
|
284
246
|
export async function loginAction(email: string, password: string) {
|
|
285
|
-
const
|
|
247
|
+
const auth = await sdk.auth.signInWithPassword({ email, password })
|
|
286
248
|
|
|
287
249
|
// Store token in cookie
|
|
288
|
-
cookies().set('spaps_token',
|
|
250
|
+
cookies().set('spaps_token', auth.access_token, {
|
|
289
251
|
httpOnly: true,
|
|
290
252
|
secure: process.env.NODE_ENV === 'production',
|
|
291
253
|
sameSite: 'lax',
|
|
292
254
|
maxAge: 60 * 60 * 24 * 7 // 1 week
|
|
293
255
|
})
|
|
294
256
|
|
|
295
|
-
return { success: true, user:
|
|
257
|
+
return { success: true, user: auth.user }
|
|
296
258
|
}
|
|
297
259
|
|
|
298
260
|
${chalk.green('Middleware Protection:')}
|
|
@@ -322,17 +284,14 @@ ${chalk.green('Middleware Protection:')}
|
|
|
322
284
|
${chalk.green('Express Middleware:')}
|
|
323
285
|
${chalk.gray('// server.js')}
|
|
324
286
|
const express = require('express')
|
|
325
|
-
const {
|
|
287
|
+
const { SweetPotatoSDK } = require('spaps-sdk')
|
|
326
288
|
|
|
327
289
|
const app = express()
|
|
328
|
-
const
|
|
329
|
-
apiUrl: process.env.SPAPS_API_URL,
|
|
330
|
-
apiKey: process.env.SPAPS_API_KEY
|
|
331
|
-
})
|
|
290
|
+
const sdk = new SweetPotatoSDK({ apiUrl: process.env.SPAPS_API_URL, apiKey: process.env.SPAPS_API_KEY })
|
|
332
291
|
|
|
333
292
|
${chalk.gray('// Add SPAPS to request')}
|
|
334
293
|
app.use((req, res, next) => {
|
|
335
|
-
req.spaps =
|
|
294
|
+
req.spaps = sdk
|
|
336
295
|
next()
|
|
337
296
|
})
|
|
338
297
|
|
|
@@ -346,8 +305,8 @@ ${chalk.green('Express Middleware:')}
|
|
|
346
305
|
|
|
347
306
|
try {
|
|
348
307
|
req.spaps.setAccessToken(token)
|
|
349
|
-
const
|
|
350
|
-
req.user =
|
|
308
|
+
const user = await req.spaps.auth.getCurrentUser()
|
|
309
|
+
req.user = user
|
|
351
310
|
next()
|
|
352
311
|
} catch (error) {
|
|
353
312
|
res.status(401).json({ error: 'Invalid token' })
|
|
@@ -360,8 +319,8 @@ ${chalk.green('Route Examples:')}
|
|
|
360
319
|
const { email, password } = req.body
|
|
361
320
|
|
|
362
321
|
try {
|
|
363
|
-
const
|
|
364
|
-
res.json(
|
|
322
|
+
const auth = await req.spaps.auth.signInWithPassword({ email, password })
|
|
323
|
+
res.json(auth)
|
|
365
324
|
} catch (error) {
|
|
366
325
|
res.status(401).json({ error: 'Invalid credentials' })
|
|
367
326
|
}
|
|
@@ -567,17 +526,17 @@ ${chalk.green('E2E Testing with Cypress:')}
|
|
|
567
526
|
${chalk.green('Mocking for Tests:')}
|
|
568
527
|
${chalk.gray('// Mock SPAPS client')}
|
|
569
528
|
jest.mock('spaps-sdk', () => ({
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
529
|
+
SweetPotatoSDK: jest.fn().mockImplementation(() => ({
|
|
530
|
+
auth: {
|
|
531
|
+
signInWithPassword: jest.fn().mockResolvedValue({
|
|
573
532
|
user: { id: '123', email: 'test@example.com' },
|
|
574
|
-
access_token: 'mock-token'
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
533
|
+
access_token: 'mock-token',
|
|
534
|
+
refresh_token: 'mock-refresh'
|
|
535
|
+
}),
|
|
536
|
+
isAuthenticated: jest.fn().mockReturnValue(true),
|
|
537
|
+
getCurrentUser: jest.fn().mockResolvedValue({ id: '123', email: 'test@example.com' })
|
|
538
|
+
},
|
|
539
|
+
setAccessToken: jest.fn()
|
|
581
540
|
}))
|
|
582
541
|
}))
|
|
583
542
|
`
|
|
@@ -587,39 +546,29 @@ ${chalk.green('Mocking for Tests:')}
|
|
|
587
546
|
title: 'API Reference',
|
|
588
547
|
content: `
|
|
589
548
|
${chalk.green('Authentication Methods:')}
|
|
590
|
-
|
|
591
|
-
register(email
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
logout(): Promise<void>
|
|
595
|
-
|
|
549
|
+
sdk.auth.signInWithPassword({ email, password }): Promise<AuthResponse>
|
|
550
|
+
sdk.auth.register({ email, password, username? }): Promise<AuthResponse>
|
|
551
|
+
sdk.auth.authenticateWallet(address, signFn, chain?): Promise<AuthResponse>
|
|
552
|
+
sdk.auth.refreshToken(refreshToken): Promise<AuthResponse>
|
|
553
|
+
sdk.auth.logout(): Promise<void>
|
|
554
|
+
sdk.auth.getCurrentUser(): Promise<User>
|
|
596
555
|
|
|
597
556
|
${chalk.green('Payment Methods:')}
|
|
598
|
-
createCheckoutSession(
|
|
599
|
-
|
|
600
|
-
|
|
557
|
+
sdk.payments.createCheckoutSession({ price_id, success_url, cancel_url }): Promise<CheckoutSession>
|
|
558
|
+
sdk.payments.getCheckoutSession(id): Promise<CheckoutSession>
|
|
559
|
+
sdk.payments.listProducts({ category?, active?, limit? }): Promise<ProductsListResponse>
|
|
601
560
|
|
|
602
561
|
${chalk.green('Usage Methods:')}
|
|
603
|
-
|
|
604
|
-
recordUsage(feature: string, amount: number): Promise<void>
|
|
562
|
+
See server docs if enabled
|
|
605
563
|
|
|
606
564
|
${chalk.green('Utility Methods:')}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
setAccessToken(token: string): void
|
|
610
|
-
isLocalMode(): boolean
|
|
611
|
-
health(): Promise<{data: any}>
|
|
612
|
-
|
|
613
|
-
${chalk.green('Properties:')}
|
|
614
|
-
client: AxiosInstance ${chalk.gray('// Direct access to Axios client')}
|
|
565
|
+
sdk.setAccessToken(token: string): void
|
|
566
|
+
sdk.clearAccessToken(): void
|
|
615
567
|
|
|
616
568
|
${chalk.green('Response Types:')}
|
|
617
|
-
${chalk.gray('//
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const response = await spaps.login(email, password)
|
|
621
|
-
// response.data contains AuthResponse
|
|
622
|
-
// response.status, response.headers also available
|
|
569
|
+
${chalk.gray('// Methods generally return typed objects directly')}
|
|
570
|
+
const auth = await sdk.auth.signInWithPassword({ email, password })
|
|
571
|
+
console.log(auth.access_token)
|
|
623
572
|
`
|
|
624
573
|
}
|
|
625
574
|
};
|
|
@@ -636,7 +585,7 @@ ${chalk.green('Authentication Endpoints:')}
|
|
|
636
585
|
GET /api/auth/user ${chalk.gray('Get current user')}
|
|
637
586
|
|
|
638
587
|
${chalk.green('Stripe Endpoints:')}
|
|
639
|
-
POST /api/stripe/
|
|
588
|
+
POST /api/stripe/checkout-sessions ${chalk.gray('Create Stripe checkout')}
|
|
640
589
|
GET /api/stripe/subscription ${chalk.gray('Get subscription status')}
|
|
641
590
|
DELETE /api/stripe/subscription ${chalk.gray('Cancel subscription')}
|
|
642
591
|
POST /api/stripe/webhook ${chalk.gray('Stripe webhook handler')}
|
|
@@ -803,4 +752,4 @@ module.exports = {
|
|
|
803
752
|
searchDocs,
|
|
804
753
|
SDK_DOCS,
|
|
805
754
|
API_ENDPOINTS
|
|
806
|
-
};
|
|
755
|
+
};
|