spaps 0.7.7 → 0.7.8

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
@@ -77,9 +77,11 @@ Restore order is always: restore base dump first, then let the API container run
77
77
  Run it without installing:
78
78
 
79
79
  ```bash
80
- npx spaps
80
+ npx --yes spaps
81
81
  ```
82
82
 
83
+ For CI, SSH automation, or the first run on a fresh box, prefer `npx --yes spaps ...` so npm does not block on its install confirmation prompt.
84
+
83
85
  Install globally:
84
86
 
85
87
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spaps",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "description": "Sweet Potato Authentication & Payment Service CLI - Docker Compose orchestrator for local Python/FastAPI SPAPS server with built-in admin middleware",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/auth/env.js CHANGED
@@ -23,6 +23,10 @@ function isHeadless(env = process.env, platform = process.platform) {
23
23
  return isSsh(env) || !hasGui(env, platform);
24
24
  }
25
25
 
26
+ function hasInteractiveTerminal(stdin = process.stdin, stdout = process.stdout) {
27
+ return Boolean(stdin && stdin.isTTY && stdout && stdout.isTTY);
28
+ }
29
+
26
30
  function tryOpenBrowser(url, { env = process.env, platform = process.platform } = {}) {
27
31
  if (isHeadless(env, platform)) return false;
28
32
  try {
@@ -53,5 +57,6 @@ module.exports = {
53
57
  isSsh,
54
58
  hasGui,
55
59
  isHeadless,
60
+ hasInteractiveTerminal,
56
61
  tryOpenBrowser,
57
62
  };
@@ -0,0 +1,37 @@
1
+ const chalk = require('chalk');
2
+
3
+ function showQuickReference() {
4
+ const output = [
5
+ '',
6
+ chalk.yellow('šŸ  SPAPS SDK Quick Reference'),
7
+ '',
8
+ chalk.green('Installation:'),
9
+ ' npm install spaps-sdk',
10
+ '',
11
+ chalk.green('Basic Setup:'),
12
+ chalk.gray(` import { SPAPSClient } from 'spaps-sdk'`),
13
+ chalk.gray(` const spaps = new SPAPSClient()`),
14
+ '',
15
+ chalk.green('Common Methods:'),
16
+ ' await spaps.login(email, password)',
17
+ ' await spaps.register(email, password)',
18
+ ' await spaps.getUser()',
19
+ ' await spaps.createCheckoutSession(priceId, successUrl)',
20
+ ' await spaps.getSubscription()',
21
+ ' await spaps.getUsageBalance()',
22
+ '',
23
+ chalk.green('Helper Methods:'),
24
+ ` spaps.isAuthenticated() ${chalk.gray('// Check auth status')}`,
25
+ ` spaps.isLocalMode() ${chalk.gray('// Check if local mode')}`,
26
+ ` spaps.getAccessToken() ${chalk.gray('// Get current token')}`,
27
+ '',
28
+ chalk.blue('šŸ“š Full docs: npx spaps docs --interactive'),
29
+ '',
30
+ ].join('\n');
31
+
32
+ process.stdout.write(`${output}\n`);
33
+ }
34
+
35
+ module.exports = {
36
+ showQuickReference,
37
+ };
@@ -5,6 +5,7 @@
5
5
 
6
6
  const chalk = require('chalk');
7
7
  const prompts = require('prompts');
8
+ const { showQuickReference } = require('./docs-quick');
8
9
 
9
10
  const SDK_DOCS = {
10
11
  quickstart: {
@@ -676,37 +677,6 @@ async function showInteractiveDocs() {
676
677
  }
677
678
  }
678
679
 
679
- function showQuickReference() {
680
- console.log(chalk.yellow('\nšŸ  SPAPS SDK Quick Reference\n'));
681
-
682
- console.log(chalk.green('Installation:'));
683
- console.log(' npm install spaps-sdk');
684
- console.log();
685
-
686
- console.log(chalk.green('Basic Setup:'));
687
- console.log(chalk.gray(` import { SPAPSClient } from 'spaps-sdk'`));
688
- console.log(chalk.gray(` const spaps = new SPAPSClient()`));
689
- console.log();
690
-
691
- console.log(chalk.green('Common Methods:'));
692
- console.log(' await spaps.login(email, password)');
693
- console.log(' await spaps.register(email, password)');
694
- console.log(' await spaps.getUser()');
695
- console.log(' await spaps.createCheckoutSession(priceId, successUrl)');
696
- console.log(' await spaps.getSubscription()');
697
- console.log(' await spaps.getUsageBalance()');
698
- console.log();
699
-
700
- console.log(chalk.green('Helper Methods:'));
701
- console.log(' spaps.isAuthenticated() ' + chalk.gray('// Check auth status'));
702
- console.log(' spaps.isLocalMode() ' + chalk.gray('// Check if local mode'));
703
- console.log(' spaps.getAccessToken() ' + chalk.gray('// Get current token'));
704
- console.log();
705
-
706
- console.log(chalk.blue('šŸ“š Full docs: npx spaps docs --interactive'));
707
- console.log();
708
- }
709
-
710
680
  function searchDocs(query) {
711
681
  const results = [];
712
682
  const searchTerm = query.toLowerCase();
package/src/handlers.js CHANGED
@@ -2,26 +2,30 @@ const chalk = require('chalk');
2
2
  const fs = require('fs');
3
3
  const { DEFAULT_PORT } = require('./config');
4
4
  const { handleError } = require('./error-handler');
5
- const { showInteractiveHelp, showQuickHelp } = require('./help-system');
6
- const { showInteractiveDocs, showQuickReference, searchDocs } = require('./docs-system');
7
- const { getQuickStartInstructions, getServerStatus, runQuickTest } = require('./ai-helper');
8
- const { buildToolSpec } = require('./ai-tool-spec');
9
- const { runDoctor } = require('./doctor');
10
- const { buildHomeView, renderHomeView } = require('./home-view');
11
- const {
12
- applyFixtures,
13
- exportStorageState,
14
- initFixtureKernel,
15
- resetFixtures,
16
- } = require('./fixture-kernel');
17
- const { createProjectStarter } = require('./project-scaffolder');
18
- const {
19
- loginHandler,
20
- logoutHandler,
21
- whoamiHandler,
22
- tokenHandler,
23
- } = require('./auth/handlers');
24
- const { callEndpoint, emit, emitAuthError } = require('./domain-cli');
5
+ const { hasInteractiveTerminal } = require('./auth/env');
6
+ const { showQuickHelp } = require('./help-quick');
7
+ const { showQuickReference } = require('./docs-quick');
8
+
9
+ function lazy(factory) {
10
+ let value;
11
+ return () => {
12
+ if (value === undefined) {
13
+ value = factory();
14
+ }
15
+ return value;
16
+ };
17
+ }
18
+
19
+ const loadHelpSystem = lazy(() => require('./help-system'));
20
+ const loadDocsSystem = lazy(() => require('./docs-system'));
21
+ const loadAiHelper = lazy(() => require('./ai-helper'));
22
+ const loadAiToolSpec = lazy(() => require('./ai-tool-spec'));
23
+ const loadDoctor = lazy(() => require('./doctor'));
24
+ const loadHomeView = lazy(() => require('./home-view'));
25
+ const loadFixtureKernel = lazy(() => require('./fixture-kernel'));
26
+ const loadProjectScaffolder = lazy(() => require('./project-scaffolder'));
27
+ const loadAuthCommandHandlers = lazy(() => require('./auth/handlers'));
28
+ const loadDomainCli = lazy(() => require('./domain-cli'));
25
29
 
26
30
  function createHandlers(version, logo) {
27
31
  function invalidArgument(message) {
@@ -30,7 +34,14 @@ function createHandlers(version, logo) {
30
34
  return error;
31
35
  }
32
36
 
37
+ function emitInteractiveFallback(message) {
38
+ console.log(
39
+ chalk.yellow(`\nāš ļø ${message}. Showing the quick reference instead.\n`)
40
+ );
41
+ }
42
+
33
43
  const verifyHandler = async ({ options }) => {
44
+ const { runQuickTest } = loadAiHelper();
34
45
  const result = await runQuickTest({
35
46
  port: options.port,
36
47
  serverUrl: options.serverUrl,
@@ -65,6 +76,7 @@ function createHandlers(version, logo) {
65
76
 
66
77
  return {
67
78
  home: async ({ options }) => {
79
+ const { buildHomeView, renderHomeView } = loadHomeView();
68
80
  const view = await buildHomeView({
69
81
  port: options.port,
70
82
  serverUrl: options.serverUrl,
@@ -135,6 +147,7 @@ function createHandlers(version, logo) {
135
147
  }
136
148
  },
137
149
  quickstart: async ({ options }) => {
150
+ const { getQuickStartInstructions } = loadAiHelper();
138
151
  const instructions = await getQuickStartInstructions(options.port);
139
152
  if (options.json) {
140
153
  console.log(JSON.stringify(instructions, null, 2));
@@ -153,6 +166,7 @@ function createHandlers(version, logo) {
153
166
  }
154
167
  },
155
168
  status: async ({ options }) => {
169
+ const { getServerStatus } = loadAiHelper();
156
170
  const status = await getServerStatus(options.port);
157
171
  if (options.json) {
158
172
  console.log(JSON.stringify(status));
@@ -204,6 +218,7 @@ function createHandlers(version, logo) {
204
218
  },
205
219
  create: async ({ options }) => {
206
220
  const isJson = options.json;
221
+ const { createProjectStarter } = loadProjectScaffolder();
207
222
 
208
223
  try {
209
224
  const result = await createProjectStarter({
@@ -269,7 +284,12 @@ function createHandlers(version, logo) {
269
284
  },
270
285
  help: async ({ options }) => {
271
286
  if (options.interactive) {
272
- await showInteractiveHelp();
287
+ if (!hasInteractiveTerminal()) {
288
+ emitInteractiveFallback('Interactive help requires a TTY');
289
+ showQuickHelp();
290
+ return;
291
+ }
292
+ await loadHelpSystem().showInteractiveHelp();
273
293
  } else if (options.quick) {
274
294
  showQuickHelp();
275
295
  } else {
@@ -278,7 +298,7 @@ function createHandlers(version, logo) {
278
298
  },
279
299
  docs: async ({ options }) => {
280
300
  if (options.search) {
281
- const results = searchDocs(options.search);
301
+ const results = loadDocsSystem().searchDocs(options.search);
282
302
  if (options.json) {
283
303
  console.log(JSON.stringify({ results }, null, 2));
284
304
  } else {
@@ -296,12 +316,18 @@ function createHandlers(version, logo) {
296
316
  console.log(chalk.blue(' to browse full documentation\n'));
297
317
  }
298
318
  } else if (options.interactive) {
299
- await showInteractiveDocs();
319
+ if (!hasInteractiveTerminal()) {
320
+ emitInteractiveFallback('Interactive docs require a TTY');
321
+ showQuickReference();
322
+ return;
323
+ }
324
+ await loadDocsSystem().showInteractiveDocs();
300
325
  } else {
301
326
  showQuickReference();
302
327
  }
303
328
  },
304
329
  tools: async ({ options }) => {
330
+ const { buildToolSpec } = loadAiToolSpec();
305
331
  const spec = await buildToolSpec({
306
332
  format: options.format || 'openai',
307
333
  port: options.port,
@@ -328,6 +354,12 @@ function createHandlers(version, logo) {
328
354
  },
329
355
  fixtures: async ({ options }) => {
330
356
  const isJson = options.json;
357
+ const {
358
+ applyFixtures,
359
+ exportStorageState,
360
+ initFixtureKernel,
361
+ resetFixtures,
362
+ } = loadFixtureKernel();
331
363
 
332
364
  try {
333
365
  if (options.format && options.format !== 'playwright') {
@@ -465,13 +497,14 @@ function createHandlers(version, logo) {
465
497
  }
466
498
  },
467
499
  doctor: async ({ options }) => {
500
+ const { runDoctor } = loadDoctor();
468
501
  await runDoctor({ port: options.port || DEFAULT_PORT, stripe: options.stripe || null, json: options.json });
469
502
  },
470
503
  test: verifyHandler,
471
- login: loginHandler,
472
- logout: logoutHandler,
473
- whoami: whoamiHandler,
474
- token: tokenHandler,
504
+ login: async (...args) => loadAuthCommandHandlers().loginHandler(...args),
505
+ logout: async (...args) => loadAuthCommandHandlers().logoutHandler(...args),
506
+ whoami: async (...args) => loadAuthCommandHandlers().whoamiHandler(...args),
507
+ token: async (...args) => loadAuthCommandHandlers().tokenHandler(...args),
475
508
  dayrate: dayrateHandler,
476
509
  email: emailHandler,
477
510
  policy: policyHandler,
@@ -481,6 +514,7 @@ function createHandlers(version, logo) {
481
514
  }
482
515
 
483
516
  function emitText({ intent, result, isJson, successMessage = null }) {
517
+ const { emit } = loadDomainCli();
484
518
  if (isJson) {
485
519
  emit({ intent, result, isJson, successMessage });
486
520
  return;
@@ -548,6 +582,7 @@ function assignIfDefined(target, key, value) {
548
582
  }
549
583
 
550
584
  async function dayrateHandler({ options }) {
585
+ const { callEndpoint, emit, emitAuthError } = loadDomainCli();
551
586
  const isJson = Boolean(options.json);
552
587
  const sub = options.subcommand;
553
588
  if (sub !== 'config') {
@@ -566,6 +601,7 @@ async function dayrateHandler({ options }) {
566
601
  }
567
602
 
568
603
  async function emailHandler({ options }) {
604
+ const { callEndpoint, emit, emitAuthError } = loadDomainCli();
569
605
  const isJson = Boolean(options.json);
570
606
  const sub = options.subcommand;
571
607
 
@@ -777,6 +813,7 @@ async function emailHandler({ options }) {
777
813
  }
778
814
 
779
815
  async function policyHandler({ options }) {
816
+ const { callEndpoint, emit, emitAuthError } = loadDomainCli();
780
817
  const isJson = Boolean(options.json);
781
818
  const sub = options.subcommand;
782
819
  try {
@@ -832,6 +869,7 @@ async function policyHandler({ options }) {
832
869
  }
833
870
 
834
871
  async function webhookHandler({ options }) {
872
+ const { callEndpoint, emit, emitAuthError } = loadDomainCli();
835
873
  const isJson = Boolean(options.json);
836
874
  const sub = options.subcommand;
837
875
  try {
@@ -863,6 +901,7 @@ async function webhookHandler({ options }) {
863
901
  }
864
902
 
865
903
  async function issueReportsHandler({ options }) {
904
+ const { callEndpoint, emit, emitAuthError } = loadDomainCli();
866
905
  const isJson = Boolean(options.json);
867
906
  const sub = options.subcommand;
868
907
  if (sub !== 'list-mine') {
@@ -0,0 +1,42 @@
1
+ const chalk = require('chalk');
2
+
3
+ function showQuickHelp() {
4
+ const output = [
5
+ '',
6
+ chalk.yellow('šŸ  SPAPS Quick Reference'),
7
+ '',
8
+ chalk.green('Common Commands:'),
9
+ ` npx spaps local ${chalk.gray('# Start local server')}`,
10
+ ` npx spaps init ${chalk.gray('# Initialize in project')}`,
11
+ ` npx spaps create <name> ${chalk.gray('# Scaffold a SPAPS starter project')}`,
12
+ ` npx spaps fixtures apply ${chalk.gray('# Generate repo-local auth fixtures')}`,
13
+ ` npx spaps fixtures storage-state ${chalk.gray('# Export one persona artifact')}`,
14
+ ` npx spaps types ${chalk.gray('# Generate types (v0.4.0)')}`,
15
+ '',
16
+ chalk.green('Local Development:'),
17
+ ` npx spaps local --port 3001 ${chalk.gray('# Custom port')}`,
18
+ ` npx spaps local --open ${chalk.gray('# Open browser')}`,
19
+ ` npx spaps local --json ${chalk.gray('# JSON output')}`,
20
+ '',
21
+ chalk.green('SDK Usage:'),
22
+ ` npm install spaps-sdk ${chalk.gray('# Install SDK')}`,
23
+ '',
24
+ chalk.gray(' import { SPAPSClient } from "spaps-sdk"'),
25
+ chalk.gray(' const spaps = new SPAPSClient()'),
26
+ chalk.gray(' await spaps.login(email, password)'),
27
+ '',
28
+ chalk.green('Debugging:'),
29
+ ` curl http://localhost:3301/health ${chalk.gray('# Check server')}`,
30
+ ` npx spaps help --interactive ${chalk.gray('# Interactive help')}`,
31
+ '',
32
+ chalk.blue('šŸ“š Docs: https://sweetpotato.dev'),
33
+ chalk.blue('šŸ’¬ Discord: https://discord.gg/sweetpotato'),
34
+ '',
35
+ ].join('\n');
36
+
37
+ process.stdout.write(`${output}\n`);
38
+ }
39
+
40
+ module.exports = {
41
+ showQuickHelp,
42
+ };
@@ -7,6 +7,7 @@ const chalk = require('chalk');
7
7
  const prompts = require('prompts');
8
8
 
9
9
  const { DEFAULT_PORT } = require('./config');
10
+ const { showQuickHelp } = require('./help-quick');
10
11
 
11
12
  const HELP_TREE = {
12
13
  root: {
@@ -448,42 +449,6 @@ async function showInteractiveHelp() {
448
449
  }
449
450
  }
450
451
 
451
- function showQuickHelp() {
452
- console.log(chalk.yellow('\nšŸ  SPAPS Quick Reference\n'));
453
-
454
- console.log(chalk.green('Common Commands:'));
455
- console.log(' npx spaps local ' + chalk.gray('# Start local server'));
456
- console.log(' npx spaps init ' + chalk.gray('# Initialize in project'));
457
- console.log(' npx spaps create <name> ' + chalk.gray('# Scaffold a SPAPS starter project'));
458
- console.log(' npx spaps fixtures apply ' + chalk.gray('# Generate repo-local auth fixtures'));
459
- console.log(' npx spaps fixtures storage-state ' + chalk.gray('# Export one persona artifact'));
460
- console.log(' npx spaps types ' + chalk.gray('# Generate types (v0.4.0)'));
461
- console.log();
462
-
463
- console.log(chalk.green('Local Development:'));
464
- console.log(' npx spaps local --port 3001 ' + chalk.gray('# Custom port'));
465
- console.log(' npx spaps local --open ' + chalk.gray('# Open browser'));
466
- console.log(' npx spaps local --json ' + chalk.gray('# JSON output'));
467
- console.log();
468
-
469
- console.log(chalk.green('SDK Usage:'));
470
- console.log(' npm install spaps-sdk ' + chalk.gray('# Install SDK'));
471
- console.log();
472
- console.log(chalk.gray(' import { SPAPSClient } from "spaps-sdk"'));
473
- console.log(chalk.gray(' const spaps = new SPAPSClient()'));
474
- console.log(chalk.gray(' await spaps.login(email, password)'));
475
- console.log();
476
-
477
- console.log(chalk.green('Debugging:'));
478
- console.log(' curl http://localhost:3301/health ' + chalk.gray('# Check server'));
479
- console.log(' npx spaps help --interactive ' + chalk.gray('# Interactive help'));
480
- console.log();
481
-
482
- console.log(chalk.blue('šŸ“š Docs: https://sweetpotato.dev'));
483
- console.log(chalk.blue('šŸ’¬ Discord: https://discord.gg/sweetpotato'));
484
- console.log();
485
- }
486
-
487
452
  module.exports = {
488
453
  showInteractiveHelp,
489
454
  showQuickHelp,