@@ -5,22 +5,11 @@ import { existsSync, readFileSync } from 'node:fs';
55import { join } from 'node:path' ;
66import { runSetup , type SetupContext , type SetupPromptDef , type AdapterWithSetup } from '@profullstack/sh1pt-core' ;
77import { ensureInstalled , loadInstalledPackage } from '../installer.js' ;
8+ import { parsePaymentsSummary , type PaymentsSummary } from './config-payments.js' ;
89
9- type Stack = 'node' | 'bun' | 'python' | 'rust' | 'cpp' | 'dotnet' | 'custom' ;
10-
11- type PaymentProviderSummary = {
12- key : string ;
13- use : string ;
14- enabled : boolean ;
15- isDefault : boolean ;
16- } ;
10+ export { parsePaymentsSummary } from './config-payments.js' ;
1711
18- type PaymentsSummary = {
19- path : string ;
20- defaultProvider ?: string ;
21- platformFeeBps ?: number ;
22- providers : PaymentProviderSummary [ ] ;
23- } ;
12+ type Stack = 'node' | 'bun' | 'python' | 'rust' | 'cpp' | 'dotnet' | 'custom' ;
2413
2514const STACKS : Array < { value : Stack ; title : string ; description : string ; supported : boolean } > = [
2615 { value : 'node' , title : 'Node + TypeScript + React' , description : 'Next.js / Expo / Tauri / Chrome ext' , supported : true } ,
@@ -417,25 +406,6 @@ function urlKeyFor(target: string): string {
417406 } as Record < string , string > ) [ target ] ?? 'WEBHOOK_URL' ;
418407}
419408
420- export function parsePaymentsSummary ( source : string , path = 'sh1pt.config.ts' ) : PaymentsSummary | undefined {
421- const payments = readObjectBody ( source , 'payments' ) ;
422- if ( ! payments ) return undefined ;
423- const providers = readObjectBody ( payments , 'providers' ) ;
424- const defaultProvider = readStringProperty ( payments , 'defaultProvider' ) ;
425- const fee = readNumberProperty ( payments , 'platformFeeBps' ) ;
426- const providerBlocks = providers ? readTopLevelObjectEntries ( providers ) : [ ] ;
427- return {
428- path,
429- defaultProvider,
430- platformFeeBps : fee ,
431- providers : providerBlocks . map ( ( { key, body } ) => {
432- const use = readStringProperty ( body , 'use' ) ?? key ;
433- const enabled = readBooleanProperty ( body , 'enabled' ) ?? true ;
434- return { key, use, enabled, isDefault : use === defaultProvider || key === defaultProvider } ;
435- } ) ,
436- } ;
437- }
438-
439409function readPaymentsSummary ( cwd : string , configPath : string ) : PaymentsSummary {
440410 const path = configPath . startsWith ( '/' ) ? configPath : join ( cwd , configPath ) ;
441411 if ( ! existsSync ( path ) ) {
@@ -465,76 +435,6 @@ function renderPaymentsSummary(summary: PaymentsSummary): void {
465435 }
466436}
467437
468- function readObjectBody ( source : string , property : string ) : string | undefined {
469- const match = new RegExp ( `(?:^|[,{\\s])${ escapeRegExp ( property ) } \\s*:` ) . exec ( source ) ;
470- if ( ! match ) return undefined ;
471- const open = source . indexOf ( '{' , match . index + match [ 0 ] . length ) ;
472- if ( open === - 1 ) return undefined ;
473- const close = findMatchingBrace ( source , open ) ;
474- return close === - 1 ? undefined : source . slice ( open + 1 , close ) ;
475- }
476-
477- function readTopLevelObjectEntries ( source : string ) : Array < { key : string ; body : string } > {
478- const entries : Array < { key : string ; body : string } > = [ ] ;
479- const keyRe = / (?: ^ | , ) \s * ( [ ' " ] ? [ A - Z a - z 0 - 9 _ - ] + [ ' " ] ? ) \s * : / g;
480- let match : RegExpExecArray | null ;
481- while ( ( match = keyRe . exec ( source ) ) ) {
482- const rawKey = match [ 1 ] ;
483- if ( ! rawKey ) continue ;
484- const open = source . indexOf ( '{' , keyRe . lastIndex ) ;
485- if ( open === - 1 ) continue ;
486- const between = source . slice ( keyRe . lastIndex , open ) . trim ( ) ;
487- if ( between . length > 0 ) continue ;
488- const close = findMatchingBrace ( source , open ) ;
489- if ( close === - 1 ) continue ;
490- entries . push ( { key : rawKey . replace ( / ^ [ ' " ] | [ ' " ] $ / g, '' ) , body : source . slice ( open + 1 , close ) } ) ;
491- keyRe . lastIndex = close + 1 ;
492- }
493- return entries ;
494- }
495-
496- function findMatchingBrace ( source : string , open : number ) : number {
497- let depth = 0 ;
498- let quote : '"' | "'" | '`' | undefined ;
499- for ( let i = open ; i < source . length ; i += 1 ) {
500- const ch = source [ i ] ;
501- const prev = source [ i - 1 ] ;
502- if ( quote ) {
503- if ( ch === quote && prev !== '\\' ) quote = undefined ;
504- continue ;
505- }
506- if ( ch === '"' || ch === "'" || ch === '`' ) {
507- quote = ch ;
508- continue ;
509- }
510- if ( ch === '{' ) depth += 1 ;
511- if ( ch === '}' ) {
512- depth -= 1 ;
513- if ( depth === 0 ) return i ;
514- }
515- }
516- return - 1 ;
517- }
518-
519- function readStringProperty ( source : string , key : string ) : string | undefined {
520- const match = new RegExp ( `${ escapeRegExp ( key ) } \\s*:\\s*['"]([^'"]+)['"]` ) . exec ( source ) ;
521- return match ?. [ 1 ] ;
522- }
523-
524- function readNumberProperty ( source : string , key : string ) : number | undefined {
525- const match = new RegExp ( `${ escapeRegExp ( key ) } \\s*:\\s*(\\d+)` ) . exec ( source ) ;
526- return match ?. [ 1 ] ? Number ( match [ 1 ] ) : undefined ;
527- }
528-
529- function readBooleanProperty ( source : string , key : string ) : boolean | undefined {
530- const match = new RegExp ( `${ escapeRegExp ( key ) } \\s*:\\s*(true|false)` ) . exec ( source ) ;
531- return match ?. [ 1 ] === undefined ? undefined : match [ 1 ] === 'true' ;
532- }
533-
534- function escapeRegExp ( input : string ) : string {
535- return input . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
536- }
537-
538438// Build the SetupContext the CLI hands to every adapter.setup(). Today
539439// secrets live in-process + logged; a real vault lands once `sh1pt login`
540440// has an API to write against.
0 commit comments