From fd46bafb9814a25e57621e844e7edeaaefcbe0eb Mon Sep 17 00:00:00 2001 From: sunnylqm Date: Sun, 14 Sep 2025 17:25:35 +0800 Subject: [PATCH] Update version to 2.1.3 in package.json; set baseUrl in .swcrc; refactor API query logic to use dynamic base URL and update defaultEndpoints in constants.ts --- .swcrc | 1 + package.json | 2 +- src/api.ts | 13 ++++--- src/utils/constants.ts | 6 +-- src/utils/http-helper.ts | 83 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 src/utils/http-helper.ts diff --git a/.swcrc b/.swcrc index ec8d57a..4b16f81 100644 --- a/.swcrc +++ b/.swcrc @@ -1,5 +1,6 @@ { "jsc": { + "baseUrl": "./src", "loose": true, "target": "es2018", "parser": { diff --git a/package.json b/package.json index f94a79e..7b723f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-update-cli", - "version": "2.1.2", + "version": "2.1.3", "description": "command line tool for react-native-update (remote updates for react native)", "main": "index.js", "bin": { diff --git a/src/api.ts b/src/api.ts index f9cebaa..5dd5540 100644 --- a/src/api.ts +++ b/src/api.ts @@ -10,18 +10,16 @@ import packageJson from '../package.json'; import type { Package, Session } from './types'; import { credentialFile, - defaultEndpoint, pricingPageUrl, } from './utils/constants'; import { t } from './utils/i18n'; +import { getBaseUrl } from 'utils/http-helper'; const tcpPing = util.promisify(tcpp.ping); let session: Session | undefined; let savedSession: Session | undefined; -const host = - process.env.PUSHY_REGISTRY || process.env.RNU_API || defaultEndpoint; const userAgent = `react-native-update-cli/${packageJson.version}`; @@ -64,7 +62,9 @@ export const closeSession = () => { }; async function query(url: string, options: fetch.RequestInit) { - const resp = await fetch(url, options); + const baseUrl = await getBaseUrl; + const fullUrl = `${baseUrl}${url}`; + const resp = await fetch(fullUrl, options); const text = await resp.text(); let json: any; try { @@ -83,7 +83,7 @@ async function query(url: string, options: fetch.RequestInit) { function queryWithoutBody(method: string) { return (api: string) => - query(host + api, { + query(api, { method, headers: { 'User-Agent': userAgent, @@ -94,7 +94,7 @@ function queryWithoutBody(method: string) { function queryWithBody(method: string) { return (api: string, body?: Record) => - query(host + api, { + query(api, { method, headers: { 'User-Agent': userAgent, @@ -116,6 +116,7 @@ export async function uploadFile(fn: string, key?: string) { }); let realUrl = url; if (backupUrl) { + // @ts-ignore if (global.USE_ACC_OSS) { realUrl = backupUrl; } else { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 7d36ac7..a412fa6 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -10,6 +10,6 @@ export const pricingPageUrl = IS_CRESC ? 'https://cresc.dev/pricing' : 'https://pushy.reactnative.cn/pricing.html'; -export const defaultEndpoint = IS_CRESC - ? 'https://api.cresc.dev' - : 'https://update.reactnative.cn/api'; +export const defaultEndpoints = IS_CRESC + ? ['https://api.cresc.dev', 'https://api.cresc.app'] + : ['https://update.reactnative.cn/api', 'https://update.react-native.cn/api']; diff --git a/src/utils/http-helper.ts b/src/utils/http-helper.ts new file mode 100644 index 0000000..2f5f567 --- /dev/null +++ b/src/utils/http-helper.ts @@ -0,0 +1,83 @@ +import { defaultEndpoints } from './constants'; + +// const baseUrl = `http://localhost:9000`; +// let baseUrl = SERVER.main[0]; +// const baseUrl = `https://p.reactnative.cn/api`; + +export function promiseAny(promises: Promise[]) { + return new Promise((resolve, reject) => { + let count = 0; + + for (const promise of promises) { + Promise.resolve(promise) + .then(resolve) + .catch(() => { + count++; + if (count === promises.length) { + reject(new Error('All promises were rejected')); + } + }); + } + }); +} + +export const ping = async (url: string) => { + let pingFinished = false; + return Promise.race([ + fetch(url, { + method: 'HEAD', + }) + .then(({ status, statusText }) => { + pingFinished = true; + if (status === 200) { + // console.log('ping success', url); + return url; + } + // console.log('ping failed', url, status, statusText); + throw new Error('ping failed'); + }) + .catch((e) => { + pingFinished = true; + // console.log('ping error', url, e); + throw new Error('ping error'); + }), + new Promise((_, reject) => + setTimeout(() => { + reject(new Error('ping timeout')); + if (!pingFinished) { + // console.log('ping timeout', url); + } + }, 2000), + ), + ]) as Promise; +}; + +export const testUrls = async (urls?: string[]) => { + if (!urls?.length) { + return null; + } + const ret = await promiseAny(urls.map(ping)); + if (ret) { + return ret; + } + // console.log('all ping failed, use first url:', urls[0]); + return urls[0]; +}; + +export const getBaseUrl = (async () => { + const testEndpoint = process.env.PUSHY_REGISTRY || process.env.RNU_API; + if (testEndpoint) { + return testEndpoint; + } + return testUrls(defaultEndpoints.map((url) => `${url}/status`)).then( + (ret) => { + let baseUrl = defaultEndpoints[0]; + if (ret) { + // remove /status + baseUrl = ret.replace('/status', ''); + } + // console.log('baseUrl', baseUrl); + return baseUrl; + }, + ); +})();