@playcraft/devkit 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/batch-build.js +5 -4
- package/core/constants.js +1 -1
- package/core/cos-uploader.js +13 -5
- package/package.json +1 -1
package/core/batch-build.js
CHANGED
|
@@ -96,10 +96,11 @@ const REMOTE_CONFIG_REPO="https://git.woa.com/maclerylin/playable-build-config.g
|
|
|
96
96
|
*
|
|
97
97
|
* @param {string} appName - 应用名称,对应远程仓库中的文件夹名
|
|
98
98
|
* @returns {Promise<object|null>} 远程配置对象,失败返回 null
|
|
99
|
-
*/async function fetchRemoteConfig(appName){if(!appName)return null;const https=require("https");const http=require("http");const url=require("url")
|
|
100
|
-
const{API_BASE_URL}
|
|
101
|
-
const configContent=await new Promise((resolve,reject)=>{const parsedUrl=url.parse(configUrl);const protocol=parsedUrl.protocol==="https:"?https:http;const request=protocol.get(configUrl,response=>{if(response.statusCode!==200){reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));return}let data="";response.on("data",chunk=>data+=chunk);response.on("end",()=>resolve(data))});request.on("error",reject);request.setTimeout(30000,()=>{request.destroy();reject(new Error("Request timeout"))})})
|
|
102
|
-
|
|
99
|
+
*/async function fetchRemoteConfig(appName){if(!appName)return null;const https=require("https");const http=require("http");const url=require("url");const{API_BASE_URL,API_BASE_URL_FALLBACK}=require("./constants");const configPath=`/aix/playable-build-config/${encodeURIComponent(appName)}/build.config.js`;// 主/备域名 fallback 列表
|
|
100
|
+
const configUrls=[`${API_BASE_URL}${configPath}`,`${API_BASE_URL_FALLBACK}${configPath}`];log(`尝试从远程 URL 获取配置: ${appName}`,"info");let configContent=null;let lastError=null;// 遍历 URL 列表,主域名失败则尝试备用
|
|
101
|
+
for(const configUrl of configUrls){log(`URL: ${configUrl}`,"debug");try{configContent=await new Promise((resolve,reject)=>{const parsedUrl=url.parse(configUrl);const protocol=parsedUrl.protocol==="https:"?https:http;const request=protocol.get(configUrl,response=>{if(response.statusCode!==200){reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));return}let data="";response.on("data",chunk=>data+=chunk);response.on("end",()=>resolve(data))});request.on("error",reject);request.setTimeout(30000,()=>{request.destroy();reject(new Error("Request timeout"))})});// 请求成功,跳出循环
|
|
102
|
+
break}catch(error){lastError=error;if(configUrl!==configUrls[configUrls.length-1]){log(`主域名请求失败,尝试备用域名...`,"warn");continue}}}if(!configContent){var _lastError;log(`获取远程配置失败: ${((_lastError=lastError)===null||_lastError===void 0?void 0:_lastError.message)||"\u672A\u77E5\u9519\u8BEF"}`,"warn");return null}log("\u2713 \u8FDC\u7A0B\u914D\u7F6E\u6587\u4EF6\u4E0B\u8F7D\u6210\u529F","success");// 使用 vm 模块执行配置文件,避免 require 缓存问题
|
|
103
|
+
const vm=require("vm");const sandbox={module:{exports:{}},exports:{},require:require};sandbox.exports=sandbox.module.exports;try{vm.runInNewContext(configContent,sandbox);log(`✓ 成功加载远程配置: ${appName}`,"success");return sandbox.module.exports}catch(parseError){log(`解析远程配置文件失败: ${parseError.message}`,"error");log(`配置内容预览: ${configContent.substring(0,200)}...`,"debug");return null}}/**
|
|
103
104
|
* 加载配置文件
|
|
104
105
|
*
|
|
105
106
|
* 优先级: 本地 builds.config.js > 远程配置 > build.json > 默认值
|
package/core/constants.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* 全局常量配置
|
|
4
4
|
*
|
|
5
5
|
* 集中管理服务端 API 地址、构建参数等常量,方便切换环境。
|
|
6
|
-
*//** 服务端 API
|
|
6
|
+
*//** 服务端 API 基础地址(主) */const API_BASE_URL="http://9.135.99.122";/** 服务端 API 基础地址(备用),主地址不可用时 fallback */const API_BASE_URL_FALLBACK="https://wd-act.woa.com";module.exports={API_BASE_URL,API_BASE_URL_FALLBACK};
|
package/core/cos-uploader.js
CHANGED
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
* COS 上传模块
|
|
4
4
|
*
|
|
5
5
|
* 功能:上传文件到腾讯云 COS,并刷新 CDN 缓存
|
|
6
|
-
*/const COS=require("cos-nodejs-sdk-v5");const fs=require("fs");const path=require("path");const http=require("http");const{API_BASE_URL}=require("./constants");/**
|
|
7
|
-
*
|
|
8
|
-
|
|
6
|
+
*/const COS=require("cos-nodejs-sdk-v5");const fs=require("fs");const path=require("path");const http=require("http");const https=require("https");const{API_BASE_URL,API_BASE_URL_FALLBACK}=require("./constants");/**
|
|
7
|
+
* 通用 API 请求(自动适配 http/https,支持失败 fallback)
|
|
8
|
+
* @param {string} path - API 路径,如 '/aix/playable/api/cos/credentials'
|
|
9
|
+
* @param {string} method - 请求方法 GET/POST
|
|
10
|
+
* @param {Object|null} postData - POST 请求体(JSON 对象)
|
|
11
|
+
* @returns {Promise<Object>} - 解析后的 JSON 响应
|
|
12
|
+
*/async function apiRequest(path,method="GET",postData=null){const urls=[`${API_BASE_URL}${path}`,`${API_BASE_URL_FALLBACK}${path}`];let lastError=null;for(const url of urls){try{const result=await new Promise((resolve,reject)=>{const isHttps=url.startsWith("https");const transport=isHttps?https:http;const doRequest=res=>{if(res.statusCode!==200){reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));return}let data="";res.on("data",chunk=>data+=chunk);res.on("end",()=>{try{const result=JSON.parse(data);if(result.code==="SUCCESS"){resolve(result)}else{reject(new Error(result.message||"API request failed"))}}catch(error){reject(new Error(`Failed to parse response: ${error.message}`))}})};let req;if(method==="POST"&&postData){const body=JSON.stringify(postData);req=transport.request(url,{method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(body)}},doRequest);req.write(body)}else{req=transport.get(url,doRequest)}req.on("error",reject);req.setTimeout(30000,function(){this.destroy();reject(new Error("Request timeout"))});if(method==="GET"){req.end()}else if(method==="POST"&&!postData){req.end()}});// 成功则直接返回
|
|
13
|
+
return result}catch(error){lastError=error;// 如果还有备用 URL,继续尝试
|
|
14
|
+
if(url!==urls[urls.length-1]){console.warn(`⚠️ 主域名请求失败 (${url}), 尝试备用域名...`);continue}}}throw lastError||new Error("All API endpoints failed")}/**
|
|
15
|
+
* 从远程 API 获取临时凭证(支持主/备域名 fallback)
|
|
16
|
+
*/async function fetchTemporaryCredentials(){const result=await apiRequest("/aix/playable/api/cos/credentials");return result.data}/**
|
|
9
17
|
* 创建 COS 客户端(使用临时凭证)
|
|
10
18
|
* @param {Object} cosConfig - COS 配置
|
|
11
19
|
* @param {Object} credentials - 已获取的临时凭证(可选,避免重复请求)
|
|
@@ -20,8 +28,8 @@ if(!credentials){credentials=await fetchTemporaryCredentials()}return new COS({g
|
|
|
20
28
|
* @param {Object} credentials - 未使用,保留参数兼容性
|
|
21
29
|
* @returns {Promise<void>}
|
|
22
30
|
*/async function purgeCDNCache(cosConfig,urls,credentials=null){if(!urls||urls.length===0){return}const area=(cosConfig===null||cosConfig===void 0?void 0:cosConfig.CdnArea)||"overseas";// 如果配置中有 SecretId/SecretKey,本地直接刷新
|
|
23
|
-
if(cosConfig&&cosConfig.SecretId&&cosConfig.SecretKey){try{const tencentcloud=require("tencentcloud-sdk-nodejs-cdn");const client=new tencentcloud.cdn.v20180606.Client({credential:{secretId:cosConfig.SecretId,secretKey:cosConfig.SecretKey},region:"",profile:{httpProfile:{endpoint:"cdn.tencentcloudapi.com"}}});const batchSize=1000;for(let i=0;i<urls.length;i+=batchSize){const batch=urls.slice(i,i+batchSize);await client.PurgeUrlsCache({Urls:batch,Area:area});console.log(`✓ CDN 缓存已刷新 ${batch.length} 个 URL (区域: ${area})`)}}catch(error){if(error.code==="MODULE_NOT_FOUND"){console.warn("\u26A0\uFE0F \u672A\u5B89\u88C5 tencentcloud-sdk-nodejs-cdn\uFF0C\u8DF3\u8FC7 CDN \u5237\u65B0")}else{throw error}}return}// 否则通过服务端 API
|
|
24
|
-
|
|
31
|
+
if(cosConfig&&cosConfig.SecretId&&cosConfig.SecretKey){try{const tencentcloud=require("tencentcloud-sdk-nodejs-cdn");const client=new tencentcloud.cdn.v20180606.Client({credential:{secretId:cosConfig.SecretId,secretKey:cosConfig.SecretKey},region:"",profile:{httpProfile:{endpoint:"cdn.tencentcloudapi.com"}}});const batchSize=1000;for(let i=0;i<urls.length;i+=batchSize){const batch=urls.slice(i,i+batchSize);await client.PurgeUrlsCache({Urls:batch,Area:area});console.log(`✓ CDN 缓存已刷新 ${batch.length} 个 URL (区域: ${area})`)}}catch(error){if(error.code==="MODULE_NOT_FOUND"){console.warn("\u26A0\uFE0F \u672A\u5B89\u88C5 tencentcloud-sdk-nodejs-cdn\uFF0C\u8DF3\u8FC7 CDN \u5237\u65B0")}else{throw error}}return}// 否则通过服务端 API 代理刷新(支持主/备域名 fallback)
|
|
32
|
+
try{await apiRequest("/aix/playable/api/cdn/purge","POST",{urls,area});console.log(`✓ CDN 缓存已刷新 ${urls.length} 个 URL (区域: ${area})`)}catch(error){throw new Error(`CDN purge failed: ${error.message}`)}}/**
|
|
25
33
|
* 上传单个文件到 COS
|
|
26
34
|
*
|
|
27
35
|
* @param {Object} cosConfig - COS 配置
|