97 lines
3.2 KiB
JavaScript
97 lines
3.2 KiB
JavaScript
'use strict';
|
||
|
||
// 每頁取得的 release 筆數
|
||
const RELEASES_PER_PAGE = 10;
|
||
|
||
/**
|
||
* 以分頁方式取得指定 Gitea repo 的所有 release,並回傳合併後的陣列。
|
||
*
|
||
* 使用全域 fetch 逐頁請求,每頁 limit 為 10;當某頁回傳空資料、null
|
||
* 或筆數少於每頁上限時即停止取得。
|
||
*
|
||
* @param {string} baseUrl - release API 的基底 URL(不含 query string)。
|
||
* @param {object} [options={}] - 選用設定。
|
||
* @param {string} [options.token] - 授權 token;有值時以 `Authorization: token <token>`
|
||
* 進行授權請求,否則以匿名方式請求。
|
||
* @param {{ info: (message: string) => void }} [options.logger] - 選用的記錄器,
|
||
* 需提供 info() 方法以輸出進度訊息。
|
||
* @returns {Promise<Array>} 解析為所有 release 物件合併後的陣列;首頁即無資料時回傳空陣列。
|
||
* @throws {Error} 當網路請求失敗、response 非 2xx、回應本文讀取失敗、回傳資料無法解析,
|
||
* 或回傳非陣列資料時拋出。
|
||
* @remarks 依賴 Node.js 18+ 的全域 fetch;baseUrl 不含 query string,函式自行附加
|
||
* `?limit=<RELEASES_PER_PAGE>&page=<n>` 逐頁請求,直到某頁空字串/`null`/不足一頁為止。
|
||
*/
|
||
async function fetchReleases(baseUrl, options = {}) {
|
||
const { token, logger } = options;
|
||
const headers = {};
|
||
|
||
if (token) {
|
||
logger?.info('使用授權 token 取得 release');
|
||
headers.Authorization = `token ${token}`;
|
||
} else {
|
||
logger?.info('使用匿名請求取得 release');
|
||
}
|
||
|
||
let page = 1;
|
||
const combined = [];
|
||
|
||
while (true) {
|
||
const url = `${baseUrl}?limit=${RELEASES_PER_PAGE}&page=${page}`;
|
||
|
||
let response;
|
||
try {
|
||
response = await fetch(url, { headers });
|
||
} catch (error) {
|
||
throw new Error(`release API 請求失敗 (page=${page}): ${error.message}`);
|
||
}
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`release API 請求失敗 (page=${page})`);
|
||
}
|
||
|
||
let text;
|
||
try {
|
||
text = await response.text();
|
||
} catch (error) {
|
||
throw new Error(`release API 回應讀取失敗 (page=${page}): ${error.message}`);
|
||
}
|
||
|
||
// 空字串或 null 代表已無更多資料
|
||
if (!text || text === 'null') {
|
||
break;
|
||
}
|
||
|
||
let pageJson;
|
||
try {
|
||
pageJson = JSON.parse(text);
|
||
} catch {
|
||
// 附上截斷的回傳內容(至多 200 字元)以利定位回傳格式異常的確切原因
|
||
const snippet = text.length > 200 ? `${text.slice(0, 200)}…` : text;
|
||
throw new Error(`release API 回傳資料無法解析 (page=${page}):${snippet}`);
|
||
}
|
||
|
||
if (pageJson === null) {
|
||
break;
|
||
}
|
||
|
||
if (!Array.isArray(pageJson)) {
|
||
throw new Error(`release API 回傳非陣列資料 (page=${page})`);
|
||
}
|
||
|
||
const count = pageJson.length;
|
||
logger?.info(`第 ${page} 頁取得 ${count} 筆 release`);
|
||
combined.push(...pageJson);
|
||
|
||
// 不足一頁代表已取完
|
||
if (count < RELEASES_PER_PAGE) {
|
||
break;
|
||
}
|
||
|
||
page += 1;
|
||
}
|
||
|
||
return combined;
|
||
}
|
||
|
||
module.exports = { RELEASES_PER_PAGE, fetchReleases };
|