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 CHANGED
@@ -54,7 +54,7 @@ export declare class Core {
54
54
  private globalConfig;
55
55
  private appConfigMap;
56
56
  private projectMap;
57
- private compilerMap;
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 getCompiler;
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 { ProjectCompiler } from 'xhs-mp-compiler-cli';
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
- compiler: ProjectCompiler;
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
- compiler: ProjectCompiler;
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.2",
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.2",
32
- "xhs-mp-project": "2.0.2",
33
- "xhs-mp-shared": "2.0.2"
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",