├── .eslintrc.js ├── .gitignore ├── .yarn ├── plugins │ └── @yarnpkg │ │ └── plugin-typescript.cjs └── releases │ └── yarn-3.0.2.cjs ├── .yarnrc.yml ├── README.md ├── _templates ├── component │ ├── assets │ │ └── styled.ts.t │ ├── index.tsx.t │ └── interface.ts.t ├── layout │ ├── asset │ │ └── styled.ts.t │ ├── index.tsx.t │ └── interface.ts.t └── state │ └── index.ts.t ├── electron-builder.yml ├── main ├── background.ts └── helpers │ ├── create-window.ts │ ├── index.ts │ ├── ipc.ts │ └── logger.ts ├── package.json ├── renderer ├── _document.tsx ├── components │ └── Titlebar │ │ ├── assets │ │ └── titlebar.ts │ │ └── index.tsx ├── layouts │ └── main │ │ ├── assets │ │ └── styled.ts │ │ └── index.tsx ├── next-env.d.ts ├── next.config.js ├── pages │ ├── _app.tsx │ └── home.tsx ├── public │ └── images │ │ └── logo.png ├── styles │ └── globals.sass └── tsconfig.json ├── resources ├── icon.icns └── icon.ico ├── tsconfig.json └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const {off} = require("./renderer/.next/static/chunks/main"); 2 | module.exports = { 3 | extends: [ 4 | 'airbnb-typescript', 5 | 'airbnb/hooks', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:prettier/recommended' 8 | ], 9 | plugins: ['react', '@typescript-eslint'], 10 | env: { 11 | browser: true, 12 | es6: true, 13 | jest: true, 14 | }, 15 | globals: { 16 | Atomics: 'readonly', 17 | SharedArrayBuffer: 'readonly', 18 | }, 19 | parser: '@typescript-eslint/parser', 20 | parserOptions: { 21 | ecmaFeatures: { 22 | jsx: true, 23 | }, 24 | ecmaVersion: 2018, 25 | sourceType: 'module', 26 | project: './tsconfig.json', 27 | }, 28 | rules: { 29 | '@typescript-eslint/no-explicit-any': 'off', 30 | 'react/require-default-props': 'off', 31 | 'react/jsx-props-no-spreading': 'off', 32 | 'linebreak-style': 'off', 33 | 'import/no-extraneous-dependencies': 'off', 34 | 'react/button-has-type': 'off', 35 | '@typescript-eslint/ban-ts-comment': 'off', 36 | "no-console": 'off', 37 | 'react-hooks/exhaustive-deps': 'off', 38 | 'jsx-a11y/control-has-associated-label': 'off', 39 | 'prettier/prettier': [ 40 | 'error', 41 | { 42 | endOfLine: 'auto', 43 | }, 44 | ], 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .next 4 | app 5 | dist 6 | renderer/.next 7 | .idea 8 | .vscode 9 | 10 | .pnp.* 11 | .yarn/* 12 | !.yarn/patches 13 | !.yarn/plugins 14 | !.yarn/releases 15 | !.yarn/sdks 16 | !.yarn/versions 17 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-typescript.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-typescript", 5 | factory: function (require) { 6 | var plugin=(()=>{var Ft=Object.create,H=Object.defineProperty,Bt=Object.defineProperties,Kt=Object.getOwnPropertyDescriptor,zt=Object.getOwnPropertyDescriptors,Gt=Object.getOwnPropertyNames,Q=Object.getOwnPropertySymbols,$t=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty,De=Object.prototype.propertyIsEnumerable;var Re=(e,t,r)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,u=(e,t)=>{for(var r in t||(t={}))ne.call(t,r)&&Re(e,r,t[r]);if(Q)for(var r of Q(t))De.call(t,r)&&Re(e,r,t[r]);return e},g=(e,t)=>Bt(e,zt(t)),Lt=e=>H(e,"__esModule",{value:!0});var R=(e,t)=>{var r={};for(var s in e)ne.call(e,s)&&t.indexOf(s)<0&&(r[s]=e[s]);if(e!=null&&Q)for(var s of Q(e))t.indexOf(s)<0&&De.call(e,s)&&(r[s]=e[s]);return r};var I=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Vt=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Qt=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Gt(t))!ne.call(e,s)&&s!=="default"&&H(e,s,{get:()=>t[s],enumerable:!(r=Kt(t,s))||r.enumerable});return e},C=e=>Qt(Lt(H(e!=null?Ft($t(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var xe=I(J=>{"use strict";Object.defineProperty(J,"__esModule",{value:!0});function _(e){let t=[...e.caches],r=t.shift();return r===void 0?ve():{get(s,n,a={miss:()=>Promise.resolve()}){return r.get(s,n,a).catch(()=>_({caches:t}).get(s,n,a))},set(s,n){return r.set(s,n).catch(()=>_({caches:t}).set(s,n))},delete(s){return r.delete(s).catch(()=>_({caches:t}).delete(s))},clear(){return r.clear().catch(()=>_({caches:t}).clear())}}}function ve(){return{get(e,t,r={miss:()=>Promise.resolve()}){return t().then(n=>Promise.all([n,r.miss(n)])).then(([n])=>n)},set(e,t){return Promise.resolve(t)},delete(e){return Promise.resolve()},clear(){return Promise.resolve()}}}J.createFallbackableCache=_;J.createNullCache=ve});var Ee=I(($s,qe)=>{qe.exports=xe()});var Te=I(ae=>{"use strict";Object.defineProperty(ae,"__esModule",{value:!0});function Jt(e={serializable:!0}){let t={};return{get(r,s,n={miss:()=>Promise.resolve()}){let a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);let o=s(),d=n&&n.miss||(()=>Promise.resolve());return o.then(y=>d(y)).then(()=>o)},set(r,s){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete t[JSON.stringify(r)],Promise.resolve()},clear(){return t={},Promise.resolve()}}}ae.createInMemoryCache=Jt});var we=I((Vs,Me)=>{Me.exports=Te()});var Ce=I(M=>{"use strict";Object.defineProperty(M,"__esModule",{value:!0});function Xt(e,t,r){let s={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers(){return e===oe.WithinHeaders?s:{}},queryParameters(){return e===oe.WithinQueryParameters?s:{}}}}function Yt(e){let t=0,r=()=>(t++,new Promise(s=>{setTimeout(()=>{s(e(r))},Math.min(100*t,1e3))}));return e(r)}function ke(e,t=(r,s)=>Promise.resolve()){return Object.assign(e,{wait(r){return ke(e.then(s=>Promise.all([t(s,r),s])).then(s=>s[1]))}})}function Zt(e){let t=e.length-1;for(t;t>0;t--){let r=Math.floor(Math.random()*(t+1)),s=e[t];e[t]=e[r],e[r]=s}return e}function er(e,t){return Object.keys(t!==void 0?t:{}).forEach(r=>{e[r]=t[r](e)}),e}function tr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}var rr="4.2.0",sr=e=>()=>e.transporter.requester.destroy(),oe={WithinQueryParameters:0,WithinHeaders:1};M.AuthMode=oe;M.addMethods=er;M.createAuth=Xt;M.createRetryablePromise=Yt;M.createWaitablePromise=ke;M.destroy=sr;M.encode=tr;M.shuffle=Zt;M.version=rr});var F=I((Js,Ue)=>{Ue.exports=Ce()});var Ne=I(ie=>{"use strict";Object.defineProperty(ie,"__esModule",{value:!0});var nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};ie.MethodEnum=nr});var B=I((Ys,We)=>{We.exports=Ne()});var Ze=I(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});var He=B();function ce(e,t){let r=e||{},s=r.data||{};return Object.keys(r).forEach(n=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(n)===-1&&(s[n]=r[n])}),{data:Object.entries(s).length>0?s:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var X={Read:1,Write:2,Any:3},U={Up:1,Down:2,Timeouted:3},_e=2*60*1e3;function ue(e,t=U.Up){return g(u({},e),{status:t,lastUpdate:Date.now()})}function Fe(e){return e.status===U.Up||Date.now()-e.lastUpdate>_e}function Be(e){return e.status===U.Timeouted&&Date.now()-e.lastUpdate<=_e}function le(e){return{protocol:e.protocol||"https",url:e.url,accept:e.accept||X.Any}}function ar(e,t){return Promise.all(t.map(r=>e.get(r,()=>Promise.resolve(ue(r))))).then(r=>{let s=r.filter(d=>Fe(d)),n=r.filter(d=>Be(d)),a=[...s,...n],o=a.length>0?a.map(d=>le(d)):t;return{getTimeout(d,y){return(n.length===0&&d===0?1:n.length+3+d)*y},statelessHosts:o}})}var or=({isTimedOut:e,status:t})=>!e&&~~t==0,ir=e=>{let t=e.status;return e.isTimedOut||or(e)||~~(t/100)!=2&&~~(t/100)!=4},cr=({status:e})=>~~(e/100)==2,ur=(e,t)=>ir(e)?t.onRetry(e):cr(e)?t.onSucess(e):t.onFail(e);function Qe(e,t,r,s){let n=[],a=$e(r,s),o=Le(e,s),d=r.method,y=r.method!==He.MethodEnum.Get?{}:u(u({},r.data),s.data),b=u(u(u({"x-algolia-agent":e.userAgent.value},e.queryParameters),y),s.queryParameters),f=0,p=(h,S)=>{let O=h.pop();if(O===void 0)throw Ve(de(n));let P={data:a,headers:o,method:d,url:Ge(O,r.path,b),connectTimeout:S(f,e.timeouts.connect),responseTimeout:S(f,s.timeout)},x=j=>{let T={request:P,response:j,host:O,triesLeft:h.length};return n.push(T),T},v={onSucess:j=>Ke(j),onRetry(j){let T=x(j);return j.isTimedOut&&f++,Promise.all([e.logger.info("Retryable failure",pe(T)),e.hostsCache.set(O,ue(O,j.isTimedOut?U.Timeouted:U.Down))]).then(()=>p(h,S))},onFail(j){throw x(j),ze(j,de(n))}};return e.requester.send(P).then(j=>ur(j,v))};return ar(e.hostsCache,t).then(h=>p([...h.statelessHosts].reverse(),h.getTimeout))}function lr(e){let{hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,hosts:y,queryParameters:b,headers:f}=e,p={hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,headers:f,queryParameters:b,hosts:y.map(h=>le(h)),read(h,S){let O=ce(S,p.timeouts.read),P=()=>Qe(p,p.hosts.filter(j=>(j.accept&X.Read)!=0),h,O);if((O.cacheable!==void 0?O.cacheable:h.cacheable)!==!0)return P();let v={request:h,mappedRequestOptions:O,transporter:{queryParameters:p.queryParameters,headers:p.headers}};return p.responsesCache.get(v,()=>p.requestsCache.get(v,()=>p.requestsCache.set(v,P()).then(j=>Promise.all([p.requestsCache.delete(v),j]),j=>Promise.all([p.requestsCache.delete(v),Promise.reject(j)])).then(([j,T])=>T)),{miss:j=>p.responsesCache.set(v,j)})},write(h,S){return Qe(p,p.hosts.filter(O=>(O.accept&X.Write)!=0),h,ce(S,p.timeouts.write))}};return p}function dr(e){let t={value:`Algolia for JavaScript (${e})`,add(r){let s=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return t.value.indexOf(s)===-1&&(t.value=`${t.value}${s}`),t}};return t}function Ke(e){try{return JSON.parse(e.content)}catch(t){throw Je(t.message,e)}}function ze({content:e,status:t},r){let s=e;try{s=JSON.parse(e).message}catch(n){}return Xe(s,t,r)}function pr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}function Ge(e,t,r){let s=Ye(r),n=`${e.protocol}://${e.url}/${t.charAt(0)==="/"?t.substr(1):t}`;return s.length&&(n+=`?${s}`),n}function Ye(e){let t=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(e).map(r=>pr("%s=%s",r,t(e[r])?JSON.stringify(e[r]):e[r])).join("&")}function $e(e,t){if(e.method===He.MethodEnum.Get||e.data===void 0&&t.data===void 0)return;let r=Array.isArray(e.data)?e.data:u(u({},e.data),t.data);return JSON.stringify(r)}function Le(e,t){let r=u(u({},e.headers),t.headers),s={};return Object.keys(r).forEach(n=>{let a=r[n];s[n.toLowerCase()]=a}),s}function de(e){return e.map(t=>pe(t))}function pe(e){let t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return g(u({},e),{request:g(u({},e.request),{headers:u(u({},e.request.headers),t)})})}function Xe(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}function Je(e,t){return{name:"DeserializationError",message:e,response:t}}function Ve(e){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:e}}A.CallEnum=X;A.HostStatusEnum=U;A.createApiError=Xe;A.createDeserializationError=Je;A.createMappedRequestOptions=ce;A.createRetryError=Ve;A.createStatefulHost=ue;A.createStatelessHost=le;A.createTransporter=lr;A.createUserAgent=dr;A.deserializeFailure=ze;A.deserializeSuccess=Ke;A.isStatefulHostTimeouted=Be;A.isStatefulHostUp=Fe;A.serializeData=$e;A.serializeHeaders=Le;A.serializeQueryParameters=Ye;A.serializeUrl=Ge;A.stackFrameWithoutCredentials=pe;A.stackTraceWithoutCredentials=de});var K=I((en,et)=>{et.exports=Ze()});var tt=I(w=>{"use strict";Object.defineProperty(w,"__esModule",{value:!0});var N=F(),mr=K(),z=B(),hr=e=>{let t=e.region||"us",r=N.createAuth(N.AuthMode.WithinHeaders,e.appId,e.apiKey),s=mr.createTransporter(g(u({hosts:[{url:`analytics.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n=e.appId;return N.addMethods({appId:n,transporter:s},e.methods)},yr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:"2/abtests",data:t},r),gr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Delete,path:N.encode("2/abtests/%s",t)},r),fr=e=>(t,r)=>e.transporter.read({method:z.MethodEnum.Get,path:N.encode("2/abtests/%s",t)},r),br=e=>t=>e.transporter.read({method:z.MethodEnum.Get,path:"2/abtests"},t),Pr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:N.encode("2/abtests/%s/stop",t)},r);w.addABTest=yr;w.createAnalyticsClient=hr;w.deleteABTest=gr;w.getABTest=fr;w.getABTests=br;w.stopABTest=Pr});var st=I((rn,rt)=>{rt.exports=tt()});var at=I(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});var me=F(),jr=K(),nt=B(),Or=e=>{let t=e.region||"us",r=me.createAuth(me.AuthMode.WithinHeaders,e.appId,e.apiKey),s=jr.createTransporter(g(u({hosts:[{url:`recommendation.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)}));return me.addMethods({appId:e.appId,transporter:s},e.methods)},Ir=e=>t=>e.transporter.read({method:nt.MethodEnum.Get,path:"1/strategies/personalization"},t),Ar=e=>(t,r)=>e.transporter.write({method:nt.MethodEnum.Post,path:"1/strategies/personalization",data:t},r);G.createRecommendationClient=Or;G.getPersonalizationStrategy=Ir;G.setPersonalizationStrategy=Ar});var it=I((nn,ot)=>{ot.exports=at()});var jt=I(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});var l=F(),q=K(),m=B(),Sr=require("crypto");function Y(e){let t=r=>e.request(r).then(s=>{if(e.batch!==void 0&&e.batch(s.hits),!e.shouldStop(s))return s.cursor?t({cursor:s.cursor}):t({page:(r.page||0)+1})});return t({})}var Dr=e=>{let t=e.appId,r=l.createAuth(e.authMode!==void 0?e.authMode:l.AuthMode.WithinHeaders,t,e.apiKey),s=q.createTransporter(g(u({hosts:[{url:`${t}-dsn.algolia.net`,accept:q.CallEnum.Read},{url:`${t}.algolia.net`,accept:q.CallEnum.Write}].concat(l.shuffle([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}]))},e),{headers:u(g(u({},r.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n={transporter:s,appId:t,addAlgoliaAgent(a,o){s.userAgent.add({segment:a,version:o})},clearCache(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(()=>{})}};return l.addMethods(n,e.methods)};function ct(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function ut(){return{name:"ObjectNotFoundError",message:"Object not found."}}function lt(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Rr=e=>(t,r)=>{let d=r||{},{queryParameters:s}=d,n=R(d,["queryParameters"]),a=u({acl:t},s!==void 0?{queryParameters:s}:{}),o=(y,b)=>l.createRetryablePromise(f=>$(e)(y.key,b).catch(p=>{if(p.status!==404)throw p;return f()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/keys",data:a},n),o)},vr=e=>(t,r,s)=>{let n=q.createMappedRequestOptions(s);return n.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},n)},xr=e=>(t,r,s)=>e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:t,cluster:r}},s),Z=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"copy",destination:r}},s),n)},qr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Rules]})),Er=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Settings]})),Tr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Synonyms]})),Mr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).then(o).catch(d=>{if(d.status!==404)throw d}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/keys/%s",t)},r),s)},wr=()=>(e,t)=>{let r=q.serializeQueryParameters(t),s=Sr.createHmac("sha256",e).update(r).digest("hex");return Buffer.from(s+r).toString("base64")},$=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/keys/%s",t)},r),kr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/logs"},t),Cr=()=>e=>{let t=Buffer.from(e,"base64").toString("ascii"),r=/validUntil=(\d+)/,s=t.match(r);if(s===null)throw lt();return parseInt(s[1],10)-Math.round(new Date().getTime()/1e3)},Ur=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/top"},t),Nr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/clusters/mapping/%s",t)},r),Wr=e=>t=>{let n=t||{},{retrieveMappings:r}=n,s=R(n,["retrieveMappings"]);return r===!0&&(s.getClusters=!0),e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/pending"},s)},L=e=>(t,r={})=>{let s={transporter:e.transporter,appId:e.appId,indexName:t};return l.addMethods(s,r.methods)},Hr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/keys"},t),_r=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters"},t),Fr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/indexes"},t),Br=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping"},t),Kr=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"move",destination:r}},s),n)},zr=e=>(t,r)=>{let s=(n,a)=>Promise.all(Object.keys(n.taskID).map(o=>L(e)(o,{methods:{waitTask:D}}).waitTask(n.taskID[o],a)));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:t}},r),s)},Gr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:t}},r),$r=e=>(t,r)=>{let s=t.map(n=>g(u({},n),{params:q.serializeQueryParameters(n.params||{})}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:s},cacheable:!0},r)},Lr=e=>(t,r)=>Promise.all(t.map(s=>{let d=s.params,{facetName:n,facetQuery:a}=d,o=R(d,["facetName","facetQuery"]);return L(e)(s.indexName,{methods:{searchForFacetValues:dt}}).searchForFacetValues(n,a,u(u({},r),o))})),Vr=e=>(t,r)=>{let s=q.createMappedRequestOptions(r);return s.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Delete,path:"1/clusters/mapping"},s)},Qr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).catch(d=>{if(d.status!==404)throw d;return o()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/keys/%s/restore",t)},r),s)},Jr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:t}},r),Xr=e=>(t,r)=>{let s=Object.assign({},r),f=r||{},{queryParameters:n}=f,a=R(f,["queryParameters"]),o=n?{queryParameters:n}:{},d=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],y=p=>Object.keys(s).filter(h=>d.indexOf(h)!==-1).every(h=>p[h]===s[h]),b=(p,h)=>l.createRetryablePromise(S=>$(e)(t,h).then(O=>y(O)?Promise.resolve():S()));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/keys/%s",t),data:o},a),b)},pt=e=>(t,r)=>{let s=(n,a)=>D(e)(n.taskID,a);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/batch",e.indexName),data:{requests:t}},r),s)},Yr=e=>t=>Y(g(u({},t),{shouldStop:r=>r.cursor===void 0,request:r=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/browse",e.indexName),data:r},t)})),Zr=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},es=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},te=e=>(t,r,s)=>{let y=s||{},{batchSize:n}=y,a=R(y,["batchSize"]),o={taskIDs:[],objectIDs:[]},d=(b=0)=>{let f=[],p;for(p=b;p({action:r,body:h})),a).then(h=>(o.objectIDs=o.objectIDs.concat(h.objectIDs),o.taskIDs.push(h.taskID),p++,d(p)))};return l.createWaitablePromise(d(),(b,f)=>Promise.all(b.taskIDs.map(p=>D(e)(p,f))))},ts=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/clear",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),rs=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ss=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ns=e=>(t,r)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/deleteByQuery",e.indexName),data:t},r),(s,n)=>D(e)(s.taskID,n)),as=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),os=e=>(t,r)=>l.createWaitablePromise(yt(e)([t],r).then(s=>({taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),yt=e=>(t,r)=>{let s=t.map(n=>({objectID:n}));return te(e)(s,k.DeleteObject,r)},is=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},cs=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},us=e=>t=>gt(e)(t).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),ls=e=>(t,r)=>{let y=r||{},{query:s,paginate:n}=y,a=R(y,["query","paginate"]),o=0,d=()=>ft(e)(s||"",g(u({},a),{page:o})).then(b=>{for(let[f,p]of Object.entries(b.hits))if(t(p))return{object:p,position:parseInt(f,10),page:o};if(o++,n===!1||o>=b.nbPages)throw ut();return d()});return d()},ds=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/%s",e.indexName,t)},r),ps=()=>(e,t)=>{for(let[r,s]of Object.entries(e.hits))if(s.objectID===t)return parseInt(r,10);return-1},ms=e=>(t,r)=>{let o=r||{},{attributesToRetrieve:s}=o,n=R(o,["attributesToRetrieve"]),a=t.map(d=>u({indexName:e.indexName,objectID:d},s?{attributesToRetrieve:s}:{}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:a}},n)},hs=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},r),gt=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/settings",e.indexName),data:{getVersion:2}},t),ys=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},r),bt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/task/%s",e.indexName,t.toString())},r),gs=e=>(t,r)=>l.createWaitablePromise(Pt(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),Pt=e=>(t,r)=>{let o=r||{},{createIfNotExists:s}=o,n=R(o,["createIfNotExists"]),a=s?k.PartialUpdateObject:k.PartialUpdateObjectNoCreate;return te(e)(t,a,n)},fs=e=>(t,r)=>{let O=r||{},{safe:s,autoGenerateObjectIDIfNotExist:n,batchSize:a}=O,o=R(O,["safe","autoGenerateObjectIDIfNotExist","batchSize"]),d=(P,x,v,j)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",P),data:{operation:v,destination:x}},j),(T,V)=>D(e)(T.taskID,V)),y=Math.random().toString(36).substring(7),b=`${e.indexName}_tmp_${y}`,f=he({appId:e.appId,transporter:e.transporter,indexName:b}),p=[],h=d(e.indexName,b,"copy",g(u({},o),{scope:["settings","synonyms","rules"]}));p.push(h);let S=(s?h.wait(o):h).then(()=>{let P=f(t,g(u({},o),{autoGenerateObjectIDIfNotExist:n,batchSize:a}));return p.push(P),s?P.wait(o):P}).then(()=>{let P=d(b,e.indexName,"move",o);return p.push(P),s?P.wait(o):P}).then(()=>Promise.all(p)).then(([P,x,v])=>({objectIDs:x.objectIDs,taskIDs:[P.taskID,...x.taskIDs,v.taskID]}));return l.createWaitablePromise(S,(P,x)=>Promise.all(p.map(v=>v.wait(x))))},bs=e=>(t,r)=>ye(e)(t,g(u({},r),{clearExistingRules:!0})),Ps=e=>(t,r)=>ge(e)(t,g(u({},r),{replaceExistingSynonyms:!0})),js=e=>(t,r)=>l.createWaitablePromise(he(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),he=e=>(t,r)=>{let o=r||{},{autoGenerateObjectIDIfNotExist:s}=o,n=R(o,["autoGenerateObjectIDIfNotExist"]),a=s?k.AddObject:k.UpdateObject;if(a===k.UpdateObject){for(let d of t)if(d.objectID===void 0)return l.createWaitablePromise(Promise.reject(ct()))}return te(e)(t,a,n)},Os=e=>(t,r)=>ye(e)([t],r),ye=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,clearExistingRules:n}=d,a=R(d,["forwardToReplicas","clearExistingRules"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.clearExistingRules=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},Is=e=>(t,r)=>ge(e)([t],r),ge=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,replaceExistingSynonyms:n}=d,a=R(d,["forwardToReplicas","replaceExistingSynonyms"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.replaceExistingSynonyms=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},ft=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),dt=e=>(t,r,s)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},s),mt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/search",e.indexName),data:{query:t}},r),ht=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/search",e.indexName),data:{query:t}},r),As=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/indexes/%s/settings",e.indexName),data:t},a),(d,y)=>D(e)(d.taskID,y))},D=e=>(t,r)=>l.createRetryablePromise(s=>bt(e)(t,r).then(n=>n.status!=="published"?s():void 0)),Ss={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",ListIndexes:"listIndexes",Logs:"logs",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},k={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject"},ee={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},Ds={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},Rs={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};i.ApiKeyACLEnum=Ss;i.BatchActionEnum=k;i.ScopeEnum=ee;i.StrategyEnum=Ds;i.SynonymEnum=Rs;i.addApiKey=Rr;i.assignUserID=vr;i.assignUserIDs=xr;i.batch=pt;i.browseObjects=Yr;i.browseRules=Zr;i.browseSynonyms=es;i.chunkedBatch=te;i.clearObjects=ts;i.clearRules=rs;i.clearSynonyms=ss;i.copyIndex=Z;i.copyRules=qr;i.copySettings=Er;i.copySynonyms=Tr;i.createBrowsablePromise=Y;i.createMissingObjectIDError=ct;i.createObjectNotFoundError=ut;i.createSearchClient=Dr;i.createValidUntilNotFoundError=lt;i.deleteApiKey=Mr;i.deleteBy=ns;i.deleteIndex=as;i.deleteObject=os;i.deleteObjects=yt;i.deleteRule=is;i.deleteSynonym=cs;i.exists=us;i.findObject=ls;i.generateSecuredApiKey=wr;i.getApiKey=$;i.getLogs=kr;i.getObject=ds;i.getObjectPosition=ps;i.getObjects=ms;i.getRule=hs;i.getSecuredApiKeyRemainingValidity=Cr;i.getSettings=gt;i.getSynonym=ys;i.getTask=bt;i.getTopUserIDs=Ur;i.getUserID=Nr;i.hasPendingMappings=Wr;i.initIndex=L;i.listApiKeys=Hr;i.listClusters=_r;i.listIndices=Fr;i.listUserIDs=Br;i.moveIndex=Kr;i.multipleBatch=zr;i.multipleGetObjects=Gr;i.multipleQueries=$r;i.multipleSearchForFacetValues=Lr;i.partialUpdateObject=gs;i.partialUpdateObjects=Pt;i.removeUserID=Vr;i.replaceAllObjects=fs;i.replaceAllRules=bs;i.replaceAllSynonyms=Ps;i.restoreApiKey=Qr;i.saveObject=js;i.saveObjects=he;i.saveRule=Os;i.saveRules=ye;i.saveSynonym=Is;i.saveSynonyms=ge;i.search=ft;i.searchForFacetValues=dt;i.searchRules=mt;i.searchSynonyms=ht;i.searchUserIDs=Jr;i.setSettings=As;i.updateApiKey=Xr;i.waitTask=D});var It=I((on,Ot)=>{Ot.exports=jt()});var At=I(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});function vs(){return{debug(e,t){return Promise.resolve()},info(e,t){return Promise.resolve()},error(e,t){return Promise.resolve()}}}var xs={Debug:1,Info:2,Error:3};re.LogLevelEnum=xs;re.createNullLogger=vs});var Dt=I((un,St)=>{St.exports=At()});var xt=I(fe=>{"use strict";Object.defineProperty(fe,"__esModule",{value:!0});var Rt=require("http"),vt=require("https"),qs=require("url");function Es(){let e={keepAlive:!0},t=new Rt.Agent(e),r=new vt.Agent(e);return{send(s){return new Promise(n=>{let a=qs.parse(s.url),o=a.query===null?a.pathname:`${a.pathname}?${a.query}`,d=u({agent:a.protocol==="https:"?r:t,hostname:a.hostname,path:o,method:s.method,headers:s.headers},a.port!==void 0?{port:a.port||""}:{}),y=(a.protocol==="https:"?vt:Rt).request(d,h=>{let S="";h.on("data",O=>S+=O),h.on("end",()=>{clearTimeout(f),clearTimeout(p),n({status:h.statusCode||0,content:S,isTimedOut:!1})})}),b=(h,S)=>setTimeout(()=>{y.abort(),n({status:0,content:S,isTimedOut:!0})},h*1e3),f=b(s.connectTimeout,"Connection timeout"),p;y.on("error",h=>{clearTimeout(f),clearTimeout(p),n({status:0,content:h.message,isTimedOut:!1})}),y.once("response",()=>{clearTimeout(f),p=b(s.responseTimeout,"Socket timeout")}),s.data!==void 0&&y.write(s.data),y.end()})},destroy(){return t.destroy(),r.destroy(),Promise.resolve()}}}fe.createNodeHttpRequester=Es});var Et=I((dn,qt)=>{qt.exports=xt()});var kt=I((pn,Tt)=>{"use strict";var Mt=Ee(),Ts=we(),W=st(),be=F(),Pe=it(),c=It(),Ms=Dt(),ws=Et(),ks=K();function wt(e,t,r){let s={appId:e,apiKey:t,timeouts:{connect:2,read:5,write:30},requester:ws.createNodeHttpRequester(),logger:Ms.createNullLogger(),responsesCache:Mt.createNullCache(),requestsCache:Mt.createNullCache(),hostsCache:Ts.createInMemoryCache(),userAgent:ks.createUserAgent(be.version).add({segment:"Node.js",version:process.versions.node})};return c.createSearchClient(g(u(u({},s),r),{methods:{search:c.multipleQueries,searchForFacetValues:c.multipleSearchForFacetValues,multipleBatch:c.multipleBatch,multipleGetObjects:c.multipleGetObjects,multipleQueries:c.multipleQueries,copyIndex:c.copyIndex,copySettings:c.copySettings,copyRules:c.copyRules,copySynonyms:c.copySynonyms,moveIndex:c.moveIndex,listIndices:c.listIndices,getLogs:c.getLogs,listClusters:c.listClusters,multipleSearchForFacetValues:c.multipleSearchForFacetValues,getApiKey:c.getApiKey,addApiKey:c.addApiKey,listApiKeys:c.listApiKeys,updateApiKey:c.updateApiKey,deleteApiKey:c.deleteApiKey,restoreApiKey:c.restoreApiKey,assignUserID:c.assignUserID,assignUserIDs:c.assignUserIDs,getUserID:c.getUserID,searchUserIDs:c.searchUserIDs,listUserIDs:c.listUserIDs,getTopUserIDs:c.getTopUserIDs,removeUserID:c.removeUserID,hasPendingMappings:c.hasPendingMappings,generateSecuredApiKey:c.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:c.getSecuredApiKeyRemainingValidity,destroy:be.destroy,initIndex:n=>a=>c.initIndex(n)(a,{methods:{batch:c.batch,delete:c.deleteIndex,getObject:c.getObject,getObjects:c.getObjects,saveObject:c.saveObject,saveObjects:c.saveObjects,search:c.search,searchForFacetValues:c.searchForFacetValues,waitTask:c.waitTask,setSettings:c.setSettings,getSettings:c.getSettings,partialUpdateObject:c.partialUpdateObject,partialUpdateObjects:c.partialUpdateObjects,deleteObject:c.deleteObject,deleteObjects:c.deleteObjects,deleteBy:c.deleteBy,clearObjects:c.clearObjects,browseObjects:c.browseObjects,getObjectPosition:c.getObjectPosition,findObject:c.findObject,exists:c.exists,saveSynonym:c.saveSynonym,saveSynonyms:c.saveSynonyms,getSynonym:c.getSynonym,searchSynonyms:c.searchSynonyms,browseSynonyms:c.browseSynonyms,deleteSynonym:c.deleteSynonym,clearSynonyms:c.clearSynonyms,replaceAllObjects:c.replaceAllObjects,replaceAllSynonyms:c.replaceAllSynonyms,searchRules:c.searchRules,getRule:c.getRule,deleteRule:c.deleteRule,saveRule:c.saveRule,saveRules:c.saveRules,replaceAllRules:c.replaceAllRules,browseRules:c.browseRules,clearRules:c.clearRules}}),initAnalytics:()=>n=>W.createAnalyticsClient(g(u(u({},s),n),{methods:{addABTest:W.addABTest,getABTest:W.getABTest,getABTests:W.getABTests,stopABTest:W.stopABTest,deleteABTest:W.deleteABTest}})),initRecommendation:()=>n=>Pe.createRecommendationClient(g(u(u({},s),n),{methods:{getPersonalizationStrategy:Pe.getPersonalizationStrategy,setPersonalizationStrategy:Pe.setPersonalizationStrategy}}))}}))}wt.version=be.version;Tt.exports=wt});var Ut=I((mn,je)=>{var Ct=kt();je.exports=Ct;je.exports.default=Ct});var Ws={};Vt(Ws,{default:()=>Ks});var Oe=C(require("@yarnpkg/core")),E=C(require("@yarnpkg/core")),Ie=C(require("@yarnpkg/plugin-essentials")),Ht=C(require("semver"));var se=C(require("@yarnpkg/core")),Nt=C(Ut()),Cs="e8e1bd300d860104bb8c58453ffa1eb4",Us="OFCNCOG2CU",Wt=async(e,t)=>{var a;let r=se.structUtils.stringifyIdent(e),n=Ns(t).initIndex("npm-search");try{return((a=(await n.getObject(r,{attributesToRetrieve:["types"]})).types)==null?void 0:a.ts)==="definitely-typed"}catch(o){return!1}},Ns=e=>(0,Nt.default)(Us,Cs,{requester:{async send(r){try{let s=await se.httpUtils.request(r.url,r.data||null,{configuration:e,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var _t=e=>e.scope?`${e.scope}__${e.name}`:`${e.name}`,Hs=async(e,t,r,s)=>{if(r.scope==="types")return;let{project:n}=e,{configuration:a}=n,o=a.makeResolver(),d={project:n,resolver:o,report:new E.ThrowReport};if(!await Wt(r,a))return;let b=_t(r),f=E.structUtils.parseRange(r.range).selector;if(!E.semverUtils.validRange(f)){let P=await o.getCandidates(r,new Map,d);f=E.structUtils.parseRange(P[0].reference).selector}let p=Ht.default.coerce(f);if(p===null)return;let h=`${Ie.suggestUtils.Modifier.CARET}${p.major}`,S=E.structUtils.makeDescriptor(E.structUtils.makeIdent("types",b),h),O=E.miscUtils.mapAndFind(n.workspaces,P=>{var T,V;let x=(T=P.manifest.dependencies.get(r.identHash))==null?void 0:T.descriptorHash,v=(V=P.manifest.devDependencies.get(r.identHash))==null?void 0:V.descriptorHash;if(x!==r.descriptorHash&&v!==r.descriptorHash)return E.miscUtils.mapAndFind.skip;let j=[];for(let Ae of Oe.Manifest.allDependencies){let Se=P.manifest[Ae].get(S.identHash);typeof Se!="undefined"&&j.push([Ae,Se])}return j.length===0?E.miscUtils.mapAndFind.skip:j});if(typeof O!="undefined")for(let[P,x]of O)e.manifest[P].set(x.identHash,x);else{try{if((await o.getCandidates(S,new Map,d)).length===0)return}catch{return}e.manifest[Ie.suggestUtils.Target.DEVELOPMENT].set(S.identHash,S)}},_s=async(e,t,r)=>{if(r.scope==="types")return;let s=_t(r),n=E.structUtils.makeIdent("types",s);for(let a of Oe.Manifest.allDependencies)typeof e.manifest[a].get(n.identHash)!="undefined"&&e.manifest[a].delete(n.identHash)},Fs=(e,t)=>{t.publishConfig&&t.publishConfig.typings&&(t.typings=t.publishConfig.typings),t.publishConfig&&t.publishConfig.types&&(t.types=t.publishConfig.types)},Bs={hooks:{afterWorkspaceDependencyAddition:Hs,afterWorkspaceDependencyRemoval:_s,beforeWorkspacePacking:Fs}},Ks=Bs;return Ws;})(); 7 | return plugin; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs 5 | spec: "@yarnpkg/plugin-typescript" 6 | 7 | yarnPath: .yarn/releases/yarn-3.0.2.cjs 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Deprecated in favour of: 2 | [Needlework.Net](https://github.com/BlossomiShymae/Needlework.Net) 3 | 4 | # LCU Explorer 5 | 6 | --- 7 | 8 | A replacement for rift explorer which doesn't need restarting from the original contributors 9 | 10 | ## Usage 11 | 12 | - Download the [latest release from GitHub](https://github.com/HextechDocs/lcu-explorer/releases/latest) (exe installer or unpacked standalone zip). 13 | - LCU Explorer should start after installing, or start manually after unzipping. 14 | - If the LoL client is not already running, start it now. 15 | - Endpoints will show immediately after launching, but "try it out" is hidden unless the client is running. 16 | 17 | ## Development 18 | 19 | ### Install dependencies 20 | ``` 21 | yarn 22 | ``` 23 | then... 24 | 25 | ### Run in dev mode 26 | ``` 27 | yarn dev 28 | ``` 29 | 30 | ### Build 31 | ``` 32 | yarn build 33 | ``` 34 | 35 | ## Credits 36 | 37 | **Massive thank you to [Mingwei Samuel](https://github.com/MingweiSamuel)** for his work on this app and the backend driving it. 38 | -------------------------------------------------------------------------------- /_templates/component/assets/styled.ts.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/components/<%= h.capitalize(name) %>/assets/Styled.ts 3 | --- 4 | import styled from 'styled-components'; 5 | import theme from 'styled-theming'; 6 | 7 | const backgroundColor = theme('mode', { 8 | light: '#ddd', 9 | dark: '#222', 10 | }); 11 | 12 | const Styled = styled.div` 13 | background-color: ${backgroundColor}; 14 | `; 15 | 16 | export default Styled 17 | -------------------------------------------------------------------------------- /_templates/component/index.tsx.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/components/<%= h.capitalize(name) %>/index.tsx 3 | --- 4 | import Styled from './assets/Styled' 5 | 6 | import Props from '@Interfaces/components/<%= h.capitalize(name) %>/props' 7 | 8 | const <%= h.capitalize(name) %> = ({}: Props): JSX.Element => { 9 | return ( 10 | 11 | Content 12 | 13 | ) 14 | } 15 | 16 | export default <%= h.capitalize(name) %> 17 | -------------------------------------------------------------------------------- /_templates/component/interface.ts.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/interfaces/components/<%= h.capitalize(name) %>/props.tsx 3 | --- 4 | export default interface <%= h.capitalize(name) %>Props { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /_templates/layout/asset/styled.ts.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/layouts/<%= h.capitalize(name) %>/assets/Styled.ts 3 | --- 4 | import styled from 'styled-components'; 5 | import theme from 'styled-theming'; 6 | 7 | const backgroundColor = theme('mode', { 8 | light: '#ddd', 9 | dark: '#222', 10 | }); 11 | 12 | const Styled = styled.div` 13 | background-color: ${backgroundColor}; 14 | `; 15 | 16 | export default Styled 17 | -------------------------------------------------------------------------------- /_templates/layout/index.tsx.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/layouts/<%= h.capitalize(name) %>/index.tsx 3 | --- 4 | import { ThemeProvider } from 'styled-components'; 5 | import { useRecoilState } from 'recoil'; 6 | import Styled from './assets/Styled' 7 | 8 | import Header from '@Components/Header'; 9 | import ThemeAtom from '@State/Theme'; 10 | 11 | import Props from '@Interfaces/layouts/<%= h.capitalize(name) %>/props' 12 | 13 | const <%= h.capitalize(name) %> = ({}: Props): JSX.Element => { 14 | const [theme, setTheme] = useRecoilState(ThemeAtom); 15 | 16 | return ( 17 | 18 | 19 |
20 | {children} 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default <%= h.capitalize(name) %> 27 | -------------------------------------------------------------------------------- /_templates/layout/interface.ts.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/interfaces/layouts/<%= h.capitalize(name) %>/props.tsx 3 | --- 4 | export default interface <%= h.capitalize(name) %>Props { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /_templates/state/index.ts.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: renderer/state/<%= h.capitalize(name) %>.ts 3 | --- 4 | import {atom} from "recoil"; 5 | 6 | const <%= h.capitalize(name) %>Atom = atom({key: '<%= h.capitalize(name) %>State',default:''}) 7 | 8 | export default <%= h.capitalize(name) %>Atom 9 | -------------------------------------------------------------------------------- /electron-builder.yml: -------------------------------------------------------------------------------- 1 | appId: dev.hextechdocs.lcuexplorer 2 | productName: LCU Explorer 3 | copyright: Copyright © 2022 HextechDocs 4 | directories: 5 | output: dist 6 | buildResources: resources 7 | files: 8 | - from: . 9 | filter: 10 | - package.json 11 | - app 12 | publish: null 13 | -------------------------------------------------------------------------------- /main/background.ts: -------------------------------------------------------------------------------- 1 | import { app, ipcMain as ipc } from "electron"; 2 | import serve from "electron-serve"; 3 | import Store from "electron-store"; 4 | import LCUConnector from "lcu-connector"; 5 | import { createWindow } from "./helpers"; 6 | 7 | import "./helpers/ipc"; 8 | 9 | type Credentials = { 10 | address: string; 11 | port: number; 12 | username: string; 13 | password: string; 14 | protocol: string; 15 | }; 16 | 17 | const store = new Store(); 18 | const isProd: boolean = process.env.NODE_ENV === "production"; 19 | 20 | if (isProd) { 21 | serve({ directory: "app" }); 22 | } else { 23 | app.setPath("userData", `${app.getPath("userData")} (development)`); 24 | } 25 | 26 | app.on( 27 | "certificate-error", 28 | (event, _webContents, _url, _error, certificate, callback) => { 29 | if ( 30 | certificate.fingerprint === 31 | "sha256/TQ1pFVrt3Msu+IVgubjrrixp75XCuDFovDbcTcqTJjw=" 32 | ) { 33 | event.preventDefault(); 34 | callback(true); 35 | } else { 36 | callback(false); 37 | } 38 | } 39 | ); 40 | 41 | (async () => { 42 | await app.whenReady(); 43 | 44 | const backgroundColor = (): string => { 45 | if (!store.get("theme")) { 46 | store.set("theme", "dark"); 47 | } 48 | const dark = "#222"; 49 | const light = "#DDD"; 50 | 51 | if (store.get("theme") === "dark") { 52 | return light; 53 | } 54 | return dark; 55 | }; 56 | 57 | const mainWindow = createWindow("main", { 58 | width: 1280, 59 | height: 720, 60 | minWidth: 1280, 61 | minHeight: 720, 62 | title: "LCU Explorer", 63 | frame: false, 64 | backgroundColor: backgroundColor(), 65 | webPreferences: { 66 | nodeIntegration: true, 67 | allowRunningInsecureContent: true, 68 | webSecurity: false, 69 | }, 70 | }); 71 | 72 | (() => { 73 | const feReady = new Promise((resolve) => ipc.on("fe-ready", resolve)); 74 | function sendCredentials(credentials: Credentials) { 75 | console.log( 76 | `BE received credentials update: ${JSON.stringify(credentials)}` 77 | ); 78 | feReady.then(() => { 79 | console.log(`BE sending credentials: ${JSON.stringify(credentials)}`); 80 | mainWindow.webContents.send("credentialspass", credentials); 81 | }); 82 | } 83 | const connector = new LCUConnector(); 84 | connector.on("connect", sendCredentials); 85 | connector.on("disconnect", () => sendCredentials(null)); 86 | connector.start(); 87 | })(); 88 | 89 | ipc.on("process:min", () => { 90 | mainWindow.minimize(); 91 | }); 92 | 93 | ipc.on("process:minmax", () => { 94 | // eslint-disable-next-line @typescript-eslint/no-unused-expressions 95 | mainWindow.maximizable ? mainWindow.maximize() : mainWindow.unmaximize(); 96 | }); 97 | 98 | if (isProd) { 99 | await mainWindow.loadURL("app://./home.html"); 100 | } else { 101 | const port = process.argv[2]; 102 | await mainWindow.loadURL(`http://localhost:${port}/home`); 103 | mainWindow.webContents.openDevTools({ mode: "detach" }); 104 | } 105 | })(); 106 | 107 | app.on("window-all-closed", () => { 108 | app.quit(); 109 | }); 110 | 111 | ipc.on("process:close", () => { 112 | process.exit(0); 113 | }); 114 | -------------------------------------------------------------------------------- /main/helpers/create-window.ts: -------------------------------------------------------------------------------- 1 | import { 2 | screen, 3 | BrowserWindow, 4 | BrowserWindowConstructorOptions, 5 | } from "electron"; 6 | import Store from "electron-store"; 7 | 8 | export default ( 9 | windowName: string, 10 | options: BrowserWindowConstructorOptions 11 | ): BrowserWindow => { 12 | const key = "window-state"; 13 | const name = `window-state-${windowName}`; 14 | const store = new Store({ name }); 15 | const defaultSize = { 16 | width: options.width, 17 | height: options.height, 18 | }; 19 | let state = {}; 20 | let win; 21 | 22 | const restore = () => store.get(key, defaultSize); 23 | 24 | const getCurrentPosition = () => { 25 | const position = win.getPosition(); 26 | const size = win.getSize(); 27 | return { 28 | x: position[0], 29 | y: position[1], 30 | width: size[0], 31 | height: size[1], 32 | }; 33 | }; 34 | 35 | const windowWithinBounds = (windowState, bounds) => { 36 | return ( 37 | windowState.x >= bounds.x && 38 | windowState.y >= bounds.y && 39 | windowState.x + windowState.width <= bounds.x + bounds.width && 40 | windowState.y + windowState.height <= bounds.y + bounds.height 41 | ); 42 | }; 43 | 44 | const resetToDefaults = () => { 45 | const { bounds } = screen.getPrimaryDisplay(); 46 | return { 47 | ...defaultSize, 48 | x: (bounds.width - defaultSize.width) / 2, 49 | y: (bounds.height - defaultSize.height) / 2, 50 | }; 51 | }; 52 | 53 | const ensureVisibleOnSomeDisplay = (windowState) => { 54 | const visible = screen.getAllDisplays().some((display) => { 55 | return windowWithinBounds(windowState, display.bounds); 56 | }); 57 | if (!visible) { 58 | // Window is partially or fully not visible now. 59 | // Reset it to safe defaults. 60 | return resetToDefaults(); 61 | } 62 | return windowState; 63 | }; 64 | 65 | const saveState = () => { 66 | if (!win.isMinimized() && !win.isMaximized()) { 67 | Object.assign(state, getCurrentPosition()); 68 | } 69 | store.set(key, state); 70 | }; 71 | 72 | state = ensureVisibleOnSomeDisplay(restore()); 73 | 74 | const browserOptions: BrowserWindowConstructorOptions = { 75 | ...options, 76 | ...state, 77 | webPreferences: { 78 | nodeIntegration: true, 79 | contextIsolation: false, 80 | ...options.webPreferences, 81 | }, 82 | }; 83 | win = new BrowserWindow(browserOptions); 84 | 85 | win.on("close", saveState); 86 | 87 | return win; 88 | }; 89 | -------------------------------------------------------------------------------- /main/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import createWindow from "./create-window"; 2 | import ipc from "./ipc"; 3 | 4 | export { createWindow, ipc }; 5 | -------------------------------------------------------------------------------- /main/helpers/ipc.ts: -------------------------------------------------------------------------------- 1 | import { ipcRenderer as ipc } from "electron"; 2 | import logger from "./logger"; 3 | 4 | // ipc.on("close", () => { 5 | // logger.warn("Close event triggered via close button."); 6 | // }); 7 | // 8 | // ipc.on("minmax", () => { 9 | // logger.debug("Window min/max via minmax button."); 10 | // }); 11 | // 12 | // ipc.on("min", () => { 13 | // logger.debug("Window minimized via button."); 14 | // }); 15 | 16 | export default {}; 17 | -------------------------------------------------------------------------------- /main/helpers/logger.ts: -------------------------------------------------------------------------------- 1 | import tracer from "tracer"; 2 | 3 | const logger = tracer.colorConsole(); 4 | 5 | export default logger; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "lcu-explorer", 4 | "description": "Interactive lcu documentation", 5 | "version": "1.2.0", 6 | "author": { 7 | "name": "hextechdocs", 8 | "url": "https://hextechdocs.dev", 9 | "email": "team@hextechdocs.dev" 10 | }, 11 | "contributors": [ 12 | { 13 | "name": "Ray", 14 | "url": "https://hiray.me", 15 | "email": "dev@hiray.me" 16 | }, 17 | { 18 | "name": "Mingwei Samuel", 19 | "url": "https://www.mingweisamuel.com", 20 | "email": "mingwei.samuel@gmail.com" 21 | } 22 | ], 23 | "main": "app/background.js", 24 | "scripts": { 25 | "dev": "nextron", 26 | "build": "nextron build", 27 | "postinstall": "electron-builder install-app-deps", 28 | "format": "prettier --write {main,renderer}/**/*.ts{,x}", 29 | "lint": "tsc --noEmit && eslint {main,renderer}/**/*.ts{,x}", 30 | "update:deps": "npx npm-check-updates -u && yarn", 31 | "create:component": "npx hygen component new", 32 | "create:layout": "npx hygen layout new", 33 | "create:state": "npx hygen state new" 34 | }, 35 | "dependencies": { 36 | "@types/swagger-ui": "^3.52.0", 37 | "axios": "^0.22.0", 38 | "css-reset-and-normalize": "^2.3.5", 39 | "electron-serve": "^1.1.0", 40 | "electron-store": "^8.0.0", 41 | "lcu-connector": "^2.1.3", 42 | "lodash": "^4.17.21", 43 | "recoil": "^0.4.0", 44 | "sass": "^1.37.5", 45 | "styled-components": "^5.3.0", 46 | "styled-theming": "^2.2.0", 47 | "swagger-ui": "^3.52.3", 48 | "tracer": "^1.1.5" 49 | }, 50 | "devDependencies": { 51 | "@types/lodash": "^4", 52 | "@types/node": "^16.6.1", 53 | "@types/react": "^17.0.17", 54 | "@types/styled-components": "^5.1.12", 55 | "@types/styled-theming": "^2.2.5", 56 | "@typescript-eslint/eslint-plugin": "^4.29.1", 57 | "@typescript-eslint/parser": "^4.29.1", 58 | "electron": "^13.1.9", 59 | "electron-builder": "^22.11.7", 60 | "eslint": "7.32.0", 61 | "eslint-config-airbnb": "18.2.1", 62 | "eslint-config-airbnb-typescript": "^12.3.1", 63 | "eslint-config-prettier": "^8.3.0", 64 | "eslint-plugin-import": "2.24.0", 65 | "eslint-plugin-jsx-a11y": "6.4.1", 66 | "eslint-plugin-prettier": "^3.4.0", 67 | "eslint-plugin-react": "7.24.0", 68 | "eslint-plugin-react-hooks": "4.2.0", 69 | "next": "^11.1.1", 70 | "nextron": "^7.0.0", 71 | "prettier": "^2.3.2", 72 | "react": "^17.0.2", 73 | "react-dom": "^17.0.2", 74 | "typescript": "^4.3.5" 75 | }, 76 | "packageManager": "yarn@3.0.2" 77 | } 78 | -------------------------------------------------------------------------------- /renderer/_document.tsx: -------------------------------------------------------------------------------- 1 | import { RenderPage } from "next/dist/shared/lib/utils"; 2 | import React from "react"; 3 | import Document, { 4 | DocumentContext, 5 | Head, 6 | Html, 7 | Main, 8 | NextScript, 9 | } from "next/document"; 10 | import { ServerStyleSheet } from "styled-components"; 11 | 12 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 13 | // @ts-ignore 14 | export default class MyDocument extends Document { 15 | static async getInitialProps( 16 | ctx: DocumentContext 17 | ): Promise< 18 | RenderPage | { styles: JSX.Element; html: string; head?: JSX.Element[] } 19 | > { 20 | const sheet = new ServerStyleSheet(); 21 | const originalRenderPage = ctx.renderPage; 22 | 23 | try { 24 | ctx.renderPage = () => 25 | originalRenderPage({ 26 | enhanceApp: (App) => (props) => 27 | sheet.collectStyles(), 28 | }); 29 | 30 | const initialProps = await Document.getInitialProps(ctx); 31 | return { 32 | ...initialProps, 33 | styles: ( 34 | <> 35 | {initialProps.styles} 36 | {sheet.getStyleElement()} 37 | 38 | ), 39 | }; 40 | } finally { 41 | sheet.seal(); 42 | } 43 | } 44 | 45 | render(): JSX.Element { 46 | return ( 47 | 48 | 49 | Treeline Explorer 50 | 51 | 52 |
53 | 54 | 55 | 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /renderer/components/Titlebar/assets/titlebar.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | const TitlebarStyled = styled.div` 4 | display: flex; 5 | width: 100%; 6 | height: 2rem; 7 | -webkit-app-region: drag; 8 | flex-direction: row; 9 | 10 | .buttons { 11 | margin: 0.3rem; 12 | -webkit-app-region: no-drag; 13 | button { 14 | width: 1.25rem; 15 | height: 1.25rem; 16 | margin: 0 0.2rem; 17 | border-radius: 100%; 18 | -webkit-app-region: no-drag; 19 | transition-duration: 250ms; 20 | &:focus { 21 | border: none; 22 | outline: none; 23 | } 24 | &:hover { 25 | filter: grayscale(0.3); 26 | transition-duration: 250ms; 27 | } 28 | } 29 | 30 | #close { 31 | background-color: crimson; 32 | } 33 | 34 | #minmax { 35 | background-color: darkorange; 36 | } 37 | 38 | #max { 39 | background: mediumspringgreen; 40 | } 41 | } 42 | `; 43 | 44 | export default TitlebarStyled; 45 | -------------------------------------------------------------------------------- /renderer/components/Titlebar/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ipcRenderer as ipc } from "electron"; 3 | 4 | import TitlebarStyled from "./assets/titlebar"; 5 | 6 | const Titlebar = (): JSX.Element => { 7 | const onClose = () => { 8 | ipc.send("process:close"); 9 | }; 10 | 11 | const onMin = () => { 12 | ipc.send("process:min"); 13 | }; 14 | 15 | const onMax = () => { 16 | ipc.send("process:minmax"); 17 | }; 18 | 19 | return ( 20 | 21 |
22 |
26 |
27 | ); 28 | }; 29 | 30 | export default Titlebar; 31 | -------------------------------------------------------------------------------- /renderer/layouts/main/assets/styled.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | const Styled = styled.div``; 4 | 5 | export default Styled; 6 | -------------------------------------------------------------------------------- /renderer/layouts/main/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { ThemeProvider } from "styled-components"; 4 | import { useRecoilState } from "recoil"; 5 | 6 | import Header from "@components/Titlebar"; 7 | import ThemeAtom from "@state/Theme"; 8 | 9 | import Styled from "./assets/styled"; 10 | 11 | interface MainLayoutProps { 12 | children: never; 13 | } 14 | 15 | const MainLayout = ({ children }: MainLayoutProps): JSX.Element => { 16 | const [theme, setTheme] = useRecoilState(ThemeAtom); 17 | 18 | return ( 19 | 20 | 21 |
22 | {children} 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default MainLayout; 29 | -------------------------------------------------------------------------------- /renderer/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | // NOTE: This file should not be edited 6 | // see https://nextjs.org/docs/basic-features/typescript for more information. 7 | -------------------------------------------------------------------------------- /renderer/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpack: (config, { isServer }) => { 3 | 4 | if (!isServer) { 5 | config.target = 'electron-renderer'; 6 | config.node = { 7 | __dirname: true, 8 | } 9 | } 10 | return config; 11 | }, 12 | }; -------------------------------------------------------------------------------- /renderer/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import type { AppProps } from "next/app"; 3 | import { RecoilRoot } from "recoil"; 4 | 5 | import "css-reset-and-normalize/css/button-reset.min.css"; 6 | import "css-reset-and-normalize/css/link-reset.min.css"; 7 | import "css-reset-and-normalize/css/reset-and-normalize.min.css"; 8 | 9 | import "swagger-ui/dist/swagger-ui.css"; 10 | import "../styles/globals.sass"; 11 | 12 | const LCUExplorer = ({ Component, pageProps }: AppProps): JSX.Element => { 13 | return ( 14 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default LCUExplorer; 21 | -------------------------------------------------------------------------------- /renderer/pages/home.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { ipcRenderer } from "electron"; 3 | import Swagger from "swagger-ui"; 4 | import axios, { AxiosResponse } from "axios"; 5 | import { isEmpty } from "lodash"; 6 | 7 | import Titlebar from "@components/Titlebar"; 8 | 9 | type Credentials = { 10 | address?: string; 11 | port?: number; 12 | username?: string; 13 | password?: string; 14 | protocol?: string; 15 | }; 16 | type SwaggerUIPlugged = Swagger & { 17 | updateSpec: (specUpdates: any) => void; 18 | }; 19 | 20 | const BASIC_AUTH = "BasicAuth"; 21 | 22 | const Home: React.FC = () => { 23 | const [swagger, SetSwagger] = useState({}); 24 | const [credentials, SetCredentials] = useState({}); 25 | const [spec, SetSpec] = useState({}); 26 | 27 | // Get spec. 28 | useEffect(() => { 29 | if (!isEmpty(spec)) { 30 | console.log("spec is not empty returning"); 31 | return; 32 | } 33 | console.warn("spec is empty fetching"); 34 | axios 35 | .get("https://www.mingweisamuel.com/lcu-schema/lcu/openapi.json") 36 | .then((res: AxiosResponse) => SetSpec(res.data)); 37 | }, []); 38 | 39 | // Setup credentials listener. 40 | useEffect(() => { 41 | ipcRenderer.on("credentialspass", (_event, newCredentials) => { 42 | console.log(`FE received credentials: ${JSON.stringify(newCredentials)}`); 43 | if (isEmpty(credentials)) { 44 | SetCredentials(newCredentials); 45 | } 46 | }); 47 | ipcRenderer.send("fe-ready"); 48 | }, []); 49 | 50 | // Setup Swagger UI. 51 | useEffect(() => { 52 | const swaggerInst = Swagger({ 53 | syntaxHighlight: false, 54 | dom_id: "#swagger", 55 | spec: { 56 | openapi: "3.0.0", 57 | security: [ 58 | { 59 | [BASIC_AUTH]: [], 60 | }, 61 | ], 62 | components: { 63 | securitySchemes: { 64 | [BASIC_AUTH]: { 65 | type: "http", 66 | scheme: "basic", 67 | }, 68 | }, 69 | }, 70 | servers: [], 71 | }, 72 | operationsSorter: "alpha", 73 | tagsSorter: "alpha", 74 | docExpansion: "none", 75 | defaultModelExpandDepth: 10, 76 | maxDisplayedTags: 100, 77 | tryItOutEnabled: true, 78 | displayRequestDuration: true, 79 | pluginsOptions: { 80 | pluginLoadType: "chain", 81 | }, 82 | filter: "", 83 | deepLinking: false, // @ts-ignore 84 | requestInterceptor: (request: any) => { 85 | request.curlOptions = ["--insecure"]; 86 | return request; 87 | }, 88 | plugins: [ 89 | (system) => ({ 90 | statePlugins: { 91 | spec: { 92 | wrapSelectors: { 93 | allowTryItOutFor: () => () => { 94 | // const jsonSpec = system.getState().toJSON().spec.json; 95 | console.log("rerendering"); 96 | return true; 97 | }, 98 | }, 99 | }, 100 | }, 101 | rootInjects: { 102 | updateSpec: (specUpdates: any) => { 103 | const jsonSpec = system.getState().toJSON().spec.json; 104 | const newJsonSpec = { ...jsonSpec, ...specUpdates }; 105 | // Preserve securitySchemes. 106 | newJsonSpec.components.securitySchemes = 107 | jsonSpec.components.securitySchemes; 108 | return system.specActions.updateJsonSpec(newJsonSpec); 109 | }, 110 | }, 111 | }), 112 | ], 113 | onComplete: () => { 114 | console.log("Swagger UI loading complete."); 115 | if (isEmpty(swagger)) { 116 | console.log("swagger is empty applying instance"); 117 | SetSwagger(swaggerInst); 118 | } else { 119 | console.log("swagger instance is present"); 120 | } 121 | }, 122 | }) as SwaggerUIPlugged; 123 | }, []); 124 | 125 | useEffect(() => { 126 | console.log( 127 | `Updating FE: swagger ${swagger != null}, spec ${ 128 | spec != null 129 | }, credentials ${JSON.stringify(credentials)}.` 130 | ); 131 | 132 | // If Swagger UI not ready, nothing to update. 133 | if (swagger == null) { 134 | return; 135 | } 136 | 137 | // Update credentials/port from connector. 138 | if (credentials != null) { 139 | if (isEmpty(swagger)) { 140 | console.log("swager is empty and credentials arent null"); 141 | return; 142 | } 143 | console.log("updating spec..."); 144 | swagger.updateSpec({ 145 | servers: [ 146 | { 147 | url: `https://127.0.0.1:${credentials.port}`, 148 | description: "default", 149 | }, 150 | ], 151 | }); 152 | swagger.preauthorizeBasic( 153 | BASIC_AUTH, 154 | credentials.username, 155 | credentials.password 156 | ); 157 | } else { 158 | if (isEmpty(swagger)) { 159 | return; 160 | } 161 | console.log("updating spec"); 162 | swagger.updateSpec({ 163 | servers: [], 164 | }); 165 | } 166 | 167 | // Update OpenAPI spec lcu-schema. 168 | if (spec != null) { 169 | console.log("updating spec"); 170 | swagger.updateSpec(spec); 171 | } 172 | }, [swagger, credentials, spec]); 173 | 174 | return ( 175 | <> 176 | 177 |
178 | 179 | ); 180 | }; 181 | 182 | export default Home; 183 | -------------------------------------------------------------------------------- /renderer/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HextechDocs/lcu-explorer/29481970f75da6d0e2c3ee0fe3f1851ef45d39d0/renderer/public/images/logo.png -------------------------------------------------------------------------------- /renderer/styles/globals.sass: -------------------------------------------------------------------------------- 1 | * 2 | color: #aaa!important 3 | html, 4 | body 5 | padding: 0 6 | margin: 0 7 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif 8 | background: #222 9 | color: white 10 | 11 | .scheme-container, .information-container, .errors-wrapper 12 | display: none 13 | 14 | .opblock-tag, div 15 | color: #aaa!important 16 | background: #222!important 17 | 18 | .btn 19 | display: flex 20 | justify-content: center 21 | align-items: center 22 | 23 | /* width */ 24 | ::-webkit-scrollbar 25 | width: 10px 26 | 27 | 28 | /* Track */ 29 | ::-webkit-scrollbar-track 30 | background: transparent 31 | margin-top: 2rem 32 | 33 | 34 | /* Handle */ 35 | ::-webkit-scrollbar-thumb 36 | background: #888 37 | 38 | 39 | /* Handle on hover */ 40 | ::-webkit-scrollbar-thumb:hover 41 | background: #555 42 | -------------------------------------------------------------------------------- /renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "next-env.d.ts", 5 | "**/*.ts", 6 | "**/*.tsx" 7 | ], 8 | "exclude": [ 9 | "node_modules" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HextechDocs/lcu-explorer/29481970f75da6d0e2c3ee0fe3f1851ef45d39d0/resources/icon.icns -------------------------------------------------------------------------------- /resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HextechDocs/lcu-explorer/29481970f75da6d0e2c3ee0fe3f1851ef45d39d0/resources/icon.ico -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "jsx": "preserve", 7 | "lib": [ 8 | "dom", 9 | "dom.iterable", 10 | "esnext" 11 | ], 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "strict": false, 15 | "forceConsistentCasingInFileNames": true, 16 | "allowSyntheticDefaultImports": true, 17 | "noEmit": true, 18 | "esModuleInterop": true, 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "baseUrl": "./", 22 | "paths": { 23 | "@pages/*": ["renderer/pages/*"], 24 | "@public/*": ["renderer/public/*"], 25 | "@components/*": ["renderer/components/*"], 26 | "@layouts/*": ["renderer/layouts/*"], 27 | "@state/*": ["renderer/state/*"], 28 | "@styles/*": ["renderer/styles/*"], 29 | "@renderer": ["renderer/*"], 30 | "@helpers/*": ["main/helpers/*"], 31 | "@main/*": ["main/*"] 32 | } 33 | }, 34 | "exclude": [ 35 | "node_modules", 36 | "renderer/next.config.js", 37 | "app", 38 | "dist" 39 | ] 40 | } 41 | --------------------------------------------------------------------------------