1- // filepath: /Users/sahil.t/StudioProjects/dynamic_chat_web/netlify/edge-functions/get-package-data.js
2- // MANUAL TOGGLE: Set to true for production mode, false for local development mode
3- const FORCE_PRODUCTION_MODE = true ;
1+ // filepath: netlify/edge-functions/get-package-data.js
2+ import { getStore } from '@netlify/blobs' ;
43
5- // The namespace used by the scheduled function
64const NAMESPACE = 'package-scores' ;
75
8- // Simple in-memory cache for local development
9- const localCache = {
10- data : {
11- 'package-data' : JSON . stringify ( {
12- 'flutter' : {
13- grantedPoints : 150 ,
14- maxPoints : 160 ,
15- likeCount : 2817 ,
16- downloadCount30Days : 156194 ,
17- tags : [
18- 'publisher:simform.com' ,
19- 'sdk:flutter' ,
20- 'platform:android' ,
21- 'platform:ios' ,
22- 'platform:windows' ,
23- 'platform:linux' ,
24- 'platform:macos' ,
25- 'platform:web' ,
26- 'is:null-safe' ,
27- 'is:wasm-ready' ,
28- 'is:dart3-compatible' ,
29- 'license:mit' ,
30- 'license:fsf-libre' ,
31- 'license:osi-approved'
32- ] ,
33- lastUpdated : '2025-04-24T20:09:55.534241'
34- }
35- } ) ,
36- 'last-updated' : JSON . stringify ( new Date ( ) . toISOString ( ) )
37- }
38- } ;
6+ async function getPackageData ( packageName ) {
7+ const store = getStore ( { name : NAMESPACE } ) ;
8+ const raw = await store . get ( `package-${ packageName } ` ) ;
9+ return raw ? JSON . parse ( raw ) : null ;
10+ }
11+
12+ async function getAllPackageData ( ) {
13+ const store = getStore ( { name : NAMESPACE } ) ;
14+ const raw = await store . get ( 'package-data' ) ;
15+ return raw ? JSON . parse ( raw ) : { } ;
16+ }
3917
40- export default async ( request , context ) => {
18+ async function getLastUpdated ( ) {
19+ const store = getStore ( { name : NAMESPACE } ) ;
20+ const raw = await store . get ( 'last-updated' ) ;
21+ return raw ? JSON . parse ( raw ) : null ;
22+ }
23+
24+ export default async ( request ) => {
4125 try {
42- // Parse the URL to get the package name
4326 const url = new URL ( request . url ) ;
4427 const packageName = url . searchParams . get ( 'package' ) ;
45-
46- // Log available context for debugging
47- console . log ( `Available context keys: ${ Object . keys ( context ) . join ( ', ' ) } ` ) ;
48- if ( context . env ) {
49- console . log ( `Available env keys: ${ Object . keys ( context . env ) . join ( ', ' ) } ` ) ;
50- }
51-
28+
5229 let data ;
53- let lastUpdated ;
54- let kvAccessMethod = 'none' ;
55-
56- try {
57- console . log ( 'Attempting to access Netlify Edge KV Storage' ) ;
58-
59- // Try several different ways to access KV storage based on the context
60- let kv = null ;
61-
62- // Method 1: Try to get KV from context directly (binding in netlify.toml)
63- if ( context . KV ) {
64- console . log ( 'Found KV in context.KV' ) ;
65- kv = context . KV ;
66- }
67- // Method 2: Try from context.env
68- else if ( context . env && context . env . KV ) {
69- console . log ( 'Found KV in context.env.KV' ) ;
70- kv = context . env . KV ;
71- }
72- // Method 3: Try older netlify edge context pattern
73- else if ( context . site && context . site . kv ) {
74- console . log ( 'Found KV in context.site.kv' ) ;
75- kv = context . site . kv ;
76- }
77- // Method 4: Try via global Netlify object
78- else if ( typeof Netlify !== 'undefined' && Netlify . env && Netlify . env . get ) {
79- console . log ( 'Using global Netlify.env.get("KV")' ) ;
80- kv = Netlify . env . get ( "KV" ) ;
81- }
82-
83- if ( kv ) {
84- console . log ( 'Successfully obtained KV namespace' ) ;
85-
86- // Try with both namespaced and non-namespaced keys
87- let keys = [ ] ;
88- if ( packageName ) {
89- keys = [
90- `${ NAMESPACE } :package-${ packageName } ` ,
91- `package-${ packageName } ` ,
92- `package-scores/package-${ packageName } `
93- ] ;
94- } else {
95- keys = [
96- `${ NAMESPACE } :package-data` ,
97- `package-data` ,
98- `package-scores/package-data`
99- ] ;
100- }
101-
102- // Try each key until we find data
103- for ( const key of keys ) {
104- console . log ( `Trying to access key: ${ key } ` ) ;
105- data = await kv . get ( key ) ;
106-
107- if ( data !== null && data !== undefined ) {
108- console . log ( `Found data using key: ${ key } ` ) ;
109- kvAccessMethod = `kv-with-key-${ key } ` ;
110- break ;
111- }
112- }
113-
114- // Try each key for last updated
115- if ( data ) {
116- const updateKeys = [
117- `${ NAMESPACE } :last-updated` ,
118- `last-updated` ,
119- `package-scores/last-updated`
120- ] ;
121-
122- for ( const key of updateKeys ) {
123- lastUpdated = await kv . get ( key ) ;
124- if ( lastUpdated !== null && lastUpdated !== undefined ) {
125- break ;
126- }
30+ if ( packageName ) {
31+ data = await getPackageData ( packageName ) ;
32+ if ( ! data ) {
33+ return new Response (
34+ JSON . stringify ( {
35+ error : 'Package not found' ,
36+ note : 'Data might not be populated yet by the scheduled function'
37+ } ) ,
38+ {
39+ status : 404 ,
40+ headers : { 'Content-Type' : 'application/json' }
12741 }
128- }
129-
130- if ( ! data ) {
131- throw new Error ( 'No data found in KV store with any key pattern' ) ;
132- }
133- } else {
134- throw new Error ( 'KV namespace not available in Netlify environment' ) ;
42+ ) ;
13543 }
136- } catch ( kvError ) {
137- console . error ( `KV store access error: ${ kvError . message } ` ) ;
138- console . log ( 'Falling back to in-memory cache due to KV access error' ) ;
139-
140- // Access the in-memory cache
141- if ( packageName ) {
142- const allData = JSON . parse ( localCache . data [ 'package-data' ] || '{}' ) ;
143- data = allData [ packageName ] ? JSON . stringify ( allData [ packageName ] ) : null ;
144- } else {
145- data = localCache . data [ 'package-data' ] ;
146- }
147-
148- lastUpdated = localCache . data [ 'last-updated' ] ;
149- kvAccessMethod = 'localCacheFallback' ;
44+ } else {
45+ data = await getAllPackageData ( ) ;
15046 }
151-
152- // Handle case with no data found
153- if ( ! data ) {
154- return new Response ( JSON . stringify ( {
155- error : packageName ? 'Package not found' : 'No data available' ,
156- note : 'Data might not be populated yet by the scheduled function' ,
157- accessMethod : kvAccessMethod
158- } ) , {
159- status : packageName ? 404 : 200 ,
47+
48+ const lastUpdated = await getLastUpdated ( ) ;
49+
50+ return new Response (
51+ JSON . stringify ( {
52+ data,
53+ lastUpdated,
54+ environment : 'production' ,
55+ accessMethod : 'blob-storage'
56+ } ) ,
57+ {
58+ status : 200 ,
16059 headers : {
16160 'Content-Type' : 'application/json' ,
162- 'Cache-Control' : 'no-cache '
61+ 'Cache-Control' : 'public, max-age=60 '
16362 }
164- } ) ;
165- }
166-
167- // Handle different KV response formats
168- // Some KV implementations return { value: data }, others return data directly
169- if ( data && typeof data === 'object' && data . value !== undefined ) {
170- data = data . value ;
171- }
172- if ( lastUpdated && typeof lastUpdated === 'object' && lastUpdated . value !== undefined ) {
173- lastUpdated = lastUpdated . value ;
174- }
175-
176- // Parse the data if needed
177- if ( typeof data === 'string' ) {
178- try {
179- data = JSON . parse ( data ) ;
180- } catch ( parseError ) {
181- console . log ( 'Failed to parse data as JSON, returning as string' ) ;
182- }
183- }
184-
185- // Parse lastUpdated if needed
186- if ( typeof lastUpdated === 'string' ) {
187- try {
188- lastUpdated = JSON . parse ( lastUpdated ) ;
189- } catch ( parseError ) {
190- console . log ( 'Failed to parse lastUpdated as JSON, using as is' ) ;
19163 }
192- }
193-
194- return new Response ( JSON . stringify ( {
195- data,
196- lastUpdated,
197- environment : 'production' ,
198- accessMethod : kvAccessMethod
199- } ) , {
200- status : 200 ,
201- headers : {
202- 'Content-Type' : 'application/json' ,
203- 'Cache-Control' : 'public, max-age=60' // Cache for 1 minute
204- }
205- } ) ;
64+ ) ;
20665 } catch ( error ) {
207- console . error ( `Error serving package data: ${ error . message } ` ) ;
208- return new Response ( JSON . stringify ( {
209- error : 'Failed to retrieve package data' ,
210- message : error . message ,
211- stack : error . stack
212- } ) , {
213- status : 500 ,
214- headers : {
215- 'Content-Type' : 'application/json'
66+ console . error ( 'Edge function error:' , error ) ;
67+ return new Response (
68+ JSON . stringify ( {
69+ error : 'Failed to retrieve package data' ,
70+ message : error . message
71+ } ) ,
72+ {
73+ status : 500 ,
74+ headers : { 'Content-Type' : 'application/json' }
21675 }
217- } ) ;
76+ ) ;
21877 }
219- } ;
78+ } ;
0 commit comments