spaps 0.2.5 → 0.2.7

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.
@@ -0,0 +1,806 @@
1
+ /**
2
+ * SPAPS CLI Documentation System
3
+ * Comprehensive SDK and API documentation
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+ const prompts = require('prompts');
8
+
9
+ const SDK_DOCS = {
10
+ quickstart: {
11
+ title: 'SDK Quick Start',
12
+ content: `
13
+ ${chalk.green('Installation:')}
14
+ npm install spaps-sdk
15
+ # or
16
+ yarn add spaps-sdk
17
+
18
+ ${chalk.green('Basic Usage:')}
19
+ ${chalk.gray('// ES6 Import')}
20
+ import { SPAPSClient } from 'spaps-sdk'
21
+
22
+ ${chalk.gray('// CommonJS')}
23
+ const { SPAPSClient } = require('spaps-sdk')
24
+
25
+ ${chalk.gray('// Create client (auto-detects local mode)')}
26
+ const spaps = new SPAPSClient()
27
+
28
+ ${chalk.gray('// With custom config')}
29
+ const spaps = new SPAPSClient({
30
+ apiUrl: 'http://localhost:3300',
31
+ apiKey: 'your-api-key', ${chalk.gray('// Not needed for localhost')}
32
+ timeout: 10000
33
+ })
34
+ `
35
+ },
36
+
37
+ authentication: {
38
+ title: 'Authentication Methods',
39
+ content: `
40
+ ${chalk.green('Email/Password Authentication:')}
41
+ ${chalk.gray('// Register new user')}
42
+ const { data } = await spaps.register(email, password)
43
+ console.log('User:', data.user)
44
+ console.log('Token:', data.access_token)
45
+
46
+ ${chalk.gray('// Login existing user')}
47
+ const { data } = await spaps.login(email, password)
48
+
49
+ ${chalk.gray('// Check authentication status')}
50
+ if (spaps.isAuthenticated()) {
51
+ const user = await spaps.getUser()
52
+ console.log('Current user:', user.data)
53
+ }
54
+
55
+ ${chalk.gray('// Logout')}
56
+ await spaps.logout()
57
+
58
+ ${chalk.green('Wallet Authentication:')}
59
+ ${chalk.gray('// Solana wallet')}
60
+ await spaps.walletSignIn(
61
+ walletAddress,
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
+ )
74
+
75
+ ${chalk.green('Token Management:')}
76
+ ${chalk.gray('// Get current token')}
77
+ const token = spaps.getAccessToken()
78
+
79
+ ${chalk.gray('// Set token manually')}
80
+ spaps.setAccessToken(token)
81
+
82
+ ${chalk.gray('// Refresh token')}
83
+ await spaps.refresh()
84
+ `
85
+ },
86
+
87
+ payments: {
88
+ title: 'Payment Integration',
89
+ content: `
90
+ ${chalk.green('Stripe Checkout:')}
91
+ ${chalk.gray('// Create checkout session')}
92
+ const session = await spaps.createCheckoutSession(
93
+ 'price_123abc', ${chalk.gray('// Stripe price ID')}
94
+ 'http://localhost:3000/success', ${chalk.gray('// Success URL')}
95
+ 'http://localhost:3000/cancel' ${chalk.gray('// Cancel URL (optional)')}
96
+ )
97
+
98
+ ${chalk.gray('// Redirect to Stripe')}
99
+ window.location.href = session.data.url
100
+
101
+ ${chalk.green('Subscription Management:')}
102
+ ${chalk.gray('// Get current subscription')}
103
+ const subscription = await spaps.getSubscription()
104
+ console.log('Status:', subscription.data.status)
105
+ console.log('Plan:', subscription.data.plan)
106
+ console.log('Renews:', subscription.data.current_period_end)
107
+
108
+ ${chalk.gray('// Cancel subscription')}
109
+ await spaps.cancelSubscription()
110
+
111
+ ${chalk.green('Usage Tracking:')}
112
+ ${chalk.gray('// Check balance')}
113
+ const balance = await spaps.getUsageBalance()
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)
119
+ `
120
+ },
121
+
122
+ config: {
123
+ title: 'Configuration',
124
+ content: `
125
+ ${chalk.green('Environment Variables:')}
126
+ ${chalk.gray('# .env or .env.local')}
127
+ SPAPS_API_URL=http://localhost:3300
128
+ SPAPS_API_KEY=spaps_live_abc123...
129
+
130
+ ${chalk.gray('# Next.js (use NEXT_PUBLIC_ prefix)')}
131
+ NEXT_PUBLIC_SPAPS_API_URL=http://localhost:3300
132
+ NEXT_PUBLIC_SPAPS_API_KEY=spaps_live_abc123...
133
+
134
+ ${chalk.green('Configuration Options:')}
135
+ const spaps = new SPAPSClient({
136
+ ${chalk.gray('// API endpoint (auto-detected from env)')}
137
+ apiUrl: 'http://localhost:3300',
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
147
+ })
148
+
149
+ ${chalk.green('Local Mode Detection:')}
150
+ ${chalk.gray('// The SDK automatically detects local mode when:')}
151
+ - URL contains 'localhost'
152
+ - URL contains '127.0.0.1'
153
+ - No API URL is provided
154
+
155
+ ${chalk.gray('// Check if in local mode')}
156
+ if (spaps.isLocalMode()) {
157
+ console.log('Running in local mode - no API key needed!')
158
+ }
159
+ `
160
+ },
161
+
162
+ react: {
163
+ title: 'React Integration',
164
+ content: `
165
+ ${chalk.green('React Context Setup:')}
166
+ ${chalk.gray('// contexts/SpapsContext.tsx')}
167
+ import { createContext, useContext } from 'react'
168
+ import { SPAPSClient } from 'spaps-sdk'
169
+
170
+ const spaps = new SPAPSClient()
171
+ const SpapsContext = createContext(spaps)
172
+
173
+ export function SpapsProvider({ children }) {
174
+ return (
175
+ <SpapsContext.Provider value={spaps}>
176
+ {children}
177
+ </SpapsContext.Provider>
178
+ )
179
+ }
180
+
181
+ export const useSpaps = () => useContext(SpapsContext)
182
+
183
+ ${chalk.green('React Hook Example:')}
184
+ ${chalk.gray('// hooks/useAuth.ts')}
185
+ import { useState, useEffect } from 'react'
186
+ import { useSpaps } from '../contexts/SpapsContext'
187
+
188
+ export function useAuth() {
189
+ const spaps = useSpaps()
190
+ const [user, setUser] = useState(null)
191
+ const [loading, setLoading] = useState(true)
192
+
193
+ useEffect(() => {
194
+ if (spaps.isAuthenticated()) {
195
+ spaps.getUser()
196
+ .then(res => setUser(res.data))
197
+ .finally(() => setLoading(false))
198
+ } else {
199
+ setLoading(false)
200
+ }
201
+ }, [])
202
+
203
+ return { user, loading, isAuthenticated: !!user }
204
+ }
205
+
206
+ ${chalk.green('Component Example:')}
207
+ ${chalk.gray('// components/LoginForm.tsx')}
208
+ function LoginForm() {
209
+ const spaps = useSpaps()
210
+ const [email, setEmail] = useState('')
211
+ const [password, setPassword] = useState('')
212
+
213
+ const handleSubmit = async (e) => {
214
+ e.preventDefault()
215
+ try {
216
+ await spaps.login(email, password)
217
+ // Redirect or update state
218
+ } catch (error) {
219
+ console.error('Login failed:', error)
220
+ }
221
+ }
222
+
223
+ return (
224
+ <form onSubmit={handleSubmit}>
225
+ <input
226
+ type="email"
227
+ value={email}
228
+ onChange={(e) => setEmail(e.target.value)}
229
+ />
230
+ <input
231
+ type="password"
232
+ value={password}
233
+ onChange={(e) => setPassword(e.target.value)}
234
+ />
235
+ <button type="submit">Login</button>
236
+ </form>
237
+ )
238
+ }
239
+ `
240
+ },
241
+
242
+ nextjs: {
243
+ title: 'Next.js Integration',
244
+ content: `
245
+ ${chalk.green('App Router Setup:')}
246
+ ${chalk.gray('// app/providers.tsx')}
247
+ 'use client'
248
+
249
+ import { SPAPSClient } from 'spaps-sdk'
250
+ import { createContext, useContext } from 'react'
251
+
252
+ const SpapsContext = createContext<SPAPSClient | null>(null)
253
+
254
+ export function Providers({ children }) {
255
+ const spaps = new SPAPSClient({
256
+ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL
257
+ })
258
+
259
+ return (
260
+ <SpapsContext.Provider value={spaps}>
261
+ {children}
262
+ </SpapsContext.Provider>
263
+ )
264
+ }
265
+
266
+ export const useSpaps = () => {
267
+ const context = useContext(SpapsContext)
268
+ if (!context) throw new Error('Missing SpapsProvider')
269
+ return context
270
+ }
271
+
272
+ ${chalk.green('Server Actions:')}
273
+ ${chalk.gray('// app/actions/auth.ts')}
274
+ 'use server'
275
+
276
+ import { SPAPSClient } from 'spaps-sdk'
277
+ import { cookies } from 'next/headers'
278
+
279
+ const spaps = new SPAPSClient({
280
+ apiUrl: process.env.SPAPS_API_URL,
281
+ apiKey: process.env.SPAPS_API_KEY
282
+ })
283
+
284
+ export async function loginAction(email: string, password: string) {
285
+ const { data } = await spaps.login(email, password)
286
+
287
+ // Store token in cookie
288
+ cookies().set('spaps_token', data.access_token, {
289
+ httpOnly: true,
290
+ secure: process.env.NODE_ENV === 'production',
291
+ sameSite: 'lax',
292
+ maxAge: 60 * 60 * 24 * 7 // 1 week
293
+ })
294
+
295
+ return { success: true, user: data.user }
296
+ }
297
+
298
+ ${chalk.green('Middleware Protection:')}
299
+ ${chalk.gray('// middleware.ts')}
300
+ import { NextResponse } from 'next/server'
301
+ import type { NextRequest } from 'next/server'
302
+
303
+ export function middleware(request: NextRequest) {
304
+ const token = request.cookies.get('spaps_token')
305
+
306
+ if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
307
+ return NextResponse.redirect(new URL('/login', request.url))
308
+ }
309
+
310
+ return NextResponse.next()
311
+ }
312
+
313
+ export const config = {
314
+ matcher: '/dashboard/:path*'
315
+ }
316
+ `
317
+ },
318
+
319
+ nodejs: {
320
+ title: 'Node.js/Express Integration',
321
+ content: `
322
+ ${chalk.green('Express Middleware:')}
323
+ ${chalk.gray('// server.js')}
324
+ const express = require('express')
325
+ const { SPAPSClient } = require('spaps-sdk')
326
+
327
+ const app = express()
328
+ const spaps = new SPAPSClient({
329
+ apiUrl: process.env.SPAPS_API_URL,
330
+ apiKey: process.env.SPAPS_API_KEY
331
+ })
332
+
333
+ ${chalk.gray('// Add SPAPS to request')}
334
+ app.use((req, res, next) => {
335
+ req.spaps = spaps
336
+ next()
337
+ })
338
+
339
+ ${chalk.gray('// Auth middleware')}
340
+ async function requireAuth(req, res, next) {
341
+ const token = req.headers.authorization?.split(' ')[1]
342
+
343
+ if (!token) {
344
+ return res.status(401).json({ error: 'No token provided' })
345
+ }
346
+
347
+ try {
348
+ req.spaps.setAccessToken(token)
349
+ const { data } = await req.spaps.getUser()
350
+ req.user = data
351
+ next()
352
+ } catch (error) {
353
+ res.status(401).json({ error: 'Invalid token' })
354
+ }
355
+ }
356
+
357
+ ${chalk.green('Route Examples:')}
358
+ ${chalk.gray('// Login endpoint')}
359
+ app.post('/api/login', async (req, res) => {
360
+ const { email, password } = req.body
361
+
362
+ try {
363
+ const { data } = await req.spaps.login(email, password)
364
+ res.json(data)
365
+ } catch (error) {
366
+ res.status(401).json({ error: 'Invalid credentials' })
367
+ }
368
+ })
369
+
370
+ ${chalk.gray('// Protected route')}
371
+ app.get('/api/profile', requireAuth, (req, res) => {
372
+ res.json(req.user)
373
+ })
374
+
375
+ ${chalk.gray('// Stripe webhook')}
376
+ app.post('/api/webhooks/stripe', async (req, res) => {
377
+ // Verify webhook signature
378
+ // Update user subscription status
379
+ res.json({ received: true })
380
+ })
381
+ `
382
+ },
383
+
384
+ errors: {
385
+ title: 'Error Handling',
386
+ content: `
387
+ ${chalk.green('Error Types:')}
388
+ try {
389
+ await spaps.login(email, password)
390
+ } catch (error) {
391
+ if (error.response) {
392
+ ${chalk.gray('// Server responded with error')}
393
+ console.log('Status:', error.response.status)
394
+ console.log('Data:', error.response.data)
395
+
396
+ switch (error.response.status) {
397
+ case 401:
398
+ console.error('Invalid credentials')
399
+ break
400
+ case 429:
401
+ console.error('Rate limited - try again later')
402
+ break
403
+ case 500:
404
+ console.error('Server error')
405
+ break
406
+ }
407
+ } else if (error.request) {
408
+ ${chalk.gray('// Request made but no response')}
409
+ console.error('Network error - server unreachable')
410
+ } else {
411
+ ${chalk.gray('// Error in request setup')}
412
+ console.error('Request error:', error.message)
413
+ }
414
+ }
415
+
416
+ ${chalk.green('Custom Error Handling:')}
417
+ ${chalk.gray('// Global error handler')}
418
+ spaps.client.interceptors.response.use(
419
+ response => response,
420
+ error => {
421
+ if (error.response?.status === 401) {
422
+ // Token expired - redirect to login
423
+ window.location.href = '/login'
424
+ }
425
+ return Promise.reject(error)
426
+ }
427
+ )
428
+
429
+ ${chalk.green('Retry Logic:')}
430
+ ${chalk.gray('// Retry failed requests')}
431
+ async function retryRequest(fn, retries = 3) {
432
+ try {
433
+ return await fn()
434
+ } catch (error) {
435
+ if (retries > 0 && error.response?.status >= 500) {
436
+ await new Promise(r => setTimeout(r, 1000))
437
+ return retryRequest(fn, retries - 1)
438
+ }
439
+ throw error
440
+ }
441
+ }
442
+
443
+ ${chalk.gray('// Usage')}
444
+ const user = await retryRequest(() => spaps.getUser())
445
+ `
446
+ },
447
+
448
+ typescript: {
449
+ title: 'TypeScript Support',
450
+ content: `
451
+ ${chalk.green('Type Definitions:')}
452
+ import {
453
+ SPAPSClient,
454
+ SPAPSConfig,
455
+ AuthResponse,
456
+ User,
457
+ CheckoutSession,
458
+ Subscription,
459
+ UsageBalance
460
+ } from 'spaps-sdk'
461
+
462
+ ${chalk.green('Interface Examples:')}
463
+ ${chalk.gray('// User type')}
464
+ interface User {
465
+ id: string
466
+ email?: string
467
+ wallet_address?: string
468
+ chain_type?: string
469
+ role: string
470
+ created_at?: string
471
+ }
472
+
473
+ ${chalk.gray('// Auth response')}
474
+ interface AuthResponse {
475
+ access_token: string
476
+ refresh_token: string
477
+ user: User
478
+ }
479
+
480
+ ${chalk.gray('// Config options')}
481
+ interface SPAPSConfig {
482
+ apiUrl?: string
483
+ apiKey?: string
484
+ autoDetect?: boolean
485
+ timeout?: number
486
+ }
487
+
488
+ ${chalk.green('Type-Safe Usage:')}
489
+ ${chalk.gray('// Typed client')}
490
+ const spaps: SPAPSClient = new SPAPSClient({
491
+ apiUrl: 'http://localhost:3300'
492
+ })
493
+
494
+ ${chalk.gray('// Typed responses')}
495
+ const login = async (email: string, password: string): Promise<User> => {
496
+ const { data }: { data: AuthResponse } = await spaps.login(email, password)
497
+ return data.user
498
+ }
499
+
500
+ ${chalk.gray('// Generic wrapper')}
501
+ async function apiCall<T>(
502
+ fn: () => Promise<{ data: T }>
503
+ ): Promise<T> {
504
+ try {
505
+ const { data } = await fn()
506
+ return data
507
+ } catch (error) {
508
+ console.error('API call failed:', error)
509
+ throw error
510
+ }
511
+ }
512
+
513
+ ${chalk.gray('// Usage')}
514
+ const user = await apiCall<User>(() => spaps.getUser())
515
+ `
516
+ },
517
+
518
+ testing: {
519
+ title: 'Testing',
520
+ content: `
521
+ ${chalk.green('Unit Testing with Jest:')}
522
+ ${chalk.gray('// __tests__/auth.test.js')}
523
+ import { SPAPSClient } from 'spaps-sdk'
524
+
525
+ describe('Authentication', () => {
526
+ let spaps
527
+
528
+ beforeEach(() => {
529
+ spaps = new SPAPSClient({
530
+ apiUrl: 'http://localhost:3300'
531
+ })
532
+ })
533
+
534
+ test('login returns user and token', async () => {
535
+ const { data } = await spaps.login('test@example.com', 'password')
536
+
537
+ expect(data.user).toBeDefined()
538
+ expect(data.user.email).toBe('test@example.com')
539
+ expect(data.access_token).toBeDefined()
540
+ })
541
+
542
+ test('sets auth token after login', async () => {
543
+ await spaps.login('test@example.com', 'password')
544
+
545
+ expect(spaps.isAuthenticated()).toBe(true)
546
+ expect(spaps.getAccessToken()).toBeDefined()
547
+ })
548
+ })
549
+
550
+ ${chalk.green('E2E Testing with Cypress:')}
551
+ ${chalk.gray('// cypress/e2e/auth.cy.js')}
552
+ describe('Auth Flow', () => {
553
+ beforeEach(() => {
554
+ cy.visit('http://localhost:3000')
555
+ })
556
+
557
+ it('allows user to login', () => {
558
+ cy.get('[data-cy=email]').type('test@example.com')
559
+ cy.get('[data-cy=password]').type('password')
560
+ cy.get('[data-cy=submit]').click()
561
+
562
+ cy.url().should('include', '/dashboard')
563
+ cy.contains('Welcome back')
564
+ })
565
+ })
566
+
567
+ ${chalk.green('Mocking for Tests:')}
568
+ ${chalk.gray('// Mock SPAPS client')}
569
+ jest.mock('spaps-sdk', () => ({
570
+ SPAPSClient: jest.fn().mockImplementation(() => ({
571
+ login: jest.fn().mockResolvedValue({
572
+ data: {
573
+ user: { id: '123', email: 'test@example.com' },
574
+ access_token: 'mock-token'
575
+ }
576
+ }),
577
+ isAuthenticated: jest.fn().mockReturnValue(true),
578
+ getUser: jest.fn().mockResolvedValue({
579
+ data: { id: '123', email: 'test@example.com' }
580
+ })
581
+ }))
582
+ }))
583
+ `
584
+ },
585
+
586
+ api_reference: {
587
+ title: 'API Reference',
588
+ content: `
589
+ ${chalk.green('Authentication Methods:')}
590
+ login(email: string, password: string): Promise<{data: AuthResponse}>
591
+ register(email: string, password: string): Promise<{data: AuthResponse}>
592
+ walletSignIn(address: string, signature: string, message: string, chain: string): Promise<{data: AuthResponse}>
593
+ refresh(refreshToken?: string): Promise<{data: AuthResponse}>
594
+ logout(): Promise<void>
595
+ getUser(): Promise<{data: User}>
596
+
597
+ ${chalk.green('Payment Methods:')}
598
+ createCheckoutSession(priceId: string, successUrl: string, cancelUrl?: string): Promise<{data: CheckoutSession}>
599
+ getSubscription(): Promise<{data: Subscription}>
600
+ cancelSubscription(): Promise<void>
601
+
602
+ ${chalk.green('Usage Methods:')}
603
+ getUsageBalance(): Promise<{data: UsageBalance}>
604
+ recordUsage(feature: string, amount: number): Promise<void>
605
+
606
+ ${chalk.green('Utility Methods:')}
607
+ isAuthenticated(): boolean
608
+ getAccessToken(): string | undefined
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')}
615
+
616
+ ${chalk.green('Response Types:')}
617
+ ${chalk.gray('// All methods return data wrapped in { data: T }')}
618
+ ${chalk.gray('// This matches Axios response structure')}
619
+ ${chalk.gray('// Example:')}
620
+ const response = await spaps.login(email, password)
621
+ // response.data contains AuthResponse
622
+ // response.status, response.headers also available
623
+ `
624
+ }
625
+ };
626
+
627
+ const API_ENDPOINTS = {
628
+ title: 'API Endpoints',
629
+ content: `
630
+ ${chalk.green('Authentication Endpoints:')}
631
+ POST /api/auth/register ${chalk.gray('Register new user')}
632
+ POST /api/auth/login ${chalk.gray('Login with email/password')}
633
+ POST /api/auth/wallet-sign-in ${chalk.gray('Login with wallet')}
634
+ POST /api/auth/refresh ${chalk.gray('Refresh access token')}
635
+ POST /api/auth/logout ${chalk.gray('Logout user')}
636
+ GET /api/auth/user ${chalk.gray('Get current user')}
637
+
638
+ ${chalk.green('Stripe Endpoints:')}
639
+ POST /api/stripe/create-checkout-session ${chalk.gray('Create Stripe checkout')}
640
+ GET /api/stripe/subscription ${chalk.gray('Get subscription status')}
641
+ DELETE /api/stripe/subscription ${chalk.gray('Cancel subscription')}
642
+ POST /api/stripe/webhook ${chalk.gray('Stripe webhook handler')}
643
+
644
+ ${chalk.green('Usage Endpoints:')}
645
+ GET /api/usage/balance ${chalk.gray('Get usage balance')}
646
+ POST /api/usage/record ${chalk.gray('Record usage event')}
647
+ GET /api/usage/history ${chalk.gray('Get usage history')}
648
+
649
+ ${chalk.green('Health Endpoints:')}
650
+ GET /health ${chalk.gray('Health check')}
651
+ GET /health/local-mode ${chalk.gray('Local mode status')}
652
+
653
+ ${chalk.green('Local Mode Features:')}
654
+ ${chalk.gray('In local mode (http://localhost:3300):')}
655
+ • No API key required
656
+ • Auto-authentication enabled
657
+ • CORS disabled for all origins
658
+ • Mock responses for all endpoints
659
+ • Test users available: user, admin, premium
660
+ `
661
+ };
662
+
663
+ async function showDocsMenu() {
664
+ const choices = [
665
+ { title: '🚀 Quick Start', value: 'quickstart' },
666
+ { title: '🔐 Authentication', value: 'authentication' },
667
+ { title: '💳 Payments', value: 'payments' },
668
+ { title: '⚙️ Configuration', value: 'config' },
669
+ { title: '⚛️ React Integration', value: 'react' },
670
+ { title: '▲ Next.js Integration', value: 'nextjs' },
671
+ { title: '🟢 Node.js/Express', value: 'nodejs' },
672
+ { title: '❌ Error Handling', value: 'errors' },
673
+ { title: '📘 TypeScript', value: 'typescript' },
674
+ { title: '🧪 Testing', value: 'testing' },
675
+ { title: '📖 API Reference', value: 'api_reference' },
676
+ { title: '🌐 API Endpoints', value: 'endpoints' },
677
+ { title: chalk.gray('← Back'), value: '__back__' },
678
+ { title: chalk.gray('✕ Exit'), value: '__exit__' }
679
+ ];
680
+
681
+ const response = await prompts({
682
+ type: 'select',
683
+ name: 'section',
684
+ message: 'Select documentation section:',
685
+ choices: choices
686
+ });
687
+
688
+ return response.section;
689
+ }
690
+
691
+ async function showInteractiveDocs() {
692
+ console.log(chalk.yellow('\n🍠 SPAPS SDK Documentation\n'));
693
+
694
+ while (true) {
695
+ const section = await showDocsMenu();
696
+
697
+ if (!section || section === '__exit__') {
698
+ console.log(chalk.gray('\nGoodbye! 👋\n'));
699
+ process.exit(0);
700
+ }
701
+
702
+ if (section === '__back__') {
703
+ return; // Go back to main help
704
+ }
705
+
706
+ if (section === 'endpoints') {
707
+ console.log(chalk.yellow(`\n${API_ENDPOINTS.title}`));
708
+ console.log(API_ENDPOINTS.content);
709
+ } else if (SDK_DOCS[section]) {
710
+ const doc = SDK_DOCS[section];
711
+ console.log(chalk.yellow(`\n${doc.title}`));
712
+ console.log(doc.content);
713
+ }
714
+
715
+ // Wait for user to read
716
+ const cont = await prompts({
717
+ type: 'confirm',
718
+ name: 'continue',
719
+ message: 'Continue browsing docs?',
720
+ initial: true
721
+ });
722
+
723
+ if (!cont.continue) {
724
+ console.log(chalk.gray('\nGoodbye! 👋\n'));
725
+ process.exit(0);
726
+ }
727
+ }
728
+ }
729
+
730
+ function showQuickReference() {
731
+ console.log(chalk.yellow('\n🍠 SPAPS SDK Quick Reference\n'));
732
+
733
+ console.log(chalk.green('Installation:'));
734
+ console.log(' npm install spaps-sdk');
735
+ console.log();
736
+
737
+ console.log(chalk.green('Basic Setup:'));
738
+ console.log(chalk.gray(` import { SPAPSClient } from 'spaps-sdk'`));
739
+ console.log(chalk.gray(` const spaps = new SPAPSClient()`));
740
+ console.log();
741
+
742
+ console.log(chalk.green('Common Methods:'));
743
+ console.log(' await spaps.login(email, password)');
744
+ console.log(' await spaps.register(email, password)');
745
+ console.log(' await spaps.getUser()');
746
+ console.log(' await spaps.createCheckoutSession(priceId, successUrl)');
747
+ console.log(' await spaps.getSubscription()');
748
+ console.log(' await spaps.getUsageBalance()');
749
+ console.log();
750
+
751
+ console.log(chalk.green('Helper Methods:'));
752
+ console.log(' spaps.isAuthenticated() ' + chalk.gray('// Check auth status'));
753
+ console.log(' spaps.isLocalMode() ' + chalk.gray('// Check if local mode'));
754
+ console.log(' spaps.getAccessToken() ' + chalk.gray('// Get current token'));
755
+ console.log();
756
+
757
+ console.log(chalk.blue('📚 Full docs: npx spaps docs --interactive'));
758
+ console.log();
759
+ }
760
+
761
+ function searchDocs(query) {
762
+ const results = [];
763
+ const searchTerm = query.toLowerCase();
764
+
765
+ // Search through all documentation
766
+ Object.entries(SDK_DOCS).forEach(([key, doc]) => {
767
+ const content = doc.content.toLowerCase();
768
+ const title = doc.title.toLowerCase();
769
+
770
+ if (title.includes(searchTerm) || content.includes(searchTerm)) {
771
+ // Count occurrences
772
+ const titleMatches = (title.match(new RegExp(searchTerm, 'g')) || []).length;
773
+ const contentMatches = (content.match(new RegExp(searchTerm, 'g')) || []).length;
774
+
775
+ results.push({
776
+ section: key,
777
+ title: doc.title,
778
+ score: titleMatches * 10 + contentMatches,
779
+ preview: extractPreview(doc.content, searchTerm)
780
+ });
781
+ }
782
+ });
783
+
784
+ // Sort by relevance
785
+ results.sort((a, b) => b.score - a.score);
786
+
787
+ return results.slice(0, 5); // Top 5 results
788
+ }
789
+
790
+ function extractPreview(content, searchTerm) {
791
+ const lines = content.split('\n');
792
+ for (const line of lines) {
793
+ if (line.toLowerCase().includes(searchTerm)) {
794
+ return line.trim().substring(0, 80) + '...';
795
+ }
796
+ }
797
+ return lines[0].trim().substring(0, 80) + '...';
798
+ }
799
+
800
+ module.exports = {
801
+ showInteractiveDocs,
802
+ showQuickReference,
803
+ searchDocs,
804
+ SDK_DOCS,
805
+ API_ENDPOINTS
806
+ };