diff --git a/src/api.js b/src/api.js index 06d1f4e..bc8f5b9 100644 --- a/src/api.js +++ b/src/api.js @@ -62,18 +62,27 @@ const getBucketFiles = async (folderName) => { Prefix: folderKey, }), ); - const ret = data.Contents.filter((item) => item.Key !== folderKey) + + // SAFETY: guard undefined Contents and ensure Date is a Date + const ret = (data.Contents || []) + .filter((item) => item.Key !== folderKey) .map((item) => { + const d = + item.LastModified instanceof Date + ? item.LastModified + : new Date(item.LastModified); return { - date: item.LastModified.toLocaleDateString("en-US", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - }).replace(/,/g, ""), - sort: item.LastModified.getTime(), + date: d + .toLocaleDateString("en-US", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }) + .replace(/,/g, ""), + sort: d.getTime(), name: item.Key.replace(folderKey, ""), key: item.Key, }; @@ -81,46 +90,43 @@ const getBucketFiles = async (folderName) => { .sort((a, b) => { return a.sort > b.sort ? -1 : a.sort < b.sort ? 1 : 0; }); + const itemCount = {}; const ext = ".tar.gz"; const filteredItems = ret - .filter((item) => item.name.endsWith(ext)) - .filter((item) => { + .filter((it) => it.name.endsWith(ext)) + .filter((it) => { if (folderName === "nightly") { - const parts = item.name.split("_"); + const parts = it.name.split("_"); const groupId = `${parts[0]}_${parts[3]}_${parts[4]}`; itemCount[groupId] = itemCount[groupId] || 0; if (++itemCount[groupId] <= 3) { return true; } - if (!oldItems.find((key) => key === item.key)) { - oldItems.push(item.key); - oldItems.push(item.key + ".sha256"); - oldItems.push(item.key + ".sig"); + // mark old: tar + sidecars + if (!oldItems.find((k) => k === it.key)) { + oldItems.push(it.key, it.key + ".sha256", it.key + ".sig"); if (parts[3] === "windows") { const setup_key = - item.key.substring(0, item.key.length - ext.length) + - "_setup.exe"; - - const setup_item = ret.find((item) => item.key == setup_key); + it.key.substring(0, it.key.length - ext.length) + "_setup.exe"; + const setup_item = ret.find((r) => r.key === setup_key); if (setup_item) { - oldItems.push(setup_key); - oldItems.push(setup_key + ".sha256"); - oldItems.push(setup_key + ".sig"); + oldItems.push( + setup_key, + setup_key + ".sha256", + setup_key + ".sig", + ); } } if (parts[3] === "darwin") { const dmg_key = - item.key.substring(0, item.key.length - ext.length) + ".dmg"; - - const dmg_item = ret.find((item) => item.key == dmg_key); + it.key.substring(0, it.key.length - ext.length) + ".dmg"; + const dmg_item = ret.find((r) => r.key === dmg_key); if (dmg_item) { - oldItems.push(dmg_key); - oldItems.push(dmg_key + ".sha256"); - oldItems.push(dmg_key + ".sig"); + oldItems.push(dmg_key, dmg_key + ".sha256", dmg_key + ".sig"); } } } @@ -130,34 +136,31 @@ const getBucketFiles = async (folderName) => { }); const totalCount = filteredItems.length * 3; - const setup_items = []; - const dmg_items = []; - let setup_offset = 0; - let dmg_offset = 0; - for (let i = 0; i < totalCount && i < filteredItems.length; i += 3) { - const parts = filteredItems[i].name.split("_"); - let item = ret.filter( - (item) => item.name === filteredItems[i].name + ".sha256", - ); - filteredItems.splice(i + 1, 0, ...item); - item = ret.filter((item) => item.name === filteredItems[i].name + ".sig"); - filteredItems.splice(i + 2, 0, ...item); + const setup_items = []; + const dmg_items = []; // NEW: keep a separate DMG list + let setup_offset = 0; + let dmg_offset = 0; // NEW: independent DMG offset + + for (let i = 0; i < totalCount && i < filteredItems.length; i += 3) { + const base = filteredItems[i]; + if (!base) break; // SAFETY guard + const parts = base.name.split("_"); + + // insert tar sidecars for this row + let arr = ret.filter((r) => r.name === base.name + ".sha256"); + filteredItems.splice(i + 1, 0, ...arr); + arr = ret.filter((r) => r.name === base.name + ".sig"); + filteredItems.splice(i + 2, 0, ...arr); + + // queue windows companion block if (parts[3] === "windows") { const setup_key = - filteredItems[i].key.substring( - 0, - filteredItems[i].key.length - ext.length, - ) + "_setup.exe"; - - const setup_item = ret.find((item) => item.key == setup_key); + base.key.substring(0, base.key.length - ext.length) + "_setup.exe"; + const setup_item = ret.find((r) => r.key === setup_key); if (setup_item) { - const setup_item2 = ret.find( - (item) => item.key == setup_key + ".sha256", - ); - const setup_item3 = ret.find( - (item) => item.key == setup_key + ".sig", - ); + const setup_item2 = ret.find((r) => r.key === setup_key + ".sha256"); + const setup_item3 = ret.find((r) => r.key === setup_key + ".sig"); setup_items.push([ { idx: i + 3 + setup_offset }, setup_item, @@ -168,41 +171,39 @@ const getBucketFiles = async (folderName) => { } } + // queue darwin companion block if (parts[3] === "darwin") { const dmg_key = - filteredItems[i].key.substring( - 0, - filteredItems[i].key.length - ext.length, - ) + ".dmg"; - - const dmg_item = ret.find((item) => item.key == dmg_key); + base.key.substring(0, base.key.length - ext.length) + ".dmg"; + const dmg_item = ret.find((r) => r.key === dmg_key); if (dmg_item) { - const dmg_item2 = ret.find((item) => item.key == dmg_key + ".sha256"); - const dmg_item3 = ret.find((item) => item.key == dmg_key + ".sig"); + const dmg_item2 = ret.find((r) => r.key === dmg_key + ".sha256"); + const dmg_item3 = ret.find((r) => r.key === dmg_key + ".sig"); dmg_items.push([ - { idx: i + 3 + dmg_offset }, + { idx: i + 3 + dmg_offset }, // FIX: use dmg_offset dmg_item, dmg_item2, dmg_item3, ]); - dmg_offset += 3; + dmg_offset += 3; // FIX: increment dmg_offset } } } + // insert queued companion blocks if (dmg_items.length > 0) { dmg_items.forEach((items) => { filteredItems.splice(items[0].idx, 0, items[1]); - filteredItems.splice(items[0].idx + 1, 0, items[2]); - filteredItems.splice(items[0].idx + 2, 0, items[3]); + if (items[2]) filteredItems.splice(items[0].idx + 1, 0, items[2]); + if (items[3]) filteredItems.splice(items[0].idx + 2, 0, items[3]); }); } if (setup_items.length > 0) { setup_items.forEach((items) => { filteredItems.splice(items[0].idx, 0, items[1]); - filteredItems.splice(items[0].idx + 1, 0, items[2]); - filteredItems.splice(items[0].idx + 2, 0, items[3]); + if (items[2]) filteredItems.splice(items[0].idx + 1, 0, items[2]); + if (items[3]) filteredItems.splice(items[0].idx + 2, 0, items[3]); }); }