22 * Shared utilities for fetching GitHub releases.
33 */
44
5- import { createTtlCache } from '@socketsecurity/lib/cache-with-ttl'
65import { safeMkdir } from '@socketsecurity/lib/fs'
76import { httpDownload , httpRequest } from '@socketsecurity/lib/http-request'
87import { getDefaultLogger } from '@socketsecurity/lib/logger'
@@ -13,13 +12,6 @@ const logger = getDefaultLogger()
1312const OWNER = 'SocketDev'
1413const REPO = 'socket-btm'
1514
16- // Cache GitHub API responses for 1 hour to avoid rate limiting.
17- const cache = createTtlCache ( {
18- memoize : true ,
19- prefix : 'github-releases' ,
20- ttl : 60 * 60 * 1000 , // 1 hour.
21- } )
22-
2315/**
2416 * Get GitHub authentication headers if token is available.
2517 *
@@ -46,56 +38,52 @@ function getAuthHeaders() {
4638 * @returns {Promise<string|null> } - Latest release tag or null if not found.
4739 */
4840export async function getLatestRelease ( tool , { quiet = false } = { } ) {
49- const cacheKey = `latest-release:${ tool } `
50-
51- return await cache . getOrFetch ( cacheKey , async ( ) => {
52- return await pRetry (
53- async ( ) => {
54- const response = await httpRequest (
55- `https://api.github.com/repos/${ OWNER } /${ REPO } /releases?per_page=100` ,
56- {
57- headers : getAuthHeaders ( ) ,
58- } ,
59- )
60-
61- if ( ! response . ok ) {
62- throw new Error ( `Failed to fetch releases: ${ response . status } ` )
63- }
41+ return await pRetry (
42+ async ( ) => {
43+ const response = await httpRequest (
44+ `https://api.github.com/repos/${ OWNER } /${ REPO } /releases?per_page=100` ,
45+ {
46+ headers : getAuthHeaders ( ) ,
47+ } ,
48+ )
6449
65- const releases = JSON . parse ( response . body )
50+ if ( ! response . ok ) {
51+ throw new Error ( `Failed to fetch releases: ${ response . status } ` )
52+ }
6653
67- // Find the first release matching the tool prefix.
68- for ( const release of releases ) {
69- const { tag_name : tag } = release
70- if ( tag . startsWith ( ` ${ tool } -` ) ) {
71- if ( ! quiet ) {
72- logger . info ( ` Found release: ${ tag } ` )
73- }
74- return tag
54+ const releases = JSON . parse ( response . body )
55+
56+ // Find the first release matching the tool prefix.
57+ for ( const release of releases ) {
58+ const { tag_name : tag } = release
59+ if ( tag . startsWith ( ` ${ tool } -` ) ) {
60+ if ( ! quiet ) {
61+ logger . info ( ` Found release: ${ tag } ` )
7562 }
63+ return tag
7664 }
77-
78- // No matching release found in the list.
65+ }
66+
67+ // No matching release found in the list.
68+ if ( ! quiet ) {
69+ logger . info ( ` No ${ tool } release found in latest 100 releases` )
70+ }
71+ return null
72+ } ,
73+ {
74+ backoffFactor : 1 ,
75+ baseDelayMs : 5000 ,
76+ onRetry : ( attempt , error ) => {
7977 if ( ! quiet ) {
80- logger . info ( ` No ${ tool } release found in latest 100 releases` )
78+ logger . info (
79+ ` Retry attempt ${ attempt + 1 } /3 for ${ tool } release list...` ,
80+ )
81+ logger . warn ( ` Attempt ${ attempt + 1 } /3 failed: ${ error . message } ` )
8182 }
82- return null
8383 } ,
84- {
85- backoffFactor : 1 ,
86- baseDelayMs : 5000 ,
87- onRetry : ( attempt , error ) => {
88- if ( ! quiet ) {
89- logger . info (
90- ` Retry attempt ${ attempt + 1 } /3 for ${ tool } release list...` ,
91- )
92- logger . warn ( ` Attempt ${ attempt + 1 } /3 failed: ${ error . message } ` )
93- }
94- } ,
95- retries : 2 ,
96- } ,
97- )
98- } )
84+ retries : 2 ,
85+ } ,
86+ )
9987}
10088
10189/**
@@ -115,50 +103,46 @@ export async function getReleaseAssetUrl(
115103 assetName ,
116104 { quiet = false } = { } ,
117105) {
118- const cacheKey = `asset-url:${ tag } :${ assetName } `
119-
120- return await cache . getOrFetch ( cacheKey , async ( ) => {
121- return await pRetry (
122- async ( ) => {
123- const response = await httpRequest (
124- `https://api.github.com/repos/${ OWNER } /${ REPO } /releases/tags/${ tag } ` ,
125- {
126- headers : getAuthHeaders ( ) ,
127- } ,
128- )
129-
130- if ( ! response . ok ) {
131- throw new Error ( `Failed to fetch release ${ tag } : ${ response . status } ` )
132- }
106+ return await pRetry (
107+ async ( ) => {
108+ const response = await httpRequest (
109+ `https://api.github.com/repos/${ OWNER } /${ REPO } /releases/tags/${ tag } ` ,
110+ {
111+ headers : getAuthHeaders ( ) ,
112+ } ,
113+ )
133114
134- const release = JSON . parse ( response . body )
115+ if ( ! response . ok ) {
116+ throw new Error ( `Failed to fetch release ${ tag } : ${ response . status } ` )
117+ }
135118
136- // Find the matching asset.
137- const asset = release . assets . find ( a => a . name === assetName )
119+ const release = JSON . parse ( response . body )
138120
139- if ( ! asset ) {
140- throw new Error ( `Asset ${ assetName } not found in release ${ tag } ` )
141- }
121+ // Find the matching asset.
122+ const asset = release . assets . find ( a => a . name === assetName )
142123
124+ if ( ! asset ) {
125+ throw new Error ( `Asset ${ assetName } not found in release ${ tag } ` )
126+ }
127+
128+ if ( ! quiet ) {
129+ logger . info ( ` Found asset: ${ assetName } ` )
130+ }
131+
132+ return asset . browser_download_url
133+ } ,
134+ {
135+ backoffFactor : 1 ,
136+ baseDelayMs : 5000 ,
137+ onRetry : ( attempt , error ) => {
143138 if ( ! quiet ) {
144- logger . info ( ` Found asset: ${ assetName } ` )
139+ logger . info ( ` Retry attempt ${ attempt + 1 } /3 for asset URL...` )
140+ logger . warn ( ` Attempt ${ attempt + 1 } /3 failed: ${ error . message } ` )
145141 }
146-
147- return asset . browser_download_url
148142 } ,
149- {
150- backoffFactor : 1 ,
151- baseDelayMs : 5000 ,
152- onRetry : ( attempt , error ) => {
153- if ( ! quiet ) {
154- logger . info ( ` Retry attempt ${ attempt + 1 } /3 for asset URL...` )
155- logger . warn ( ` Attempt ${ attempt + 1 } /3 failed: ${ error . message } ` )
156- }
157- } ,
158- retries : 2 ,
159- } ,
160- )
161- } )
143+ retries : 2 ,
144+ } ,
145+ )
162146}
163147
164148/**
0 commit comments