@@ -15,16 +15,84 @@ import react from '@astrojs/react';
1515
1616import tailwindcss from '@tailwindcss/vite' ;
1717
18- // Fetch the latest release version from GitHub
19- const response = await fetch (
20- 'https://api.github.com/repos/localstack/localstack/releases/latest' ,
21- {
22- headers : { Accept : 'application/vnd.github+json' } ,
23- } ,
24- ) ;
25- const data = await response . json ( ) ;
26- const latestVersion = data . tag_name . replace ( 'v' , '' ) ;
18+ // Used on the AWS and Snowflake installation guides: CLI download URLs and some bash examples.
19+ // Source of truth: public https://github.com/localstack/localstack-cli/releases/latest
20+ const LOCALSTACK_CLI_RELEASE_API =
21+ 'https://api.github.com/repos/localstack/localstack-cli/releases/latest' ;
22+
23+ /** When the API fails or rate-limits, builds still succeed; bump when CLI ships a new line. */
24+ const LOCALSTACK_CLI_VERSION_FALLBACK = '2026.4.0' ;
25+
26+ /** @param {unknown } tagName */
27+ function normalizeCliReleaseTag ( tagName ) {
28+ if ( typeof tagName !== 'string' || ! tagName . trim ( ) ) return null ;
29+ return tagName . replace ( / ^ v / i, '' ) . trim ( ) ;
30+ }
31+
32+ /**
33+ * One request per build when LOCALSTACK_AWS_VERSION is unset. Use that env in CI to skip the
34+ * network entirely, or set GITHUB_TOKEN for 5k req/hr instead of unauthenticated 60/hr per IP.
35+ */
36+ async function fetchLatestLocalstackCliVersionFromGitHub ( ) {
37+ /** @type {Record<string, string> } */
38+ const headers = {
39+ Accept : 'application/vnd.github+json' ,
40+ 'User-Agent' : 'localstack-docs-build (https://docs.localstack.cloud)' ,
41+ } ;
42+ if ( process . env . GITHUB_TOKEN ) {
43+ headers . Authorization = `Bearer ${ process . env . GITHUB_TOKEN } ` ;
44+ }
45+
46+ const maxAttempts = 3 ;
47+ let lastError ;
48+
49+ for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
50+ try {
51+ if ( attempt > 1 ) {
52+ await new Promise ( ( r ) => setTimeout ( r , 400 * attempt ) ) ;
53+ }
54+ const response = await fetch ( LOCALSTACK_CLI_RELEASE_API , { headers } ) ;
55+ const data = await response . json ( ) ;
56+
57+ if ( response . ok ) {
58+ const version = normalizeCliReleaseTag ( data ?. tag_name ) ;
59+ if ( version ) return version ;
60+ lastError = new Error ( 'GitHub release response missing tag_name' ) ;
61+ } else {
62+ const msg =
63+ typeof data ?. message === 'string' ? data . message : `HTTP ${ response . status } ` ;
64+ lastError = new Error ( msg ) ;
65+ }
66+ } catch ( err ) {
67+ lastError = err ;
68+ }
69+ }
70+
71+ throw lastError ?? new Error ( 'Failed to fetch localstack-cli release from GitHub' ) ;
72+ }
73+
74+ const cliVersionFromEnv = normalizeCliReleaseTag ( process . env . LOCALSTACK_AWS_VERSION ?? '' ) ;
75+
76+ /** @type {string } */
77+ let latestAWSVersion ;
78+
79+ if ( cliVersionFromEnv ) {
80+ latestAWSVersion = cliVersionFromEnv ;
81+ } else {
82+ try {
83+ latestAWSVersion = await fetchLatestLocalstackCliVersionFromGitHub ( ) ;
84+ } catch ( err ) {
85+ const reason = err instanceof Error ? err . message : String ( err ) ;
86+ console . warn (
87+ `[astro.config] Could not read localstack-cli version from GitHub (${ reason } ). ` +
88+ `Using pinned fallback ${ LOCALSTACK_CLI_VERSION_FALLBACK } . ` +
89+ 'Set LOCALSTACK_AWS_VERSION in the build, add GITHUB_TOKEN for higher API limits, or bump LOCALSTACK_CLI_VERSION_FALLBACK.' ,
90+ ) ;
91+ latestAWSVersion = LOCALSTACK_CLI_VERSION_FALLBACK ;
92+ }
93+ }
2794
95+ /** @type {import('./types/astro-local-fonts').AstroLocalFontVariants } */
2896const aeonikProVariants = [
2997 {
3098 src : [
@@ -118,10 +186,10 @@ export default defineConfig({
118186 ] ,
119187 env : {
120188 schema : {
121- LOCALSTACK_VERSION : envField . string ( {
189+ LOCALSTACK_AWS_VERSION : envField . string ( {
122190 context : 'server' ,
123191 access : 'public' ,
124- default : latestVersion ,
192+ default : latestAWSVersion ,
125193 optional : true ,
126194 } ) ,
127195 } ,
0 commit comments