@@ -94,9 +94,16 @@ const fallback_collections = [
9494
9595/**
9696 * @typedef FeaturedSource
97- * @type {{url: String, integrity?: String} }
97+ * @type {{
98+ * url: String,
99+ * id?: String,
100+ * integrity?: String,
101+ * valid_until?: String
102+ * }}
98103 */
99104
105+ const get_id = ( /** @type {FeaturedSource } */ source ) => source ?. id ?? source . url
106+
100107/**
101108 * @param {{
102109 * sources: FeaturedSource[]?,
@@ -109,25 +116,51 @@ export const Featured = ({ sources, direct_html_links }) => {
109116
110117 useEffect ( ( ) => {
111118 if ( sources != null ) {
119+ set_waited_too_long ( false )
120+ set_source_data ( { } )
121+
112122 // Start downloading the sources
113- const promises = sources . map ( async ( { url, integrity } ) => {
114- const data = await ( await fetch ( new Request ( url , { integrity : integrity ?? undefined } ) ) ) . json ( )
115-
116- if ( data . format_version !== "1" ) {
117- throw new Error ( `Invalid format version: ${ data . format_version } ` )
118- }
119-
120- set_source_data ( ( old ) => ( {
121- ...old ,
122- [ url ] : {
123- ...data ,
124- source_url : url ,
125- } ,
126- } ) )
123+
124+ const ids = Array . from ( new Set ( sources . map ( get_id ) ) )
125+
126+ console . log ( ids )
127+ console . log ( "123123123213123" )
128+
129+ const promises = ids . map ( ( id ) => {
130+ const sources_for_id = sources . filter ( ( source ) => get_id ( source ) === id )
131+
132+ let result = promise_any_with_priority (
133+ sources_for_id . map ( async ( source ) => {
134+ const { url, integrity, valid_until } = source
135+
136+ if ( valid_until != null && new Date ( valid_until ) < new Date ( ) ) {
137+ throw new Error ( `Source ${ url } is expired with valid_until ${ valid_until } ` )
138+ }
139+
140+ const data = await ( await fetch ( new Request ( url , { integrity : integrity ?? undefined } ) ) ) . json ( )
141+
142+ if ( data . format_version !== "1" ) {
143+ throw new Error ( `Invalid format version: ${ data . format_version } ` )
144+ }
145+
146+ return [ data , id , url ]
147+ } )
148+ )
149+
150+ return result . then ( ( [ data , id , url ] ) => {
151+ set_source_data ( ( old ) => ( {
152+ ...old ,
153+ [ id ] : {
154+ ...data ,
155+ source_url : url ,
156+ } ,
157+ } ) )
158+ } )
127159 } )
128160
129161 Promise . any ( promises ) . catch ( ( e ) => {
130162 console . error ( "All featured sources failed to load: " , e )
163+ ; ( e ?. errors ?? [ ] ) . forEach ( ( e ) => console . error ( e ) )
131164 set_waited_too_long ( true )
132165 } )
133166 }
@@ -148,10 +181,14 @@ export const Featured = ({ sources, direct_html_links }) => {
148181
149182 const no_data = Object . entries ( source_data ) . length === 0
150183
184+ const ids = Array . from ( new Set ( sources ?. map ( get_id ) ?? [ ] ) )
185+
186+ const sorted_on_source_order = ids . map ( ( id ) => source_data [ id ] ) . filter ( ( d ) => d != null )
187+
151188 return no_data && waited_too_long
152189 ? offline_html
153190 : html `
154- ${ ( no_data ? placeholder_data : Object . values ( source_data ) ) . map ( ( /** @type {SourceManifest } */ data ) => {
191+ ${ ( no_data ? placeholder_data : sorted_on_source_order ) . map ( ( /** @type {SourceManifest } */ data ) => {
155192 let collections = data ?. collections ?? fallback_collections
156193
157194 return html `
@@ -187,3 +224,16 @@ const collection = (/** @type {SourceManifestNotebookEntry[]} */ notebooks, /**
187224 let n = ( s ) => ( isNaN ( s ) ? s : Number ( s ) )
188225 return /** @type {SourceManifestNotebookEntry[] } */ ( _ . sortBy ( nbs , [ ( nb ) => n ( nb ?. frontmatter ?. order ) , "id" ] ) )
189226}
227+
228+ /**
229+ * Given a list promises, return promise[0].catch(() => promise[1].catch(() => promise[2]... etc))
230+ * @param {Promise[] } promises
231+ * @returns {Promise }
232+ */
233+ const promise_any_with_priority = ( /** @type {Promise[] } */ promises , /** @type {Promise[] } */ already_rejected = [ ] ) => {
234+ if ( promises . length <= 1 ) {
235+ return Promise . any ( [ ...promises , ...already_rejected ] )
236+ } else {
237+ return promises [ 0 ] . catch ( ( ) => promise_any_with_priority ( promises . slice ( 1 ) , [ ...already_rejected , promises [ 0 ] ] ) )
238+ }
239+ }
0 commit comments