@@ -9,6 +9,77 @@ const corsHeaders = {
99 'Content-Type' : 'application/json' ,
1010} ;
1111
12+ const MAX_DELAY_MS = 30000 ; // Max 30 seconds
13+
14+ // Parse delay value: 2000, "2s", "500ms"
15+ function parseDelay ( value : string | null ) : number {
16+ if ( ! value ) return 0 ;
17+
18+ const trimmed = value . trim ( ) . toLowerCase ( ) ;
19+
20+ // Parse with suffix
21+ const match = trimmed . match ( / ^ ( \d + (?: \. \d + ) ? ) ( m s | s ) ? $ / ) ;
22+ if ( ! match ) return 0 ;
23+
24+ const num = parseFloat ( match [ 1 ] ) ;
25+ const unit = match [ 2 ] || 'ms' ;
26+
27+ let ms : number ;
28+ if ( unit === 's' ) {
29+ ms = num * 1000 ;
30+ } else {
31+ ms = num ;
32+ }
33+
34+ return Math . min ( Math . max ( 0 , Math . round ( ms ) ) , MAX_DELAY_MS ) ;
35+ }
36+
37+ // Pick specific keys from object
38+ function pickKeys ( obj : unknown , keys : string [ ] ) : unknown {
39+ if ( typeof obj !== 'object' || obj === null ) return obj ;
40+ if ( Array . isArray ( obj ) ) {
41+ return obj . map ( item => pickKeys ( item , keys ) ) ;
42+ }
43+
44+ const result : Record < string , unknown > = { } ;
45+ for ( const key of keys ) {
46+ if ( key in ( obj as Record < string , unknown > ) ) {
47+ result [ key ] = ( obj as Record < string , unknown > ) [ key ] ;
48+ }
49+ }
50+ return result ;
51+ }
52+
53+ // Simple JSONPath implementation (just basic path like "$.users[0].name")
54+ function jsonPath ( obj : unknown , path : string ) : unknown {
55+ if ( ! path . startsWith ( '$.' ) ) return obj ;
56+
57+ const parts = path . slice ( 2 ) . split ( / \. | \[ | \] / ) . filter ( Boolean ) ;
58+ let current : unknown = obj ;
59+
60+ for ( const part of parts ) {
61+ if ( current === null || current === undefined ) return undefined ;
62+
63+ if ( typeof current === 'object' ) {
64+ if ( Array . isArray ( current ) ) {
65+ const index = parseInt ( part , 10 ) ;
66+ if ( ! isNaN ( index ) ) {
67+ current = current [ index ] ;
68+ } else {
69+ // Arrays don't have string keys in this context
70+ return undefined ;
71+ }
72+ } else {
73+ current = ( current as Record < string , unknown > ) [ part ] ;
74+ }
75+ } else {
76+ return undefined ;
77+ }
78+ }
79+
80+ return current ;
81+ }
82+
1283export async function OPTIONS ( ) {
1384 return new NextResponse ( null , {
1485 status : 204 ,
@@ -22,13 +93,24 @@ export async function GET(
2293) {
2394 try {
2495 const { id } = await params ;
96+ const searchParams = request . nextUrl . searchParams ;
97+
98+ // Parse query params
99+ const delay = parseDelay ( searchParams . get ( 'delay' ) ) ;
100+ const pathQuery = searchParams . get ( 'path' ) ;
101+ const pickQuery = searchParams . get ( 'pick' ) ;
102+
103+ // Apply delay if specified
104+ if ( delay > 0 ) {
105+ await new Promise ( resolve => setTimeout ( resolve , delay ) ) ;
106+ }
25107
26108 const result = await sql `
27- SELECT content, expires_at
28- FROM json_bins
29- WHERE id = ${ id }
30- AND (expires_at IS NULL OR expires_at > NOW())
31- ` ;
109+ SELECT content, expires_at
110+ FROM json_bins
111+ WHERE id = ${ id }
112+ AND (expires_at IS NULL OR expires_at > NOW())
113+ ` ;
32114
33115 if ( result . length === 0 ) {
34116 return NextResponse . json (
@@ -37,10 +119,40 @@ export async function GET(
37119 ) ;
38120 }
39121
40- // Return raw JSON content
41- return new NextResponse ( result [ 0 ] . content , {
122+ let content = result [ 0 ] . content ;
123+ let parsed : unknown ;
124+
125+ // Apply transformations if requested
126+ if ( pathQuery || pickQuery ) {
127+ try {
128+ parsed = JSON . parse ( content ) ;
129+
130+ // Apply JSONPath
131+ if ( pathQuery ) {
132+ parsed = jsonPath ( parsed , pathQuery ) ;
133+ }
134+
135+ // Apply pick keys
136+ if ( pickQuery ) {
137+ const keys = pickQuery . split ( ',' ) . map ( k => k . trim ( ) ) . filter ( Boolean ) ;
138+ if ( keys . length > 0 ) {
139+ parsed = pickKeys ( parsed , keys ) ;
140+ }
141+ }
142+
143+ content = JSON . stringify ( parsed ) ;
144+ } catch {
145+ // If parsing fails, return original content
146+ }
147+ }
148+
149+ // Return JSON content
150+ return new NextResponse ( content , {
42151 status : 200 ,
43- headers : corsHeaders ,
152+ headers : {
153+ ...corsHeaders ,
154+ 'X-Delay-Applied' : delay > 0 ? `${ delay } ms` : '0' ,
155+ } ,
44156 } ) ;
45157 } catch ( error ) {
46158 console . error ( 'Error fetching JSON:' , error ) ;
0 commit comments