xhs-mp-core 2.0.2 → 2.0.3
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/dist/core.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/services/baseService.d.ts +4 -11
- package/package.json +4 -4
package/dist/core.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export declare class Core {
|
|
|
54
54
|
private globalConfig;
|
|
55
55
|
private appConfigMap;
|
|
56
56
|
private projectMap;
|
|
57
|
-
private
|
|
57
|
+
private compilerManagerMap;
|
|
58
58
|
storage: Storage;
|
|
59
59
|
logger: Logger;
|
|
60
60
|
loginManager: LoginManager;
|
|
@@ -65,7 +65,7 @@ export declare class Core {
|
|
|
65
65
|
setAppConfig(appConfig?: IAppConfig): void;
|
|
66
66
|
getAppConfig(appId: any): IAppConfig;
|
|
67
67
|
private createOrGetProject;
|
|
68
|
-
private
|
|
68
|
+
private getCompilerManager;
|
|
69
69
|
login(opts?: ILoginConfig): Promise<void>;
|
|
70
70
|
logout(opts: ILogoutConfig): void;
|
|
71
71
|
isTokenAuth(appId: any): boolean;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("xhs-mp-project"),t=require("xhs-mp-shared"),o=require("events"),r=require("axios"),s=require("path"),i=require("os"),a=require("fs-extra"),n=require("dayjs"),p=require("dayjs/plugin/utc"),c=require("dayjs/plugin/timezone"),l=require("querystring"),h=require("fs"),u=require("rxjs"),d=require("lodash"),g=require("rxjs/operators"),m=require("qrcode-terminal"),f=require("jimp"),S=require("jsqr"),v=require("process"),k=require("xhs-mp-compiler-cli");function w(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(o){if("default"!==o){var r=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,r.get?r:{enumerable:!0,get:function(){return e[o]}})}})),t.default=e,Object.freeze(t)}var x=w(s),y=w(h);const b=()=>({isSit:"false"===process.env.XHS_IS_PROD,isProd:"true"===process.env.XHS_IS_PROD}),C=require("process").env.XHS_BUSINESS_SIT_HOST||"http://business-cli.sl.beta.xiaohongshu.com",_=require("process").env.XHS_CUSTOMER_SIT_HOST||"https://customer.sit.xiaohongshu.com",I={BUSINESS_HOST:b().isSit?C:"https://business.xiaohongshu.com",CUSTOMER_HOST:b().isSit?_:"https://customer.xiaohongshu.com",CUSTOMER_SERVICE_ID:b().isSit?_.replace(/https?:\/\/customer/,"file://miniapp-open"):"file://miniapp-open.xiaohongshu.com"},P={generateQrCode:`${I.CUSTOMER_HOST}/api/cas/generateQrCode`,queryQrCodeStatus:`${I.CUSTOMER_HOST}/api/cas/queryQrCodeStatus`,session:`${I.BUSINESS_HOST}/api/eros/mp/red/code/session`,getUserInfo:`${I.BUSINESS_HOST}/api/eros/mp/red/code/user/info`},j=require("crypto");require("net");const M=e=>{if(!e)return"";const t=1024;return e<t?`${e}B`:e<1048576?`${(e/t).toFixed(2)}KB`:e<t**3?`${(e/1048576).toFixed(2)}MB`:e<t**4?`${(e/t**3).toFixed(2)}GB`:`${(e/t**4).toFixed(2)}T`};function q(e){const t=j.createHash("md5");t.update(e);return t.digest("hex")}function T(e){return e.replace(/\\/g,"/")}const U=T(s.join(i.homedir(),".xhs-mp-cli"));a.ensureDirSync(U);const E=T(s.join(U,"xhs-storage"));a.ensureDirSync(E);const A=require("tough-cookie");var $=new class{constructor(){this.cookiePath=s.join(E,"cookie.json");const e=this.getSerializeData();Object.keys(e).length?this.cookieJar=A.CookieJar.deserializeSync(e):this.cookieJar=new A.CookieJar}getSerializeData(){let e={};return a.existsSync(this.cookiePath)&&(e=a.readJSONSync(this.cookiePath)),e}save(){const e=this.cookieJar.serializeSync();a.writeJSONSync(this.cookiePath,e)}clear(){a.removeSync(this.cookiePath)}set(e){const t=e.headers["set-cookie"]||[],o=e.config.url;t.forEach((e=>{const t=A.Cookie.parse(e);if(t.domain){const e=new A.Cookie(t);this.cookieJar.setCookieSync(e,o)}})),this.save()}get(e){return this.cookieJar.getCookieStringSync(e)}};n.extend(p),n.extend(c),n.tz.setDefault("Asia/Shanghai");let O=0;const D=e=>n.tz().add(O,"millisecond").format(e);let H;r.defaults.baseURL=I.BUSINESS_HOST,r.interceptors.request.use((e=>{const{url:t,data:o,baseURL:s=""}=e;let i=r.getUri(e);if(/^https?:/.test(i))try{const e=new URL(t);i=i.replace(e.origin,"")}catch(e){i=t}const a=$.get(t);return e.headers={...e.headers,Cookie:a},e.headers["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) @xhs/mp-ide/2.0.0 Chrome/116.0.5845.228 Electron/26.4.0 Safari/537.36 discover/2.0.0 xhsminiapp/latest",e})),r.interceptors.response.use((e=>($.set(e),e))),r.interceptors.response.use((e=>{var t;const{config:o,data:r}=e;if((null===(t=o.url)||void 0===t?void 0:t.startsWith(`${I.BUSINESS_HOST}/api/eros/mp/red`))&&!r.success)throw new Error(`${r.msg}`);return e}),(async e=>{var t,o,s;const{response:i={},config:a}=e;if(401===i.status){if(-240309===(null===(t=i.data)||void 0===t?void 0:t.code))return null==H||H.logout({from:"axios"}),Promise.reject(new Error(i.data.msg||"请求失败,请重新登陆或采用 token 免密登陆"));if(-240099===(null===(o=i.data)||void 0===o?void 0:o.code)){const e=i.headers.date,t=n(e).format("YYYYMMDDHHmm"),o=D("YYYYMMDDHHmm");return o!==t?(((e,t)=>{const o=n(e).diff(n(t));O=o})(t,o),console.log("请求失败:客户端与服务端时间不一致,即将重试",t,o),(p=1e3,new Promise((e=>{setTimeout((()=>{e(null)}),p)}))).then((function(){let e=a;return a.fixConfigWhenRetry&&(e=a.fixConfigWhenRetry(a)),r(e)}))):(null==H||H.logout({from:"axios"}),Promise.reject(new Error(i.data.msg||"请求失败,cli token不匹配")))}if(null===(s=i.data)||void 0===s?void 0:s.msg)return null==H||H.logout({from:"axios"}),Promise.reject(new Error(`code:${i.data.code},msg: ${i.data.msg}`))}var p;return Promise.reject(e)}));class z extends o.EventEmitter{constructor(e){super(),this.core=e.core}get axios(){return e=this.core,H=e,r;var e}getProxyConfig(){const{proxy:e}=this.core.getGlobalConfig();if(e){const t=new URL(e);return{host:t.hostname,port:t.port,protocol:t.protocol}}return!1}async request(e){const{method:t,url:o,data:r,config:s={}}=e;return await this.axios[t](o,r,{...s,proxy:this.getProxyConfig()})}handleHttpStatus(e){if(200!==e.status)throw new Error(`request fail, code: ${e.status}, errMsg: ${e.status}`);return e}handleStatusCode(e){const{data:t}=e;if(200!==t.statusCode)throw new Error(`request fail, code: ${t.statusCode}, errMsg: ${t.errorMsg}`);return t.data}handleCode(e){const{data:t}=e;if(0!==t.code&&0!==t.error_code)throw new Error(`request fail, code: ${t.code||t.error_code}, errMsg: ${t.msg}`);return t.data}}const V=require("path"),L=require("fs-extra"),N=e=>{if(!L.existsSync(e))return"";let t="";try{t=JSON.stringify(L.readJSONSync(e))}catch(t){console.warn(`readJson error: ${e}`)}return t};class R extends z{constructor(e){super(e),this.getUploadToken=async e=>{const t=await this.request({method:"get",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/upload/permit`,data:{params:e,withCredentials:!0}});return this.handleCode(this.handleHttpStatus(t))},this.project=e.project}async request(e){const{method:t,url:o,data:r,config:s={},fixConfigWhenRetry:i}=e,a=await this.axios[t](o,r,{...s,proxy:this.getProxyConfig(),fixConfigWhenRetry:e=>{let{url:t}=e;if(t.includes("cli_token")){const[o,r=""]=t.split("?"),s=l.parse(r),{cliToken:i,nonce:a,appId:n}=this.core.getTokenParams(this.project.projectAppId),p=o+"?"+l.stringify({...s,cli_token:i,nonce:a,appId:n});e.url=p}return e}});return a}async checkUploadAuthV1({version:e}){const t=this.project,o=t.entryJsonPath,r=V.resolve(t.extJsonPath),s=N(o),i=N(r),a=t.projectAppId,n=`${I.BUSINESS_HOST}/api/eros/mp/red/code/${a}/validate/version/${e}`,p=await this.request({method:"post",url:n,data:{app_json:s,ext_json:i}});return this.handleCode(this.handleHttpStatus(p))}async checkUploadAuthV2(e){const{version:t,appId:o,cliToken:r,nonce:s}=e,i=this.project,a=i.entryJsonPath,n=V.resolve(i.extJsonPath),p=N(a),c=N(n),l=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/validate/version?app_id=${o}&cli_token=${r}&nonce=${s}&version=${t}`,h=await this.request({method:"post",url:l,data:{app_json:p,ext_json:c}});return this.handleCode(this.handleHttpStatus(h))}async createUploadTaskV1(e){const{version:t,fileUrl:o,fileUrlSourceMap:r,userVersion:s,userDesc:i,appId:a,packageMap:n,packageMapSourceMap:p,packageMapV2:c,packageMapV2SourceMap:l}=e,h={method:"post",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/${a}/upload/version/${t}`,data:{file_url:o,user_version:s,user_desc:i,package_map:n,package_map_v2:c,sourcemap:{package_v0:r,package_v1:p,package_v2:l},cloud_type:4}};let u=await this.request(h);return u=this.handleCode(this.handleHttpStatus(u)),u}async createUploadTaskV2(e){const{version:t,fileUrl:o,fileUrlSourceMap:r,userVersion:s,userDesc:i,appId:a,packageMap:n,packageMapSourceMap:p,packageMapV2:c,packageMapV2SourceMap:l,cliToken:h,nonce:u}=e,d=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/upload/version?app_id=${a}&cli_token=${h}&nonce=${u}&version=${t}`,g=await this.request({method:"post",url:d,data:{file_url:o,user_version:s,user_desc:i,package_map:n,package_map_v2:c,sourcemap:{package_v0:r,package_v1:p,package_v2:l},cloud_type:4}});return this.handleCode(this.handleHttpStatus(g))}async queryTaskDetailV1(e){const{taskId:t}=e;let o=await this.request({method:"get",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/task/detail`,data:{params:{task_id:t}}});return o=this.handleCode(this.handleHttpStatus(o)),o}async queryTaskDetailV2(e){const{taskId:t,appId:o,cliToken:r,nonce:s}=e,i=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/task/detail`;let a=await this.request({method:"get",url:i,data:{params:{task_id:t,app_id:o,cli_token:r,nonce:s}}});return a=this.handleCode(this.handleHttpStatus(a)),a}}const J=(e,t)=>e.reduce(((e,o)=>{let r={};return o.type!==t||o.isSourcemap||(r={[o.root]:o.fileId}),{...e,...r}}),{}),B=(e,t)=>{var o;const r=null===(o=e.filter((e=>e.type===t&&e.isSourcemap)))||void 0===o?void 0:o[0];return JSON.stringify({md5:null==r?void 0:r.md5,cdnFileUrl:null==r?void 0:r.cdnFileUrl})};class Q extends o{constructor(e){super(),this.uploadPkgZipOrSourcemap=(e,t,o,r)=>new u.Observable((s=>{setTimeout((()=>{const{zipPath:i,type:a,root:n}=t,p=i.endsWith("-sourcemap.zip");let c;c=p?this.uploadPkgSourcemap(t):this.uploadPkgZip(e,t,o),c.then((e=>{s.next({...e,type:a,root:n,isSourcemap:p}),s.complete(),null==r||r()})).catch((e=>{s.error(e)}))}),500)})),this.uploadPkgSourcemap=async e=>{const{appId:o,version:r,zipPath:s}=e,i=x.basename(s).split("-")[0],a=q(`${o}_${r}_${i}`),n=(await t.publicCos.upload2Qcloud(s,`${o}/${r}/${i}/${a}`)).files[0];if(200!==n.data.statusCode)throw new Error(`${s}上传失败:${n.error||"unknown error"}`);return{md5:q(y.readFileSync(s)),fileId:n.data.ETag,cdnFileUrl:`https://${n.data.Location}`}},this.uploadPkgZip=(e,o,r,s)=>{const{zipPath:i,type:a,root:n}=o,{appId:p,cliToken:c,nonce:l}=this.core.getTokenParams(this.project.projectAppId),h=new t.Uploader({bizName:"fe",scene:"fe-platform",getToken:t=>{let o=t;return this.core.isTokenAuth(this.project.projectAppId)&&(o={...t,app_id:p,nonce:l,cli_token:c}),e.getUploadToken(o)}});return new Promise(((e,t)=>{setTimeout((()=>{const o=`${"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))}-xhs-example.zip`,r=y.readFileSync(x.resolve(i)),p=y.statSync(x.resolve(i));function c(){return new Promise(((e,t)=>{setTimeout((()=>{h.post({Body:r,fileInfo:{name:o,type:"application/octet-stream",size:p.size},FilePath:x.resolve(i)}).then((o=>{var r;return 0!==o.code?t(new Error(`${i}上传失败:${o.msg}`)):(null===(r=null==o?void 0:o.data)||void 0===r?void 0:r.fileId)?(e({fileId:o.data.fileId,type:a,root:n,cdnFileUrl:o.data.previewUrl}),void(null==s||s())):t(new Error(`${i}上传失败`))}))}),500)}))}c().catch(c).catch(c).catch(c).catch(c).then((t=>{e(t)})).catch((e=>{t(e)}))}),500)}))},this.submitTask=e=>this.core.isTokenAuth(this.project.projectAppId)?this.submitTaskV2(e):this.submitTaskV1(e),this.submitTaskV1=e=>{const{uploadApi:t}=e,o=this.getCommonSubmitOptions(e);return u.from(t.createUploadTaskV1(o)).pipe(u.switchMap((e=>{const{task_id:o}=e;return u.interval(1500).pipe(u.switchMap((()=>u.from(t.queryTaskDetailV1({taskId:o})).pipe(u.map((e=>{var t;if(5===e.status)throw new Error(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.msg);return e}))))),u.first((e=>3===e.status)))})))},this.submitTaskV2=e=>{const{uploadApi:t}=e,{appId:o,cliToken:r,nonce:s}=this.core.getTokenParams(this.project.projectAppId),i=this.getCommonSubmitOptions(e);return u.from(t.createUploadTaskV2({...i,cliToken:r,nonce:s})).pipe(u.switchMap((e=>{const{task_id:i}=e;return u.interval(1500).pipe(u.switchMap((()=>u.from(t.queryTaskDetailV2({taskId:i,appId:o,cliToken:r,nonce:s})).pipe(u.map((e=>{var t;if(5===e.status)throw new Error(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.msg);return e}))))),u.first((e=>3===e.status)))})))},this.core=e.core,this.project=e.project,this.compiler=e.compiler,this.logger=e.logger}getCheckUploadAuthFn(e,t){let o;const r=this.core.isTokenAuth(this.project.projectAppId);if(this.logger.debug("Check appid auth..."),r){const{appId:r,cliToken:s,nonce:i}=this.core.getTokenParams(this.project.projectAppId);o=e.checkUploadAuthV2({version:t,appId:r,cliToken:s,nonce:i})}else o=e.checkUploadAuthV1({version:t});return o}getCommonSubmitOptions(e){const{uploadRes:t,appId:o,version:r,userDesc:s,userVersion:i}=e,a=((e,t)=>{var o;return null===(o=e.filter((e=>e.type===t&&!e.isSourcemap))[0])||void 0===o?void 0:o.fileId})(t,"v0"),n=B(t,"v0"),p=J(t,"v1"),c=B(t,"v1"),l=J(t,"v2"),h=B(t,"v2");return{version:r,fileUrl:a,fileUrlSourceMap:n,appId:o,packageMap:p,packageMapSourceMap:c,packageMapV2:d.isEmpty(l)?void 0:l,packageMapV2SourceMap:h,userDesc:s,userVersion:i}}}const{COMPILE_ENTRY:F}=require("xhs-mp-compiler-cli");class Y extends Q{constructor(e){super(e),this.doUpload=e=>{const{progressCallback:t,userVersion:o,userDesc:r}=e;if(!(null==o?void 0:o.trim()))throw new Error("请填写上传版本号");if(!(null==r?void 0:r.trim()))throw new Error("请填写版本描述");const s=()=>{var e,t;this.compiler.kill(F.upload),null===(e=this.taskSubscription)||void 0===e||e.unsubscribe(),this.taskSubscription=null,null===(t=this.uploadPromise)||void 0===t||t.resolve(null),this.uploadPromise=null,this.logger.log("Upload Done!!!")},i=e=>{var o,r;null==t||t(-1),null===(o=this.taskSubscription)||void 0===o||o.unsubscribe(),this.taskSubscription=null,this.compiler.kill(F.upload),this.logger.log("Upload Error:",e.message),null===(r=this.uploadPromise)||void 0===r||r.reject(e),this.uploadPromise=null};try{const e=this.project.projectAppId;this.taskSubscription=u.from(this.getCheckUploadAuthFn(this.uploadApi,"develop")).pipe(u.switchMap((e=>{let r=e.can_upload,s=e.can_upload_ext_json,i=e.upload_app_id;if(!r)throw new Error(e.show_msg);if(!i)throw new Error("请检查是否该appid无权限");return null==t||t(5),u.from(this.compiler.compileAndZip({entryType:F.upload,can_upload_ext_json:s,upload_app_id:i,pkgInfo:{version:o}}))})),u.switchMap((o=>{null==t||t(30),this.emit("compile-and-zip-status",{status:"uploading"}),this.logger.log("Upload packages to cos...");const r=o.map(((r,s)=>this.uploadPkgZipOrSourcemap(this.uploadApi,{appId:e,zipPath:r.zipPath,type:r.type,root:r.root},s,(()=>{null==t||t(30+45/o.length*(s+1))}))));return u.forkJoin(r)})),u.switchMap((s=>{null==t||t(80),this.logger.log("Upload packages info...");const i={uploadApi:this.uploadApi,uploadRes:s,appId:e,version:"develop",userVersion:o,userDesc:r};return this.submitTask(i)}))).subscribe({next:e=>{null==t||t(100),s()},error:e=>{i(e)}})}catch(e){i(e)}},this.uploadApi=new R(e)}upload(e){return new Promise(((t,o)=>{this.uploadPromise={resolve:t,reject:o},this.doUpload(e)}))}}class G extends z{async generateQrCode(){const e=await this.request({method:"post",url:P.generateQrCode,data:{subsystem:"business"}});return this.handleStatusCode(this.handleHttpStatus(e))}async queryQrCodeStatus(e){const t=await this.request({method:"get",url:P.queryQrCodeStatus,data:{params:{qrId:e,service:I.CUSTOMER_SERVICE_ID}}});return this.handleStatusCode(this.handleHttpStatus(t))}async login(e){const t=await this.request({method:"post",url:P.session,data:{ticket:e,clientId:I.CUSTOMER_SERVICE_ID}});return this.handleHttpStatus(t).data}async fetchUserInfo(){const e=await this.request({method:"get",url:P.getUserInfo});return this.handleCode(this.handleHttpStatus(e))}}class W{get isLogin(){return this._isLogin}set isLogin(e){this._isLogin=e}get userInfo(){return this._userInfo}set userInfo(e){this._userInfo=e,this.storage.set("xhs-cli-userInfo",e)}constructor(e){var t;this.qrCodeStatusData={},this.startPollingSub=null,this.loginPromise={},this.transformUserInfo=e=>{const{nick:t,avatar:o,desc:r,gender:s}=(i=e,["nick","avatar","desc","gender"].reduce(((e,t)=>({...e,[t]:i[t]})),{}));var i;return{nickName:t,avatar:o,userId:"",desc:r,gender:s}},this.queryQrCodeStatus=e=>u.from(this.userApi.queryQrCodeStatus(e)),this.doLogin=async e=>{const{resolve:t,reject:o}=this.loginPromise;this.loginPromise=null;try{const r=await this.userApi.login(e);if(!r.success)return void o(new Error(r.msg));const s=await this.userApi.fetchUserInfo(),i=this.transformUserInfo(s);i.userInfoData=s,t(i)}catch(e){return void o(new Error(e.message))}},this.startPolling=()=>(this.qrCodeStatusData.isLoading=!0,this.qrCodeStatusData.expired=!1,u.from(u.defer((()=>this.userApi.generateQrCode()))).pipe(g.tap((e=>{this.qrUrl=e.qrUrl,this.qrCodeStatusData.isLoading=!1,this.showQrCode(),setTimeout((()=>{this.qrCodeStatusData.expired=!0,this.stopPolling()}),6e4)})),g.exhaustMap((({qrUrl:e,qrId:t})=>u.interval(2e3).pipe(g.switchMap((()=>this.queryQrCodeStatus(t))),g.tap((e=>{if(4===e.status)throw new Error("retry login");1===e.status&&(this.stopPolling(),this.doLogin(e.ticket))}))))),g.takeWhile((e=>1!==e.status)),g.retry(5))),this.stopPolling=()=>{this.startPollingSub&&(this.startPollingSub.unsubscribe(),this.startPollingSub=null)};const{storage:o,logger:r}=e;this.storage=o,this.logger=r,this.userApi=new G(e),this.qrCodeStatusData={isLoading:!1,expired:!1},this._userInfo=o.get("userInfo")||o.get("xhs-cli-userInfo")||{},this.isLogin=!!(null===(t=this.userInfo)||void 0===t?void 0:t.nickName)}showQrCode(){m.generate(this.qrUrl,{small:!0})}async login(e="qrcode"){if(this.isLogin)this.logger.log("Had Login!!!");else{this.isLogin=!1,this.logger.log("Login...");try{if("qrcode"!==e)throw new Error("暂不支持扫码之外的其他登陆方式");{const e=await this.loginByQrcode();this.userInfo=e}this.isLogin=!0,this.logger.log("Login success")}catch(e){throw this.logger.log("Login fail:",e.message),this.isLogin=!1,this.userInfo=null,e}}}loginByQrcode(){return new Promise(((e,t)=>{this.loginPromise={resolve:e,reject:t};try{this.startPollingSub=this.startPolling().subscribe()}catch(e){console.error(e)}}))}logout(e){"axios"!==e.from&&this.logger.log("Logout..."),this.isLogin=!1,this.userInfo={},$.clear(),"axios"!==e.from&&this.logger.log("Logout Success!!!")}}const Z=async(e,t={},o,r)=>{let s=e.getCompileEntryPage();s={...s,...t};const{path:i,query:a,launchMode:n}=s;try{let e=await(async e=>{const t=Buffer.from(e.replace(/^data:image\/[a-z]+;base64,/,""),"base64"),o=await f.read(t),r={data:new Uint8ClampedArray(o.bitmap.data),width:o.bitmap.width,height:o.bitmap.height},s=S(r.data,r.width,r.height);if(!s)throw new Error("QR code not found in the image.");return s.data})(o);return i&&(e=e.replace("_develop",`_develop${i.startsWith("/")?"":"/"}${i}`)),a&&(e+=`&${a}`),"halfPageNativeFunctionalized"===n&&(e+="&runtime_mode=2"),e}catch(e){r.error("二维码解码失败:",e)}},{COMPILE_ENTRY:X}=require("xhs-mp-compiler-cli");class K extends Q{constructor(e){super(e),this.progressData={},this.previewData={},this.calcSize=e=>{var t,o;const r=this.project,s=(null===(t=null==r?void 0:r.flags)||void 0===t?void 0:t.enableV2Preivew)?"v2":"v1",i=(null===(o=null==e?void 0:e.filter)||void 0===o?void 0:o.call(e,(e=>e.type===s)).sort(((e,t)=>t.zipSize-e.zipSize)))||[];this.previewData.subPkgs=i.map(((e,t)=>({key:t,path:e.root,size:M(e.zipSize)})));const a=i.reduce(((e,t)=>t.zipSize+e),0)||0;this.previewData.zipSize=M(a)},this.uploadApi=new R(e),this.progressData={},this.previewData={}}preview(e){return new Promise(((t,o)=>{this.previewPromise={resolve:t,reject:o},this.doPreview(e)}))}doPreview(e){this.progressData.previewIsLoading=!0;const t=this.project.projectAppId,o=Date.now(),r=async t=>{var r,s;const i=JSON.parse(t.result.extra_json);this.previewData.qrcodeUrl=await Z(this.project,e.entry,i.qrcode,this.logger),this.showQrCode(this.previewData.qrcodeUrl),this.previewData.previewTotalTime=+((Date.now()-o)/1e3).toFixed(1),this.progressData.previewIsLoading=!1,this.compiler.kill(X.preview),null===(r=this.taskSubscription)||void 0===r||r.unsubscribe(),this.taskSubscription=null,null===(s=this.previewPromise)||void 0===s||s.resolve({qrcodeUrl:this.previewData.qrcodeUrl}),this.previewPromise=null,this.logger.log("Preview Done!!!")},s=e=>{var t,o;this.compiler.kill(X.preview),null===(t=this.taskSubscription)||void 0===t||t.unsubscribe(),this.taskSubscription=null,null===(o=this.previewPromise)||void 0===o||o.reject(e),this.previewPromise=null,this.logger.log("Preview Error:",e.toString())};this.taskSubscription=u.from(this.getCheckUploadAuthFn(this.uploadApi,"debug")).pipe(u.switchMap((e=>{let t=e.can_upload_ext_json,o=e.upload_app_id;if(!o)throw new Error("请检查是否该appid无权限");return u.from(this.compiler.compileAndZip({entryType:X.preview,can_upload_ext_json:t,upload_app_id:o}))})),u.tap((e=>{this.calcSize(e)})),u.switchMap((e=>{this.emit("compile-and-zip-status",{status:"uploading"}),this.logger.log("Upload packages to cos...");const o=e.map(((e,o)=>this.uploadPkgZipOrSourcemap(this.uploadApi,{appId:t,zipPath:e.zipPath,type:e.type,root:e.root},o)));return u.forkJoin(o)})),u.switchMap((e=>(this.logger.log("Upload packages info..."),this.submitTask({uploadApi:this.uploadApi,uploadRes:e,appId:t,version:"debug"}))))).subscribe({next:e=>r(e),error:e=>s(e)})}showQrCode(e){m.generate(e,{small:!0})}}const ee={code:"code",cli:"cli"};class te{constructor({core:e}){this.data={},this.core=e,this.extract()}extract(){if(this.core.scene===ee.cli){if(this.jsonPath=s.join(E,"storage.json"),a.existsSync(this.jsonPath))try{this.data=a.readJSONSync(this.jsonPath)}catch(e){this.data={}}}else this.data={}}store(){this.core.scene===ee.cli&&a.writeJSONSync(this.jsonPath,this.data)}get(e){return this.data[e]}set(e,t){this.data[e]=t,this.refresh()}refresh(){this.store()}}exports.Core=class{constructor(e){this.globalConfig={},this.appConfigMap={},this.projectMap={},this.compilerMap={},this.scene=ee.code;const{scene:o=ee.code}=e;this.scene=o,this.logger=new t.Logger("[xhs-mp-cli]"),this.storage=new te({core:this}),this.globalConfig=this.storage.get("xhs-cli-global-config")||{},this.appConfigMap=this.storage.get("xhs-cli-app-config")||{},this.logger.debug("get initial config:",this.globalConfig,this.appConfigMap),globalThis.logger=this.logger,this.loginManager=new W({core:this,storage:this.storage,logger:this.logger})}setGlobalConfig(e={}){this.globalConfig={...this.globalConfig||{},...e},this.storage.set("xhs-cli-global-config",e),this.logger.log("Set global config done")}getGlobalConfig(){return this.globalConfig||{}}setAppConfig(e={}){const{appId:t,config:o}=e;t?(this.appConfigMap[t]={...this.appConfigMap[t]||{},...o},this.storage.set("xhs-cli-app-config",this.appConfigMap),this.logger.log("Set app config done")):this.logger.error("没有传递 appid 参数")}getAppConfig(e){return this.appConfigMap[e]||{}}createOrGetProject(t){let o=t.projectPath;if(!o)throw new Error("没有配置projectPath");return s.isAbsolute(o)||(o=s.join(v.cwd(),o)),this.projectMap[o]||(this.projectMap[o]=new e.Project(t)),this.projectMap[o]}getCompiler(e,t){let o=e.projectPath;if(s.isAbsolute(o)||(o=s.join(v.cwd(),o)),!this.compilerMap[o]){const r=this.createOrGetProject(e);this.compilerMap[o]=new k.ProjectCompiler({...t,project:r,logger:this.logger})}return this.compilerMap[o]}async login(e={}){e.verbose&&this.logger.setVerbose(!0);const{type:t="qrcode"}=e;await this.loginManager.login(t)}logout(e){this.loginManager.logout(e)}isTokenAuth(e){return!!this.getAppConfig(e).token}getTokenParams(e){const t=this.getAppConfig(e).token,o="xxxxxxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)})),r=e+"#"+t+"#"+o+"#"+D("YYYYMMDDHHmm"),s=q(r);return this.logger.debug("cliToken",r,s),{cliToken:s,nonce:o,appId:e}}checkAppId(e){if(!this.appConfigMap[e])throw new Error(`找不到项目内appId(${e})对应的配置,请先确认appId是否保持一致`)}async preview(e){e.verbose&&this.logger.setVerbose(!0);const t=e.project||{},o=e.buildConfig||{},r=this.createOrGetProject(t);this.checkAppId(r.projectAppId),this.logger.log("Project:",r.projectPath),this.logger.debug("Preview options:",e);const s=this.appConfigMap[r.projectAppId];(null==s?void 0:s.token)?this.logger.debug("Auth by token"):(this.logger.debug("Auth by qrCode"),this.loginManager.isLogin||await this.login());const i=this.getCompiler(t,o),a=new K({core:this,project:r,compiler:i,logger:this.logger});try{return await a.preview({entry:e.entry})}finally{i.kill()}}async upload(e){const{project:t,buildConfig:o={},version:r,desc:s,progressCallback:i}=e;e.verbose&&this.logger.setVerbose(!0);const a=this.createOrGetProject(t);this.checkAppId(a.projectAppId),this.logger.log("ProjectPath:",a.projectPath),this.logger.debug("Upload options:",e);const n=this.appConfigMap[a.projectAppId];(null==n?void 0:n.token)?this.logger.debug("Auth by token"):(this.logger.debug("Auth by login"),this.loginManager.isLogin||await this.login());const p=this.getCompiler(t,o),c=new Y({core:this,project:a,compiler:p,logger:this.logger});try{return await c.upload({userVersion:r,userDesc:s,progressCallback:i})}finally{p.kill()}}};
|
|
1
|
+
"use strict";var e=require("xhs-mp-project"),t=require("xhs-mp-shared"),r=require("events"),o=require("axios"),s=require("path"),i=require("os"),a=require("fs-extra"),n=require("dayjs"),p=require("dayjs/plugin/utc"),l=require("dayjs/plugin/timezone"),c=require("querystring"),h=require("fs"),u=require("rxjs"),d=require("lodash"),g=require("rxjs/operators"),m=require("qrcode-terminal"),f=require("jimp"),S=require("jsqr"),v=require("process"),k=require("xhs-mp-compiler-cli");function w(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var x=w(s),y=w(h);const C=()=>({isSit:"false"===process.env.XHS_IS_PROD,isProd:"true"===process.env.XHS_IS_PROD}),b=require("process").env.XHS_BUSINESS_SIT_HOST||"http://business-cli.sl.beta.xiaohongshu.com",_=require("process").env.XHS_CUSTOMER_SIT_HOST||"https://customer.sit.xiaohongshu.com",I={BUSINESS_HOST:C().isSit?b:"https://business.xiaohongshu.com",CUSTOMER_HOST:C().isSit?_:"https://customer.xiaohongshu.com",CUSTOMER_SERVICE_ID:C().isSit?_.replace(/https?:\/\/customer/,"file://miniapp-open"):"file://miniapp-open.xiaohongshu.com"},M={generateQrCode:`${I.CUSTOMER_HOST}/api/cas/generateQrCode`,queryQrCodeStatus:`${I.CUSTOMER_HOST}/api/cas/queryQrCodeStatus`,session:`${I.BUSINESS_HOST}/api/eros/mp/red/code/session`,getUserInfo:`${I.BUSINESS_HOST}/api/eros/mp/red/code/user/info`},P=require("crypto");require("net");const j=e=>{if(!e)return"";const t=1024;return e<t?`${e}B`:e<1048576?`${(e/t).toFixed(2)}KB`:e<t**3?`${(e/1048576).toFixed(2)}MB`:e<t**4?`${(e/t**3).toFixed(2)}GB`:`${(e/t**4).toFixed(2)}T`};function q(e){const t=P.createHash("md5");t.update(e);return t.digest("hex")}function T(e){return e.replace(/\\/g,"/")}const U=T(s.join(i.homedir(),".xhs-mp-cli"));a.ensureDirSync(U);const E=T(s.join(U,"xhs-storage"));a.ensureDirSync(E);const A=require("tough-cookie");var $=new class{constructor(){this.cookiePath=s.join(E,"cookie.json");const e=this.getSerializeData();Object.keys(e).length?this.cookieJar=A.CookieJar.deserializeSync(e):this.cookieJar=new A.CookieJar}getSerializeData(){let e={};return a.existsSync(this.cookiePath)&&(e=a.readJSONSync(this.cookiePath)),e}save(){const e=this.cookieJar.serializeSync();a.writeJSONSync(this.cookiePath,e)}clear(){a.removeSync(this.cookiePath)}set(e){const t=e.headers["set-cookie"]||[],r=e.config.url;t.forEach((e=>{const t=A.Cookie.parse(e);if(t.domain){const e=new A.Cookie(t);this.cookieJar.setCookieSync(e,r)}})),this.save()}get(e){return this.cookieJar.getCookieStringSync(e)}};n.extend(p),n.extend(l),n.tz.setDefault("Asia/Shanghai");let O=0;const D=e=>n.tz().add(O,"millisecond").format(e);let H;o.defaults.baseURL=I.BUSINESS_HOST,o.interceptors.request.use((e=>{const{url:t,data:r,baseURL:s=""}=e;let i=o.getUri(e);if(/^https?:/.test(i))try{const e=new URL(t);i=i.replace(e.origin,"")}catch(e){i=t}const a=$.get(t);return e.headers={...e.headers,Cookie:a},e.headers["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) @xhs/mp-ide/2.0.0 Chrome/116.0.5845.228 Electron/26.4.0 Safari/537.36 discover/2.0.0 xhsminiapp/latest",e})),o.interceptors.response.use((e=>($.set(e),e))),o.interceptors.response.use((e=>{var t;const{config:r,data:o}=e;if((null===(t=r.url)||void 0===t?void 0:t.startsWith(`${I.BUSINESS_HOST}/api/eros/mp/red`))&&!o.success)throw new Error(`${o.msg}`);return e}),(async e=>{var t,r,s;const{response:i={},config:a}=e;if(401===i.status){if(-240309===(null===(t=i.data)||void 0===t?void 0:t.code))return null==H||H.logout({from:"axios"}),Promise.reject(new Error(i.data.msg||"请求失败,请重新登陆或采用 token 免密登陆"));if(-240099===(null===(r=i.data)||void 0===r?void 0:r.code)){const e=i.headers.date,t=n(e).format("YYYYMMDDHHmm"),r=D("YYYYMMDDHHmm");return r!==t?(((e,t)=>{const r=n(e).diff(n(t));O=r})(t,r),console.log("请求失败:客户端与服务端时间不一致,即将重试",t,r),(p=1e3,new Promise((e=>{setTimeout((()=>{e(null)}),p)}))).then((function(){let e=a;return a.fixConfigWhenRetry&&(e=a.fixConfigWhenRetry(a)),o(e)}))):(null==H||H.logout({from:"axios"}),Promise.reject(new Error(i.data.msg||"请求失败,cli token不匹配")))}if(null===(s=i.data)||void 0===s?void 0:s.msg)return null==H||H.logout({from:"axios"}),Promise.reject(new Error(`code:${i.data.code},msg: ${i.data.msg}`))}var p;return Promise.reject(e)}));class z extends r.EventEmitter{constructor(e){super(),this.core=e.core}get axios(){return e=this.core,H=e,o;var e}getProxyConfig(){const{proxy:e}=this.core.getGlobalConfig();if(e){const t=new URL(e);return{host:t.hostname,port:t.port,protocol:t.protocol}}return!1}async request(e){const{method:t,url:r,data:o,config:s={}}=e;return await this.axios[t](r,o,{...s,proxy:this.getProxyConfig()})}handleHttpStatus(e){if(200!==e.status)throw new Error(`request fail, code: ${e.status}, errMsg: ${e.status}`);return e}handleStatusCode(e){const{data:t}=e;if(200!==t.statusCode)throw new Error(`request fail, code: ${t.statusCode}, errMsg: ${t.errorMsg}`);return t.data}handleCode(e){const{data:t}=e;if(0!==t.code&&0!==t.error_code)throw new Error(`request fail, code: ${t.code||t.error_code}, errMsg: ${t.msg}`);return t.data}}const V=require("path"),L=require("fs-extra"),N=e=>{if(!L.existsSync(e))return"";let t="";try{t=JSON.stringify(L.readJSONSync(e))}catch(t){console.warn(`readJson error: ${e}`)}return t};class R extends z{constructor(e){super(e),this.getUploadToken=async e=>{const t=await this.request({method:"get",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/upload/permit`,data:{params:e,withCredentials:!0}});return this.handleCode(this.handleHttpStatus(t))},this.project=e.project}async request(e){const{method:t,url:r,data:o,config:s={},fixConfigWhenRetry:i}=e,a=await this.axios[t](r,o,{...s,proxy:this.getProxyConfig(),fixConfigWhenRetry:e=>{let{url:t}=e;if(t.includes("cli_token")){const[r,o=""]=t.split("?"),s=c.parse(o),{cliToken:i,nonce:a,appId:n}=this.core.getTokenParams(this.project.projectAppId),p=r+"?"+c.stringify({...s,cli_token:i,nonce:a,appId:n});e.url=p}return e}});return a}async checkUploadAuthV1({version:e}){const t=this.project,r=t.entryJsonPath,o=V.resolve(t.extJsonPath),s=N(r),i=N(o),a=t.projectAppId,n=`${I.BUSINESS_HOST}/api/eros/mp/red/code/${a}/validate/version/${e}`,p=await this.request({method:"post",url:n,data:{app_json:s,ext_json:i}});return this.handleCode(this.handleHttpStatus(p))}async checkUploadAuthV2(e){const{version:t,appId:r,cliToken:o,nonce:s}=e,i=this.project,a=i.entryJsonPath,n=V.resolve(i.extJsonPath),p=N(a),l=N(n),c=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/validate/version?app_id=${r}&cli_token=${o}&nonce=${s}&version=${t}`,h=await this.request({method:"post",url:c,data:{app_json:p,ext_json:l}});return this.handleCode(this.handleHttpStatus(h))}async createUploadTaskV1(e){const{version:t,fileUrl:r,fileUrlSourceMap:o,userVersion:s,userDesc:i,appId:a,packageMap:n,packageMapSourceMap:p,packageMapV2:l,packageMapV2SourceMap:c}=e,h={method:"post",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/${a}/upload/version/${t}`,data:{file_url:r,user_version:s,user_desc:i,package_map:n,package_map_v2:l,sourcemap:{package_v0:o,package_v1:p,package_v2:c},cloud_type:4}};let u=await this.request(h);return u=this.handleCode(this.handleHttpStatus(u)),u}async createUploadTaskV2(e){const{version:t,fileUrl:r,fileUrlSourceMap:o,userVersion:s,userDesc:i,appId:a,packageMap:n,packageMapSourceMap:p,packageMapV2:l,packageMapV2SourceMap:c,cliToken:h,nonce:u}=e,d=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/upload/version?app_id=${a}&cli_token=${h}&nonce=${u}&version=${t}`,g=await this.request({method:"post",url:d,data:{file_url:r,user_version:s,user_desc:i,package_map:n,package_map_v2:l,sourcemap:{package_v0:o,package_v1:p,package_v2:c},cloud_type:4}});return this.handleCode(this.handleHttpStatus(g))}async queryTaskDetailV1(e){const{taskId:t}=e;let r=await this.request({method:"get",url:`${I.BUSINESS_HOST}/api/eros/mp/red/code/task/detail`,data:{params:{task_id:t}}});return r=this.handleCode(this.handleHttpStatus(r)),r}async queryTaskDetailV2(e){const{taskId:t,appId:r,cliToken:o,nonce:s}=e,i=`${I.BUSINESS_HOST}/api/eros/mp/red/code/v2/task/detail`;let a=await this.request({method:"get",url:i,data:{params:{task_id:t,app_id:r,cli_token:o,nonce:s}}});return a=this.handleCode(this.handleHttpStatus(a)),a}}const J=(e,t)=>e.reduce(((e,r)=>{let o={};return r.type!==t||r.isSourcemap||(o={[r.root]:r.fileId}),{...e,...o}}),{}),B=(e,t)=>{var r;const o=null===(r=e.filter((e=>e.type===t&&e.isSourcemap)))||void 0===r?void 0:r[0];return JSON.stringify({md5:null==o?void 0:o.md5,cdnFileUrl:null==o?void 0:o.cdnFileUrl})};class Q extends r{constructor(e){super(),this.uploadPkgZipOrSourcemap=(e,t,r,o)=>new u.Observable((s=>{setTimeout((()=>{const{zipPath:i,type:a,root:n}=t,p=i.endsWith("-sourcemap.zip");let l;l=p?this.uploadPkgSourcemap(t):this.uploadPkgZip(e,t,r),l.then((e=>{s.next({...e,type:a,root:n,isSourcemap:p}),s.complete(),null==o||o()})).catch((e=>{s.error(e)}))}),500)})),this.uploadPkgSourcemap=async e=>{const{appId:r,version:o,zipPath:s}=e,i=x.basename(s).split("-")[0],a=q(`${r}_${o}_${i}`),n=(await t.publicCos.upload2Qcloud(s,`${r}/${o}/${i}/${a}`)).files[0];if(200!==n.data.statusCode)throw new Error(`${s}上传失败:${n.error||"unknown error"}`);return{md5:q(y.readFileSync(s)),fileId:n.data.ETag,cdnFileUrl:`https://${n.data.Location}`}},this.uploadPkgZip=(e,r,o,s)=>{const{zipPath:i,type:a,root:n}=r,{appId:p,cliToken:l,nonce:c}=this.core.getTokenParams(this.project.projectAppId),h=new t.Uploader({bizName:"fe",scene:"fe-platform",getToken:t=>{let r=t;return this.core.isTokenAuth(this.project.projectAppId)&&(r={...t,app_id:p,nonce:c,cli_token:l}),e.getUploadToken(r)}});return new Promise(((e,t)=>{setTimeout((()=>{const r=`${"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))}-xhs-example.zip`,o=y.readFileSync(x.resolve(i)),p=y.statSync(x.resolve(i));function l(){return new Promise(((e,t)=>{setTimeout((()=>{h.post({Body:o,fileInfo:{name:r,type:"application/octet-stream",size:p.size},FilePath:x.resolve(i)}).then((r=>{var o;return 0!==r.code?t(new Error(`${i}上传失败:${r.msg}`)):(null===(o=null==r?void 0:r.data)||void 0===o?void 0:o.fileId)?(e({fileId:r.data.fileId,type:a,root:n,cdnFileUrl:r.data.previewUrl}),void(null==s||s())):t(new Error(`${i}上传失败`))}))}),500)}))}l().catch(l).catch(l).catch(l).catch(l).then((t=>{e(t)})).catch((e=>{t(e)}))}),500)}))},this.submitTask=e=>this.core.isTokenAuth(this.project.projectAppId)?this.submitTaskV2(e):this.submitTaskV1(e),this.submitTaskV1=e=>{const{uploadApi:t}=e,r=this.getCommonSubmitOptions(e);return u.from(t.createUploadTaskV1(r)).pipe(u.switchMap((e=>{const{task_id:r}=e;return u.interval(1500).pipe(u.switchMap((()=>u.from(t.queryTaskDetailV1({taskId:r})).pipe(u.map((e=>{var t;if(5===e.status)throw new Error(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.msg);return e}))))),u.first((e=>3===e.status)))})))},this.submitTaskV2=e=>{const{uploadApi:t}=e,{appId:r,cliToken:o,nonce:s}=this.core.getTokenParams(this.project.projectAppId),i=this.getCommonSubmitOptions(e);return u.from(t.createUploadTaskV2({...i,cliToken:o,nonce:s})).pipe(u.switchMap((e=>{const{task_id:i}=e;return u.interval(1500).pipe(u.switchMap((()=>u.from(t.queryTaskDetailV2({taskId:i,appId:r,cliToken:o,nonce:s})).pipe(u.map((e=>{var t;if(5===e.status)throw new Error(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.msg);return e}))))),u.first((e=>3===e.status)))})))},this.core=e.core,this.project=e.project,this.compilerManager=e.compilerManager,this.logger=e.logger}getCheckUploadAuthFn(e,t){let r;const o=this.core.isTokenAuth(this.project.projectAppId);if(this.logger.debug("Check appid auth..."),o){const{appId:o,cliToken:s,nonce:i}=this.core.getTokenParams(this.project.projectAppId);r=e.checkUploadAuthV2({version:t,appId:o,cliToken:s,nonce:i})}else r=e.checkUploadAuthV1({version:t});return r}getCommonSubmitOptions(e){const{uploadRes:t,appId:r,version:o,userDesc:s,userVersion:i}=e,a=((e,t)=>{var r;return null===(r=e.filter((e=>e.type===t&&!e.isSourcemap))[0])||void 0===r?void 0:r.fileId})(t,"v0"),n=B(t,"v0"),p=J(t,"v1"),l=B(t,"v1"),c=J(t,"v2"),h=B(t,"v2");return{version:o,fileUrl:a,fileUrlSourceMap:n,appId:r,packageMap:p,packageMapSourceMap:l,packageMapV2:d.isEmpty(c)?void 0:c,packageMapV2SourceMap:h,userDesc:s,userVersion:i}}}const{COMPILE_ENTRY:F}=require("xhs-mp-compiler-cli");class Y extends Q{constructor(e){super(e),this.doUpload=e=>{const{progressCallback:t,userVersion:r,userDesc:o}=e;if(!(null==r?void 0:r.trim()))throw new Error("请填写上传版本号");if(!(null==o?void 0:o.trim()))throw new Error("请填写版本描述");const s=()=>{var e,t;this.compilerManager.killCompiler(F.upload),null===(e=this.taskSubscription)||void 0===e||e.unsubscribe(),this.taskSubscription=null,null===(t=this.uploadPromise)||void 0===t||t.resolve(null),this.uploadPromise=null,this.logger.log("Upload Done!!!")},i=e=>{var r,o;null==t||t(-1),null===(r=this.taskSubscription)||void 0===r||r.unsubscribe(),this.taskSubscription=null,this.compilerManager.killCompiler(F.upload),this.logger.log("Upload Error:",e.message),null===(o=this.uploadPromise)||void 0===o||o.reject(e),this.uploadPromise=null};try{const e=this.project.projectAppId;this.taskSubscription=u.from(this.getCheckUploadAuthFn(this.uploadApi,"develop")).pipe(u.switchMap((e=>{let o=e.can_upload,s=e.can_upload_ext_json,i=e.upload_app_id;if(!o)throw new Error(e.show_msg);if(!i)throw new Error("请检查是否该appid无权限");return null==t||t(5),u.from(this.compilerManager.compileAndZip({entryType:F.upload,can_upload_ext_json:s,upload_app_id:i,pkgInfo:{version:r}}))})),u.switchMap((r=>{null==t||t(30),this.emit("compile-and-zip-status",{status:"uploading"}),this.logger.log("Upload packages to cos...");const o=r.map(((o,s)=>this.uploadPkgZipOrSourcemap(this.uploadApi,{appId:e,zipPath:o.zipPath,type:o.type,root:o.root},s,(()=>{null==t||t(30+45/r.length*(s+1))}))));return u.forkJoin(o)})),u.switchMap((s=>{null==t||t(80),this.logger.log("Upload packages info...");const i={uploadApi:this.uploadApi,uploadRes:s,appId:e,version:"develop",userVersion:r,userDesc:o};return this.submitTask(i)}))).subscribe({next:e=>{null==t||t(100),s()},error:e=>{i(e)}})}catch(e){i(e)}},this.uploadApi=new R(e)}upload(e){return new Promise(((t,r)=>{this.uploadPromise={resolve:t,reject:r},this.doUpload(e)}))}}class G extends z{async generateQrCode(){const e=await this.request({method:"post",url:M.generateQrCode,data:{subsystem:"business"}});return this.handleStatusCode(this.handleHttpStatus(e))}async queryQrCodeStatus(e){const t=await this.request({method:"get",url:M.queryQrCodeStatus,data:{params:{qrId:e,service:I.CUSTOMER_SERVICE_ID}}});return this.handleStatusCode(this.handleHttpStatus(t))}async login(e){const t=await this.request({method:"post",url:M.session,data:{ticket:e,clientId:I.CUSTOMER_SERVICE_ID}});return this.handleHttpStatus(t).data}async fetchUserInfo(){const e=await this.request({method:"get",url:M.getUserInfo});return this.handleCode(this.handleHttpStatus(e))}}class W{get isLogin(){return this._isLogin}set isLogin(e){this._isLogin=e}get userInfo(){return this._userInfo}set userInfo(e){this._userInfo=e,this.storage.set("xhs-cli-userInfo",e)}constructor(e){var t;this.qrCodeStatusData={},this.startPollingSub=null,this.loginPromise={},this.transformUserInfo=e=>{const{nick:t,avatar:r,desc:o,gender:s}=(i=e,["nick","avatar","desc","gender"].reduce(((e,t)=>({...e,[t]:i[t]})),{}));var i;return{nickName:t,avatar:r,userId:"",desc:o,gender:s}},this.queryQrCodeStatus=e=>u.from(this.userApi.queryQrCodeStatus(e)),this.doLogin=async e=>{const{resolve:t,reject:r}=this.loginPromise;this.loginPromise=null;try{const o=await this.userApi.login(e);if(!o.success)return void r(new Error(o.msg));const s=await this.userApi.fetchUserInfo(),i=this.transformUserInfo(s);i.userInfoData=s,t(i)}catch(e){return void r(new Error(e.message))}},this.startPolling=()=>(this.qrCodeStatusData.isLoading=!0,this.qrCodeStatusData.expired=!1,u.from(u.defer((()=>this.userApi.generateQrCode()))).pipe(g.tap((e=>{this.qrUrl=e.qrUrl,this.qrCodeStatusData.isLoading=!1,this.showQrCode(),setTimeout((()=>{this.qrCodeStatusData.expired=!0,this.stopPolling()}),6e4)})),g.exhaustMap((({qrUrl:e,qrId:t})=>u.interval(2e3).pipe(g.switchMap((()=>this.queryQrCodeStatus(t))),g.tap((e=>{if(4===e.status)throw new Error("retry login");1===e.status&&(this.stopPolling(),this.doLogin(e.ticket))}))))),g.takeWhile((e=>1!==e.status)),g.retry(5))),this.stopPolling=()=>{this.startPollingSub&&(this.startPollingSub.unsubscribe(),this.startPollingSub=null)};const{storage:r,logger:o}=e;this.storage=r,this.logger=o,this.userApi=new G(e),this.qrCodeStatusData={isLoading:!1,expired:!1},this._userInfo=r.get("userInfo")||r.get("xhs-cli-userInfo")||{},this.isLogin=!!(null===(t=this.userInfo)||void 0===t?void 0:t.nickName)}showQrCode(){m.generate(this.qrUrl,{small:!0})}async login(e="qrcode"){if(this.isLogin)this.logger.log("Had Login!!!");else{this.isLogin=!1,this.logger.log("Login...");try{if("qrcode"!==e)throw new Error("暂不支持扫码之外的其他登陆方式");{const e=await this.loginByQrcode();this.userInfo=e}this.isLogin=!0,this.logger.log("Login success")}catch(e){throw this.logger.log("Login fail:",e.message),this.isLogin=!1,this.userInfo=null,e}}}loginByQrcode(){return new Promise(((e,t)=>{this.loginPromise={resolve:e,reject:t};try{this.startPollingSub=this.startPolling().subscribe()}catch(e){console.error(e)}}))}logout(e){"axios"!==e.from&&this.logger.log("Logout..."),this.isLogin=!1,this.userInfo={},$.clear(),"axios"!==e.from&&this.logger.log("Logout Success!!!")}}const Z=async(e,t={},r,o)=>{let s=e.getCompileEntryPage();s={...s,...t};const{path:i,query:a,launchMode:n}=s;try{let e=await(async e=>{const t=Buffer.from(e.replace(/^data:image\/[a-z]+;base64,/,""),"base64"),r=await f.read(t),o={data:new Uint8ClampedArray(r.bitmap.data),width:r.bitmap.width,height:r.bitmap.height},s=S(o.data,o.width,o.height);if(!s)throw new Error("QR code not found in the image.");return s.data})(r);return i&&(e=e.replace("_develop",`_develop${i.startsWith("/")?"":"/"}${i}`)),a&&(e+=`&${a}`),"halfPageNativeFunctionalized"===n&&(e+="&runtime_mode=2"),e}catch(e){o.error("二维码解码失败:",e)}},{COMPILE_ENTRY:X}=require("xhs-mp-compiler-cli");class K extends Q{constructor(e){super(e),this.progressData={},this.previewData={},this.calcSize=e=>{var t,r;const o=this.project,s=(null===(t=null==o?void 0:o.flags)||void 0===t?void 0:t.enableV2Preivew)?"v2":"v1",i=(null===(r=null==e?void 0:e.filter)||void 0===r?void 0:r.call(e,(e=>e.type===s)).sort(((e,t)=>t.zipSize-e.zipSize)))||[];this.previewData.subPkgs=i.map(((e,t)=>({key:t,path:e.root,size:j(e.zipSize)})));const a=i.reduce(((e,t)=>t.zipSize+e),0)||0;this.previewData.zipSize=j(a)},this.uploadApi=new R(e),this.progressData={},this.previewData={}}preview(e){return new Promise(((t,r)=>{this.previewPromise={resolve:t,reject:r},this.doPreview(e)}))}doPreview(e){this.progressData.previewIsLoading=!0;const t=this.project.projectAppId,r=Date.now(),o=async t=>{var o,s;const i=JSON.parse(t.result.extra_json);this.previewData.qrcodeUrl=await Z(this.project,e.entry,i.qrcode,this.logger),this.showQrCode(this.previewData.qrcodeUrl),this.previewData.previewTotalTime=+((Date.now()-r)/1e3).toFixed(1),this.progressData.previewIsLoading=!1,this.compilerManager.killCompiler(X.preview),null===(o=this.taskSubscription)||void 0===o||o.unsubscribe(),this.taskSubscription=null,null===(s=this.previewPromise)||void 0===s||s.resolve({qrcodeUrl:this.previewData.qrcodeUrl}),this.previewPromise=null,this.logger.log("Preview Done!!!")},s=e=>{var t,r;this.compilerManager.killCompiler(X.preview),null===(t=this.taskSubscription)||void 0===t||t.unsubscribe(),this.taskSubscription=null,null===(r=this.previewPromise)||void 0===r||r.reject(e),this.previewPromise=null,this.logger.log("Preview Error:",e.toString())};this.taskSubscription=u.from(this.getCheckUploadAuthFn(this.uploadApi,"debug")).pipe(u.switchMap((e=>{let t=e.can_upload_ext_json,r=e.upload_app_id;if(!r)throw new Error("请检查是否该appid无权限");return u.from(this.compilerManager.compileAndZip({entryType:X.preview,can_upload_ext_json:t,upload_app_id:r}))})),u.tap((e=>{this.calcSize(e)})),u.switchMap((e=>{this.emit("compile-and-zip-status",{status:"uploading"}),this.logger.log("Upload packages to cos...");const r=e.map(((e,r)=>this.uploadPkgZipOrSourcemap(this.uploadApi,{appId:t,zipPath:e.zipPath,type:e.type,root:e.root},r)));return u.forkJoin(r)})),u.switchMap((e=>(this.logger.log("Upload packages info..."),this.submitTask({uploadApi:this.uploadApi,uploadRes:e,appId:t,version:"debug"}))))).subscribe({next:e=>o(e),error:e=>s(e)})}showQrCode(e){m.generate(e,{small:!0})}}const ee={code:"code",cli:"cli"};class te{constructor({core:e}){this.data={},this.core=e,this.extract()}extract(){if(this.core.scene===ee.cli){if(this.jsonPath=s.join(E,"storage.json"),a.existsSync(this.jsonPath))try{this.data=a.readJSONSync(this.jsonPath)}catch(e){this.data={}}}else this.data={}}store(){this.core.scene===ee.cli&&a.writeJSONSync(this.jsonPath,this.data)}get(e){return this.data[e]}set(e,t){this.data[e]=t,this.refresh()}refresh(){this.store()}}exports.Core=class{constructor(e){this.globalConfig={},this.appConfigMap={},this.projectMap={},this.compilerManagerMap={},this.scene=ee.code;const{scene:r=ee.code}=e;this.scene=r,this.logger=new t.Logger("[xhs-mp-cli]"),this.storage=new te({core:this}),this.globalConfig=this.storage.get("xhs-cli-global-config")||{},this.appConfigMap=this.storage.get("xhs-cli-app-config")||{},this.logger.debug("get initial config:",this.globalConfig,this.appConfigMap),globalThis.logger=this.logger,this.loginManager=new W({core:this,storage:this.storage,logger:this.logger})}setGlobalConfig(e={}){this.globalConfig={...this.globalConfig||{},...e},this.storage.set("xhs-cli-global-config",e),this.logger.log("Set global config done")}getGlobalConfig(){return this.globalConfig||{}}setAppConfig(e={}){const{appId:t,config:r}=e;t?(this.appConfigMap[t]={...this.appConfigMap[t]||{},...r},this.storage.set("xhs-cli-app-config",this.appConfigMap),this.logger.log("Set app config done")):this.logger.error("没有传递 appid 参数")}getAppConfig(e){return this.appConfigMap[e]||{}}createOrGetProject(t){let r=t.projectPath;if(!r)throw new Error("没有配置projectPath");return s.isAbsolute(r)||(r=s.join(v.cwd(),r)),this.projectMap[r]||(this.projectMap[r]=new e.Project(t)),this.projectMap[r]}getCompilerManager(e,t){let r=e.projectPath;if(s.isAbsolute(r)||(r=s.join(v.cwd(),r)),!this.compilerManagerMap[r]){const o=this.createOrGetProject(e);this.compilerManagerMap[r]=new k.ProjectCompilerManager({...t,project:o,logger:this.logger})}return this.compilerManagerMap[r]}async login(e={}){e.verbose&&this.logger.setVerbose(!0);const{type:t="qrcode"}=e;await this.loginManager.login(t)}logout(e){this.loginManager.logout(e)}isTokenAuth(e){return!!this.getAppConfig(e).token}getTokenParams(e){const t=this.getAppConfig(e).token,r="xxxxxxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)})),o=e+"#"+t+"#"+r+"#"+D("YYYYMMDDHHmm"),s=q(o);return this.logger.debug("cliToken",o,s),{cliToken:s,nonce:r,appId:e}}checkAppId(e){if(!this.appConfigMap[e])throw new Error(`找不到项目内appId(${e})对应的配置,请先确认appId是否保持一致`)}async preview(e){e.verbose&&this.logger.setVerbose(!0);const t=e.project||{},r=e.buildConfig||{},o=this.createOrGetProject(t);this.checkAppId(o.projectAppId),this.logger.log("Project:",o.projectPath),this.logger.debug("Preview options:",e);const s=this.appConfigMap[o.projectAppId];(null==s?void 0:s.token)?this.logger.debug("Auth by token"):(this.logger.debug("Auth by qrCode"),this.loginManager.isLogin||await this.login());const i=this.getCompilerManager(t,r),a=new K({core:this,project:o,compilerManager:i,logger:this.logger});try{return await a.preview({entry:e.entry})}finally{i.killAll()}}async upload(e){const{project:t,buildConfig:r={},version:o,desc:s,progressCallback:i}=e;e.verbose&&this.logger.setVerbose(!0);const a=this.createOrGetProject(t);this.checkAppId(a.projectAppId),this.logger.log("ProjectPath:",a.projectPath),this.logger.debug("Upload options:",e);const n=this.appConfigMap[a.projectAppId];(null==n?void 0:n.token)?this.logger.debug("Auth by token"):(this.logger.debug("Auth by login"),this.loginManager.isLogin||await this.login());const p=this.getCompilerManager(t,r),l=new Y({core:this,project:a,compilerManager:p,logger:this.logger});try{return await l.upload({userVersion:o,userDesc:s,progressCallback:i})}finally{p.killAll()}}};
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { Project } from 'xhs-mp-project';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProjectCompilerManager } from 'xhs-mp-compiler-cli';
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
4
|
import { Core } from '../core';
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
import { UploadApi } from 'api/uploadApi';
|
|
7
|
+
type IArchType = 'v0' | 'v1' | 'v2';
|
|
7
8
|
export interface IUploadCheckVersionParams {
|
|
8
9
|
version: 'debug' | 'develop';
|
|
9
10
|
}
|
|
10
|
-
type IArchType = 'v0' | 'v1' | 'v2';
|
|
11
|
-
export type IZipResult = {
|
|
12
|
-
type: IArchType;
|
|
13
|
-
zipPath: string;
|
|
14
|
-
zipSize: number;
|
|
15
|
-
root: string;
|
|
16
|
-
originSize: number;
|
|
17
|
-
};
|
|
18
11
|
interface IUploadFileOpts {
|
|
19
12
|
appId: string;
|
|
20
13
|
version?: string;
|
|
@@ -41,14 +34,14 @@ interface ISubmitTaskRes {
|
|
|
41
34
|
export interface IBaseServiceProps {
|
|
42
35
|
core: Core;
|
|
43
36
|
project: Project;
|
|
44
|
-
|
|
37
|
+
compilerManager: ProjectCompilerManager;
|
|
45
38
|
logger: any;
|
|
46
39
|
}
|
|
47
40
|
export type IFinalRes = any;
|
|
48
41
|
export declare class BaseService extends EventEmitter {
|
|
49
42
|
core: Core;
|
|
50
43
|
project: Project;
|
|
51
|
-
|
|
44
|
+
compilerManager: ProjectCompilerManager;
|
|
52
45
|
logger: any;
|
|
53
46
|
constructor(props: IBaseServiceProps);
|
|
54
47
|
getCheckUploadAuthFn(uploadApi: any, version: string): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xhs-mp-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"querystring": "^0.2.1",
|
|
29
29
|
"rxjs": "^7.8.1",
|
|
30
30
|
"tough-cookie": "^4.1.3",
|
|
31
|
-
"xhs-mp-compiler-cli": "2.0.
|
|
32
|
-
"xhs-mp-project": "2.0.
|
|
33
|
-
"xhs-mp-shared": "2.0.
|
|
31
|
+
"xhs-mp-compiler-cli": "2.0.3",
|
|
32
|
+
"xhs-mp-project": "2.0.3",
|
|
33
|
+
"xhs-mp-shared": "2.0.3"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@rollup/plugin-commonjs": "^25.0.7",
|