@@ -6,18 +6,15 @@ import {zod} from './schema.js'
66import { AbortSilentError } from './error.js'
77import { isTruthy } from './context/utilities.js'
88import { jsonOutputEnabled } from './environment.js'
9+ import { exec } from './system.js'
910import { CLI_KIT_VERSION } from '../common/version.js'
1011import { NotificationKey , NotificationsKey , cacheRetrieve , cacheStore } from '../../private/node/conf-store.js'
12+ import { fetch } from '@shopify/cli-kit/node/http'
1113
1214const URL = 'https://cdn.shopify.com/static/cli/notifications.json'
1315const EMPTY_CACHE_MESSAGE = 'Cache is empty'
1416
15- /**
16- * Returns the URL to retrieve the notifications.
17- *
18- * @returns - The value from SHOPIFY_CLI_NOTIFICATIONS_URL or the default URL (https://cdn.shopify.com/static/cli/notifications.json).
19- */
20- export function notificationsUrl ( ) : string {
17+ function url ( ) : string {
2118 return process . env . SHOPIFY_CLI_NOTIFICATIONS_URL ?? URL
2219}
2320
@@ -112,18 +109,55 @@ async function renderNotifications(notifications: Notification[]) {
112109}
113110
114111/**
115- * Get notifications list from cache, that is updated in the background from the fetch-notifications.json script .
112+ * Get notifications list from cache, that is updated in the background from bin/ fetch-notifications.json.
116113 *
117114 * @returns A Notifications object.
118115 */
119116export async function getNotifications ( ) : Promise < Notifications > {
120- const cacheKey : NotificationsKey = `notifications-${ notificationsUrl ( ) } `
117+ const cacheKey : NotificationsKey = `notifications-${ url ( ) } `
121118 const rawNotifications = cacheRetrieve ( cacheKey ) ?. value as unknown as string
122119 if ( ! rawNotifications ) throw new Error ( EMPTY_CACHE_MESSAGE )
123120 const notifications : object = JSON . parse ( rawNotifications )
124121 return NotificationsSchema . parse ( notifications )
125122}
126123
124+ /**
125+ * Fetch notifications from the CDN and chache them.
126+ *
127+ * @returns A string with the notifications.
128+ */
129+ export async function fetchNotifications ( ) : Promise < Notifications > {
130+ outputDebug ( `Fetching notifications...` )
131+ const response = await fetch ( url ( ) , { signal : AbortSignal . timeout ( 3 * 1000 ) } )
132+ if ( response . status !== 200 ) throw new Error ( `Failed to fetch notifications: ${ response . statusText } ` )
133+ const rawNotifications = await response . text ( )
134+ await cacheNotifications ( rawNotifications )
135+ const notifications : object = JSON . parse ( rawNotifications )
136+ return NotificationsSchema . parse ( notifications )
137+ }
138+
139+ /**
140+ * Store the notifications in the cache.
141+ *
142+ * @param notifications - String with the notifications to cache.
143+ * @returns A Notifications object.
144+ */
145+ async function cacheNotifications ( notifications : string ) : Promise < void > {
146+ cacheStore ( `notifications-${ url ( ) } ` , notifications )
147+ outputDebug ( `Notifications from ${ url ( ) } stored in the cache` )
148+ }
149+
150+ /**
151+ * Fetch notifications in background as a detached process.
152+ */
153+ export function fetchNotificationsInBackground ( ) : void {
154+ // eslint-disable-next-line no-void
155+ void exec ( 'shopify' , [ 'notifications' , 'list' ] , {
156+ background : true ,
157+ env : { ...process . env , SHOPIFY_CLI_NO_ANALYTICS : '1' } ,
158+ } )
159+ }
160+
127161/**
128162 * Filters notifications based on the version of the CLI.
129163 *
0 commit comments