diff --git a/.config/example.yml b/.config/example.yml index 29f4a6229..900ac0905 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -145,6 +145,12 @@ id: 'aid' # '127.0.0.1/32' #] +# TWA +#twa: +# nameSpace: android_app +# packageName: tld.domain.twa +# sha256CertFingerprints: ['AB:CD:EF'] + # Upload or download file size limits (bytes) #maxFileSize: 262144000 diff --git a/.dockerignore b/.dockerignore index 09d3015be..0b22aa24e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,9 +14,3 @@ redis/ files/ misskey-assets/ .pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions diff --git a/.gitignore b/.gitignore index 7388e9f2e..a4f945138 100644 --- a/.gitignore +++ b/.gitignore @@ -12,18 +12,6 @@ packages/backend/.idea/vcs.xml node_modules report.*.json -# Yarn -yarn.lock -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -packages/client/.yarn/cache -packages/backend/.yarn/cache -packages/sw/.yarn/cache - # Cypress cypress/screenshots cypress/videos @@ -65,3 +53,7 @@ packages/backend/assets/instance.css *.blend3 *.blend4 *.blend5 + +# old yarn +.yarn +yarn* diff --git a/.vim/coc-settings.json b/.vim/coc-settings.json new file mode 100644 index 000000000..62b7b934b --- /dev/null +++ b/.vim/coc-settings.json @@ -0,0 +1,4 @@ +{ + "eslint.packageManager": "pnpm", + "workspace.workspaceFolderCheckCwd": false +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 42264548e..785d6e13e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,9 +1,11 @@ { - "recommendations": [ - "editorconfig.editorconfig", - "eg2.vscode-npm-script", - "dbaeumer.vscode-eslint", - "Vue.volar", - "Vue.vscode-typescript-vue-plugin" - ] + "recommendations": [ + "editorconfig.editorconfig", + "eg2.vscode-npm-script", + "rome.rome", + "Vue.volar", + "Vue.vscode-typescript-vue-plugin", + "arcanis.vscode-zipfs", + "Orta.vscode-twoslash-queries" + ] } diff --git a/.woodpecker/commit.yml b/.woodpecker/commit.yml new file mode 100644 index 000000000..386484ce2 --- /dev/null +++ b/.woodpecker/commit.yml @@ -0,0 +1,21 @@ +pipeline: + testCommit: + image: node:latest + commands: + - cp .config/ci.yml .config/default.yml + - corepack enable + - corepack prepare pnpm@latest --activate + - pnpm i --frozen-lockfile + - pnpm run build + - pnpm run migrate + +services: + database: + image: postgres:15 + environment: + - POSTGRES_PASSWORD=test + redis: + image: redis + +branches: + include: [ main, develop, feature/* ] diff --git a/.woodpecker/commitBuild.yml b/.woodpecker/commitBuild.yml deleted file mode 100644 index 407672a46..000000000 --- a/.woodpecker/commitBuild.yml +++ /dev/null @@ -1,17 +0,0 @@ -pipeline: - build: - image: node:${NODE_VERSION} - commands: - - corepack enable - - yarn install - - yarn build - environment: - - YARN_ENABLE_IMMUTABLE_INSTALLS=false - -matrix: - NODE_VERSION: - - 18.12.1 - - 19.2.0 - -branches: - include: [ main, develop, feature/* ] diff --git a/.woodpecker/commitDatabase.yml b/.woodpecker/commitDatabase.yml deleted file mode 100644 index cbffa5d8a..000000000 --- a/.woodpecker/commitDatabase.yml +++ /dev/null @@ -1,28 +0,0 @@ -pipeline: - migrate: - image: node:19.2.0 - commands: - - cp .config/ci.yml .config/default.yml - - corepack enable - - yarn set version berry - - yarn install - - yarn build - - yarn migrate - environment: - - YARN_ENABLE_IMMUTABLE_INSTALLS=false - -services: - database: - image: postgres:${DATABASE} - environment: - - POSTGRES_PASSWORD=test - redis: - image: redis - -matrix: - DATABASE: - - 12 - - latest - -branches: - include: [ main, develop, feature/* ] diff --git a/.woodpecker/dockerHubTag.yml b/.woodpecker/dockerHubTag.yml index 5543ae234..4294e1a58 100644 --- a/.woodpecker/dockerHubTag.yml +++ b/.woodpecker/dockerHubTag.yml @@ -16,3 +16,6 @@ pipeline: # Push new version when version tag is created event: tag tag: v* + +depends_on: + - prSecurityCheck diff --git a/.woodpecker/commitDocker.yml b/.woodpecker/testDocker.yml similarity index 100% rename from .woodpecker/commitDocker.yml rename to .woodpecker/testDocker.yml diff --git a/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs b/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs deleted file mode 100644 index 8d3e2a39b..000000000 --- a/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +++ /dev/null @@ -1,546 +0,0 @@ -/* eslint-disable */ -//prettier-ignore -module.exports = { -name: "@yarnpkg/plugin-interactive-tools", -factory: function (require) { -var plugin=(()=>{var $P=Object.create,Py=Object.defineProperty,eI=Object.defineProperties,tI=Object.getOwnPropertyDescriptor,nI=Object.getOwnPropertyDescriptors,rI=Object.getOwnPropertyNames,L_=Object.getOwnPropertySymbols,iI=Object.getPrototypeOf,rD=Object.prototype.hasOwnProperty,sS=Object.prototype.propertyIsEnumerable;var aS=(i,o,a)=>o in i?Py(i,o,{enumerable:!0,configurable:!0,writable:!0,value:a}):i[o]=a,qt=(i,o)=>{for(var a in o||(o={}))rD.call(o,a)&&aS(i,a,o[a]);if(L_)for(var a of L_(o))sS.call(o,a)&&aS(i,a,o[a]);return i},Zr=(i,o)=>eI(i,nI(o)),uI=i=>Py(i,"__esModule",{value:!0});var wl=(i,o)=>{var a={};for(var c in i)rD.call(i,c)&&o.indexOf(c)<0&&(a[c]=i[c]);if(i!=null&&L_)for(var c of L_(i))o.indexOf(c)<0&&sS.call(i,c)&&(a[c]=i[c]);return a};var Ke=(i,o)=>()=>(o||i((o={exports:{}}).exports,o),o.exports),oI=(i,o)=>{for(var a in o)Py(i,a,{get:o[a],enumerable:!0})},lI=(i,o,a)=>{if(o&&typeof o=="object"||typeof o=="function")for(let c of rI(o))!rD.call(i,c)&&c!=="default"&&Py(i,c,{get:()=>o[c],enumerable:!(a=tI(o,c))||a.enumerable});return i},ou=i=>lI(uI(Py(i!=null?$P(iI(i)):{},"default",i&&i.__esModule&&"default"in i?{get:()=>i.default,enumerable:!0}:{value:i,enumerable:!0})),i);var Iy=Ke((mW,fS)=>{"use strict";var cS=Object.getOwnPropertySymbols,sI=Object.prototype.hasOwnProperty,aI=Object.prototype.propertyIsEnumerable;function fI(i){if(i==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(i)}function cI(){try{if(!Object.assign)return!1;var i=new String("abc");if(i[5]="de",Object.getOwnPropertyNames(i)[0]==="5")return!1;for(var o={},a=0;a<10;a++)o["_"+String.fromCharCode(a)]=a;var c=Object.getOwnPropertyNames(o).map(function(t){return o[t]});if(c.join("")!=="0123456789")return!1;var _={};return"abcdefghijklmnopqrst".split("").forEach(function(t){_[t]=t}),Object.keys(Object.assign({},_)).join("")==="abcdefghijklmnopqrst"}catch(t){return!1}}fS.exports=cI()?Object.assign:function(i,o){for(var a,c=fI(i),_,t=1;t{"use strict";var iD=Iy(),$f=typeof Symbol=="function"&&Symbol.for,by=$f?Symbol.for("react.element"):60103,dI=$f?Symbol.for("react.portal"):60106,pI=$f?Symbol.for("react.fragment"):60107,hI=$f?Symbol.for("react.strict_mode"):60108,vI=$f?Symbol.for("react.profiler"):60114,mI=$f?Symbol.for("react.provider"):60109,yI=$f?Symbol.for("react.context"):60110,gI=$f?Symbol.for("react.forward_ref"):60112,_I=$f?Symbol.for("react.suspense"):60113,EI=$f?Symbol.for("react.memo"):60115,DI=$f?Symbol.for("react.lazy"):60116,dS=typeof Symbol=="function"&&Symbol.iterator;function By(i){for(var o="https://reactjs.org/docs/error-decoder.html?invariant="+i,a=1;aN_.length&&N_.push(i)}function aD(i,o,a,c){var _=typeof i;(_==="undefined"||_==="boolean")&&(i=null);var t=!1;if(i===null)t=!0;else switch(_){case"string":case"number":t=!0;break;case"object":switch(i.$$typeof){case by:case dI:t=!0}}if(t)return a(c,i,o===""?"."+fD(i,0):o),1;if(t=0,o=o===""?".":o+":",Array.isArray(i))for(var M=0;M{"use strict";var RI="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";TS.exports=RI});var hD=Ke((_W,xS)=>{"use strict";var pD=function(){};process.env.NODE_ENV!=="production"&&(RS=CS(),F_={},AS=Function.call.bind(Object.prototype.hasOwnProperty),pD=function(i){var o="Warning: "+i;typeof console!="undefined"&&console.error(o);try{throw new Error(o)}catch(a){}});var RS,F_,AS;function OS(i,o,a,c,_){if(process.env.NODE_ENV!=="production"){for(var t in i)if(AS(i,t)){var M;try{if(typeof i[t]!="function"){var N=Error((c||"React class")+": "+a+" type `"+t+"` is invalid; it must be a function, usually from the `prop-types` package, but received `"+typeof i[t]+"`.");throw N.name="Invariant Violation",N}M=i[t](o,t,c,a,null,RS)}catch(T){M=T}if(M&&!(M instanceof Error)&&pD((c||"React class")+": type specification of "+a+" `"+t+"` is invalid; the type checker function must return `null` or an `Error` but returned a "+typeof M+". You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument)."),M instanceof Error&&!(M.message in F_)){F_[M.message]=!0;var O=_?_():"";pD("Failed "+a+" type: "+M.message+(O!=null?O:""))}}}}OS.resetWarningCache=function(){process.env.NODE_ENV!=="production"&&(F_={})};xS.exports=OS});var MS=Ke(Eu=>{"use strict";process.env.NODE_ENV!=="production"&&function(){"use strict";var i=Iy(),o=hD(),a="16.13.1",c=typeof Symbol=="function"&&Symbol.for,_=c?Symbol.for("react.element"):60103,t=c?Symbol.for("react.portal"):60106,M=c?Symbol.for("react.fragment"):60107,N=c?Symbol.for("react.strict_mode"):60108,O=c?Symbol.for("react.profiler"):60114,T=c?Symbol.for("react.provider"):60109,B=c?Symbol.for("react.context"):60110,H=c?Symbol.for("react.concurrent_mode"):60111,q=c?Symbol.for("react.forward_ref"):60112,ne=c?Symbol.for("react.suspense"):60113,m=c?Symbol.for("react.suspense_list"):60120,pe=c?Symbol.for("react.memo"):60115,ge=c?Symbol.for("react.lazy"):60116,ve=c?Symbol.for("react.block"):60121,ue=c?Symbol.for("react.fundamental"):60117,_e=c?Symbol.for("react.responder"):60118,ce=c?Symbol.for("react.scope"):60119,me=typeof Symbol=="function"&&Symbol.iterator,re="@@iterator";function we(Q){if(Q===null||typeof Q!="object")return null;var Se=me&&Q[me]||Q[re];return typeof Se=="function"?Se:null}var Ie={current:null},je={suspense:null},ct={current:null},pt=/^(.*)[\\\/]/;function Xe(Q,Se,Ne){var Le="";if(Se){var ht=Se.fileName,Yn=ht.replace(pt,"");if(/^index\./.test(Yn)){var Cn=ht.match(pt);if(Cn){var cr=Cn[1];if(cr){var Si=cr.replace(pt,"");Yn=Si+"/"+Yn}}}Le=" (at "+Yn+":"+Se.lineNumber+")"}else Ne&&(Le=" (created by "+Ne+")");return` - in `+(Q||"Unknown")+Le}var tt=1;function He(Q){return Q._status===tt?Q._result:null}function kt(Q,Se,Ne){var Le=Se.displayName||Se.name||"";return Q.displayName||(Le!==""?Ne+"("+Le+")":Ne)}function zt(Q){if(Q==null)return null;if(typeof Q.tag=="number"&&dt("Received an unexpected object in getComponentName(). This is likely a bug in React. Please file an issue."),typeof Q=="function")return Q.displayName||Q.name||null;if(typeof Q=="string")return Q;switch(Q){case M:return"Fragment";case t:return"Portal";case O:return"Profiler";case N:return"StrictMode";case ne:return"Suspense";case m:return"SuspenseList"}if(typeof Q=="object")switch(Q.$$typeof){case B:return"Context.Consumer";case T:return"Context.Provider";case q:return kt(Q,Q.render,"ForwardRef");case pe:return zt(Q.type);case ve:return zt(Q.render);case ge:{var Se=Q,Ne=He(Se);if(Ne)return zt(Ne);break}}return null}var nt={},X=null;function fe(Q){X=Q}nt.getCurrentStack=null,nt.getStackAddendum=function(){var Q="";if(X){var Se=zt(X.type),Ne=X._owner;Q+=Xe(Se,X._source,Ne&&zt(Ne.type))}var Le=nt.getCurrentStack;return Le&&(Q+=Le()||""),Q};var xe={current:!1},le={ReactCurrentDispatcher:Ie,ReactCurrentBatchConfig:je,ReactCurrentOwner:ct,IsSomeRendererActing:xe,assign:i};i(le,{ReactDebugCurrentFrame:nt,ReactComponentTreeHook:{}});function qe(Q){{for(var Se=arguments.length,Ne=new Array(Se>1?Se-1:0),Le=1;Le1?Se-1:0),Le=1;Le0&&typeof Ne[Ne.length-1]=="string"&&Ne[Ne.length-1].indexOf(` - in`)===0;if(!Le){var ht=le.ReactDebugCurrentFrame,Yn=ht.getStackAddendum();Yn!==""&&(Se+="%s",Ne=Ne.concat([Yn]))}var Cn=Ne.map(function(Mu){return""+Mu});Cn.unshift("Warning: "+Se),Function.prototype.apply.call(console[Q],console,Cn);try{var cr=0,Si="Warning: "+Se.replace(/%s/g,function(){return Ne[cr++]});throw new Error(Si)}catch(Mu){}}}var nn={};function an(Q,Se){{var Ne=Q.constructor,Le=Ne&&(Ne.displayName||Ne.name)||"ReactClass",ht=Le+"."+Se;if(nn[ht])return;dt("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",Se,Le),nn[ht]=!0}}var Mn={isMounted:function(Q){return!1},enqueueForceUpdate:function(Q,Se,Ne){an(Q,"forceUpdate")},enqueueReplaceState:function(Q,Se,Ne,Le){an(Q,"replaceState")},enqueueSetState:function(Q,Se,Ne,Le){an(Q,"setState")}},lr={};Object.freeze(lr);function ln(Q,Se,Ne){this.props=Q,this.context=Se,this.refs=lr,this.updater=Ne||Mn}ln.prototype.isReactComponent={},ln.prototype.setState=function(Q,Se){if(!(typeof Q=="object"||typeof Q=="function"||Q==null))throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,Q,Se,"setState")},ln.prototype.forceUpdate=function(Q){this.updater.enqueueForceUpdate(this,Q,"forceUpdate")};{var Gt={isMounted:["isMounted","Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks."],replaceState:["replaceState","Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236)."]},Er=function(Q,Se){Object.defineProperty(ln.prototype,Q,{get:function(){qe("%s(...) is deprecated in plain JavaScript React classes. %s",Se[0],Se[1])}})};for(var w in Gt)Gt.hasOwnProperty(w)&&Er(w,Gt[w])}function jt(){}jt.prototype=ln.prototype;function Xn(Q,Se,Ne){this.props=Q,this.context=Se,this.refs=lr,this.updater=Ne||Mn}var vr=Xn.prototype=new jt;vr.constructor=Xn,i(vr,ln.prototype),vr.isPureReactComponent=!0;function jr(){var Q={current:null};return Object.seal(Q),Q}var fr=Object.prototype.hasOwnProperty,zr={key:!0,ref:!0,__self:!0,__source:!0},Qt,wu,po;po={};function A0(Q){if(fr.call(Q,"ref")){var Se=Object.getOwnPropertyDescriptor(Q,"ref").get;if(Se&&Se.isReactWarning)return!1}return Q.ref!==void 0}function J0(Q){if(fr.call(Q,"key")){var Se=Object.getOwnPropertyDescriptor(Q,"key").get;if(Se&&Se.isReactWarning)return!1}return Q.key!==void 0}function Ps(Q,Se){var Ne=function(){Qt||(Qt=!0,dt("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://fb.me/react-special-props)",Se))};Ne.isReactWarning=!0,Object.defineProperty(Q,"key",{get:Ne,configurable:!0})}function Z0(Q,Se){var Ne=function(){wu||(wu=!0,dt("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://fb.me/react-special-props)",Se))};Ne.isReactWarning=!0,Object.defineProperty(Q,"ref",{get:Ne,configurable:!0})}function $0(Q){if(typeof Q.ref=="string"&&ct.current&&Q.__self&&ct.current.stateNode!==Q.__self){var Se=zt(ct.current.type);po[Se]||(dt('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://fb.me/react-strict-mode-string-ref',zt(ct.current.type),Q.ref),po[Se]=!0)}}var Wt=function(Q,Se,Ne,Le,ht,Yn,Cn){var cr={$$typeof:_,type:Q,key:Se,ref:Ne,props:Cn,_owner:Yn};return cr._store={},Object.defineProperty(cr._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:!1}),Object.defineProperty(cr,"_self",{configurable:!1,enumerable:!1,writable:!1,value:Le}),Object.defineProperty(cr,"_source",{configurable:!1,enumerable:!1,writable:!1,value:ht}),Object.freeze&&(Object.freeze(cr.props),Object.freeze(cr)),cr};function xi(Q,Se,Ne){var Le,ht={},Yn=null,Cn=null,cr=null,Si=null;if(Se!=null){A0(Se)&&(Cn=Se.ref,$0(Se)),J0(Se)&&(Yn=""+Se.key),cr=Se.__self===void 0?null:Se.__self,Si=Se.__source===void 0?null:Se.__source;for(Le in Se)fr.call(Se,Le)&&!zr.hasOwnProperty(Le)&&(ht[Le]=Se[Le])}var Mu=arguments.length-2;if(Mu===1)ht.children=Ne;else if(Mu>1){for(var zu=Array(Mu),Hu=0;Hu1){for(var Su=Array(Hu),Ti=0;Ti is not supported and will be removed in a future major release. Did you mean to render instead?")),Ne.Provider},set:function(Cn){Ne.Provider=Cn}},_currentValue:{get:function(){return Ne._currentValue},set:function(Cn){Ne._currentValue=Cn}},_currentValue2:{get:function(){return Ne._currentValue2},set:function(Cn){Ne._currentValue2=Cn}},_threadCount:{get:function(){return Ne._threadCount},set:function(Cn){Ne._threadCount=Cn}},Consumer:{get:function(){return Le||(Le=!0,dt("Rendering is not supported and will be removed in a future major release. Did you mean to render instead?")),Ne.Consumer}}}),Ne.Consumer=Yn}return Ne._currentRenderer=null,Ne._currentRenderer2=null,Ne}function Vt(Q){var Se={$$typeof:ge,_ctor:Q,_status:-1,_result:null};{var Ne,Le;Object.defineProperties(Se,{defaultProps:{configurable:!0,get:function(){return Ne},set:function(ht){dt("React.lazy(...): It is not supported to assign `defaultProps` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),Ne=ht,Object.defineProperty(Se,"defaultProps",{enumerable:!0})}},propTypes:{configurable:!0,get:function(){return Le},set:function(ht){dt("React.lazy(...): It is not supported to assign `propTypes` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),Le=ht,Object.defineProperty(Se,"propTypes",{enumerable:!0})}}})}return Se}function Au(Q){return Q!=null&&Q.$$typeof===pe?dt("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof Q!="function"?dt("forwardRef requires a render function but was given %s.",Q===null?"null":typeof Q):Q.length!==0&&Q.length!==2&&dt("forwardRef render functions accept exactly two parameters: props and ref. %s",Q.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),Q!=null&&(Q.defaultProps!=null||Q.propTypes!=null)&&dt("forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?"),{$$typeof:q,render:Q}}function eu(Q){return typeof Q=="string"||typeof Q=="function"||Q===M||Q===H||Q===O||Q===N||Q===ne||Q===m||typeof Q=="object"&&Q!==null&&(Q.$$typeof===ge||Q.$$typeof===pe||Q.$$typeof===T||Q.$$typeof===B||Q.$$typeof===q||Q.$$typeof===ue||Q.$$typeof===_e||Q.$$typeof===ce||Q.$$typeof===ve)}function Jo(Q,Se){return eu(Q)||dt("memo: The first argument must be a component. Instead received: %s",Q===null?"null":typeof Q),{$$typeof:pe,type:Q,compare:Se===void 0?null:Se}}function Yi(){var Q=Ie.current;if(Q===null)throw Error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: -1. You might have mismatching versions of React and the renderer (such as React DOM) -2. You might be breaking the Rules of Hooks -3. You might have more than one copy of React in the same app -See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.`);return Q}function Ql(Q,Se){var Ne=Yi();if(Se!==void 0&&dt("useContext() second argument is reserved for future use in React. Passing it is not supported. You passed: %s.%s",Se,typeof Se=="number"&&Array.isArray(arguments[2])?` - -Did you call array.map(useContext)? Calling Hooks inside a loop is not supported. Learn more at https://fb.me/rules-of-hooks`:""),Q._context!==void 0){var Le=Q._context;Le.Consumer===Q?dt("Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be removed in a future major release. Did you mean to call useContext(Context) instead?"):Le.Provider===Q&&dt("Calling useContext(Context.Provider) is not supported. Did you mean to call useContext(Context) instead?")}return Ne.useContext(Q,Se)}function k0(Q){var Se=Yi();return Se.useState(Q)}function ai(Q,Se,Ne){var Le=Yi();return Le.useReducer(Q,Se,Ne)}function f0(Q){var Se=Yi();return Se.useRef(Q)}function Jl(Q,Se){var Ne=Yi();return Ne.useEffect(Q,Se)}function L0(Q,Se){var Ne=Yi();return Ne.useLayoutEffect(Q,Se)}function bs(Q,Se){var Ne=Yi();return Ne.useCallback(Q,Se)}function $n(Q,Se){var Ne=Yi();return Ne.useMemo(Q,Se)}function tl(Q,Se,Ne){var Le=Yi();return Le.useImperativeHandle(Q,Se,Ne)}function c0(Q,Se){{var Ne=Yi();return Ne.useDebugValue(Q,Se)}}var bo;bo=!1;function Sl(){if(ct.current){var Q=zt(ct.current.type);if(Q)return` - -Check the render method of \``+Q+"`."}return""}function N0(Q){if(Q!==void 0){var Se=Q.fileName.replace(/^.*[\\\/]/,""),Ne=Q.lineNumber;return` - -Check your code at `+Se+":"+Ne+"."}return""}function wt(Q){return Q!=null?N0(Q.__source):""}var bt={};function Hn(Q){var Se=Sl();if(!Se){var Ne=typeof Q=="string"?Q:Q.displayName||Q.name;Ne&&(Se=` - -Check the top-level render call using <`+Ne+">.")}return Se}function qr(Q,Se){if(!(!Q._store||Q._store.validated||Q.key!=null)){Q._store.validated=!0;var Ne=Hn(Se);if(!bt[Ne]){bt[Ne]=!0;var Le="";Q&&Q._owner&&Q._owner!==ct.current&&(Le=" It was passed a child from "+zt(Q._owner.type)+"."),fe(Q),dt('Each child in a list should have a unique "key" prop.%s%s See https://fb.me/react-warning-keys for more information.',Ne,Le),fe(null)}}}function Ki(Q,Se){if(typeof Q=="object"){if(Array.isArray(Q))for(var Ne=0;Ne",ht=" Did you accidentally export a JSX literal instead of a component?"):Cn=typeof Q,dt("React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",Cn,ht)}var cr=xi.apply(this,arguments);if(cr==null)return cr;if(Le)for(var Si=2;Si{"use strict";process.env.NODE_ENV==="production"?vD.exports=SS():vD.exports=MS()});var kS=Ke((Wv,Uy)=>{(function(){var i,o="4.17.21",a=200,c="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",_="Expected a function",t="Invalid `variable` option passed into `_.template`",M="__lodash_hash_undefined__",N=500,O="__lodash_placeholder__",T=1,B=2,H=4,q=1,ne=2,m=1,pe=2,ge=4,ve=8,ue=16,_e=32,ce=64,me=128,re=256,we=512,Ie=30,je="...",ct=800,pt=16,Xe=1,tt=2,He=3,kt=1/0,zt=9007199254740991,nt=17976931348623157e292,X=0/0,fe=4294967295,xe=fe-1,le=fe>>>1,qe=[["ary",me],["bind",m],["bindKey",pe],["curry",ve],["curryRight",ue],["flip",we],["partial",_e],["partialRight",ce],["rearg",re]],dt="[object Arguments]",Rt="[object Array]",nn="[object AsyncFunction]",an="[object Boolean]",Mn="[object Date]",lr="[object DOMException]",ln="[object Error]",Gt="[object Function]",Er="[object GeneratorFunction]",w="[object Map]",jt="[object Number]",Xn="[object Null]",vr="[object Object]",jr="[object Promise]",fr="[object Proxy]",zr="[object RegExp]",Qt="[object Set]",wu="[object String]",po="[object Symbol]",A0="[object Undefined]",J0="[object WeakMap]",Ps="[object WeakSet]",Z0="[object ArrayBuffer]",$0="[object DataView]",Wt="[object Float32Array]",xi="[object Float64Array]",su="[object Int8Array]",mi="[object Int16Array]",Dr="[object Int32Array]",el="[object Uint8Array]",Ko="[object Uint8ClampedArray]",Uu="[object Uint16Array]",Xo="[object Uint32Array]",Xr=/\b__p \+= '';/g,O0=/\b(__p \+=) '' \+/g,M0=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Po=/&(?:amp|lt|gt|quot|#39);/g,au=/[&<>"']/g,ki=RegExp(Po.source),Is=RegExp(au.source),Xl=/<%-([\s\S]+?)%>/g,Io=/<%([\s\S]+?)%>/g,ho=/<%=([\s\S]+?)%>/g,Hr=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Ri=/^\w*$/,Qo=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,yi=/[\\^$.*+?()[\]{}|]/g,en=RegExp(yi.source),bn=/^\s+/,Ai=/\s/,gi=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Vt=/\{\n\/\* \[wrapped with (.+)\] \*/,Au=/,? & /,eu=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Jo=/[()=,{}\[\]\/\s]/,Yi=/\\(\\)?/g,Ql=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,k0=/\w*$/,ai=/^[-+]0x[0-9a-f]+$/i,f0=/^0b[01]+$/i,Jl=/^\[object .+?Constructor\]$/,L0=/^0o[0-7]+$/i,bs=/^(?:0|[1-9]\d*)$/,$n=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,tl=/($^)/,c0=/['\n\r\u2028\u2029\\]/g,bo="\\ud800-\\udfff",Sl="\\u0300-\\u036f",N0="\\ufe20-\\ufe2f",wt="\\u20d0-\\u20ff",bt=Sl+N0+wt,Hn="\\u2700-\\u27bf",qr="a-z\\xdf-\\xf6\\xf8-\\xff",Ki="\\xac\\xb1\\xd7\\xf7",Qr="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Ou="\\u2000-\\u206f",vo=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Li="A-Z\\xc0-\\xd6\\xd8-\\xde",mo="\\ufe0e\\ufe0f",vs=Ki+Qr+Ou+vo,Tt="['\u2019]",d0="["+bo+"]",nl="["+vs+"]",Zl="["+bt+"]",ju="\\d+",ms="["+Hn+"]",Bo="["+qr+"]",Q="[^"+bo+vs+ju+Hn+qr+Li+"]",Se="\\ud83c[\\udffb-\\udfff]",Ne="(?:"+Zl+"|"+Se+")",Le="[^"+bo+"]",ht="(?:\\ud83c[\\udde6-\\uddff]){2}",Yn="[\\ud800-\\udbff][\\udc00-\\udfff]",Cn="["+Li+"]",cr="\\u200d",Si="(?:"+Bo+"|"+Q+")",Mu="(?:"+Cn+"|"+Q+")",zu="(?:"+Tt+"(?:d|ll|m|re|s|t|ve))?",Hu="(?:"+Tt+"(?:D|LL|M|RE|S|T|VE))?",Su=Ne+"?",Ti="["+mo+"]?",F0="(?:"+cr+"(?:"+[Le,ht,Yn].join("|")+")"+Ti+Su+")*",ku="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",p0="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",qu=Ti+Su+F0,Ia="(?:"+[ms,ht,Yn].join("|")+")"+qu,yo="(?:"+[Le+Zl+"?",Zl,ht,Yn,d0].join("|")+")",ua=RegExp(Tt,"g"),Zo=RegExp(Zl,"g"),oa=RegExp(Se+"(?="+Se+")|"+yo+qu,"g"),ba=RegExp([Cn+"?"+Bo+"+"+zu+"(?="+[nl,Cn,"$"].join("|")+")",Mu+"+"+Hu+"(?="+[nl,Cn+Si,"$"].join("|")+")",Cn+"?"+Si+"+"+zu,Cn+"+"+Hu,p0,ku,ju,Ia].join("|"),"g"),ys=RegExp("["+cr+bo+bt+mo+"]"),To=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Qn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],fc=-1,fi={};fi[Wt]=fi[xi]=fi[su]=fi[mi]=fi[Dr]=fi[el]=fi[Ko]=fi[Uu]=fi[Xo]=!0,fi[dt]=fi[Rt]=fi[Z0]=fi[an]=fi[$0]=fi[Mn]=fi[ln]=fi[Gt]=fi[w]=fi[jt]=fi[vr]=fi[zr]=fi[Qt]=fi[wu]=fi[J0]=!1;var $r={};$r[dt]=$r[Rt]=$r[Z0]=$r[$0]=$r[an]=$r[Mn]=$r[Wt]=$r[xi]=$r[su]=$r[mi]=$r[Dr]=$r[w]=$r[jt]=$r[vr]=$r[zr]=$r[Qt]=$r[wu]=$r[po]=$r[el]=$r[Ko]=$r[Uu]=$r[Xo]=!0,$r[ln]=$r[Gt]=$r[J0]=!1;var $l={\u00C0:"A",\u00C1:"A",\u00C2:"A",\u00C3:"A",\u00C4:"A",\u00C5:"A",\u00E0:"a",\u00E1:"a",\u00E2:"a",\u00E3:"a",\u00E4:"a",\u00E5:"a",\u00C7:"C",\u00E7:"c",\u00D0:"D",\u00F0:"d",\u00C8:"E",\u00C9:"E",\u00CA:"E",\u00CB:"E",\u00E8:"e",\u00E9:"e",\u00EA:"e",\u00EB:"e",\u00CC:"I",\u00CD:"I",\u00CE:"I",\u00CF:"I",\u00EC:"i",\u00ED:"i",\u00EE:"i",\u00EF:"i",\u00D1:"N",\u00F1:"n",\u00D2:"O",\u00D3:"O",\u00D4:"O",\u00D5:"O",\u00D6:"O",\u00D8:"O",\u00F2:"o",\u00F3:"o",\u00F4:"o",\u00F5:"o",\u00F6:"o",\u00F8:"o",\u00D9:"U",\u00DA:"U",\u00DB:"U",\u00DC:"U",\u00F9:"u",\u00FA:"u",\u00FB:"u",\u00FC:"u",\u00DD:"Y",\u00FD:"y",\u00FF:"y",\u00C6:"Ae",\u00E6:"ae",\u00DE:"Th",\u00FE:"th",\u00DF:"ss",\u0100:"A",\u0102:"A",\u0104:"A",\u0101:"a",\u0103:"a",\u0105:"a",\u0106:"C",\u0108:"C",\u010A:"C",\u010C:"C",\u0107:"c",\u0109:"c",\u010B:"c",\u010D:"c",\u010E:"D",\u0110:"D",\u010F:"d",\u0111:"d",\u0112:"E",\u0114:"E",\u0116:"E",\u0118:"E",\u011A:"E",\u0113:"e",\u0115:"e",\u0117:"e",\u0119:"e",\u011B:"e",\u011C:"G",\u011E:"G",\u0120:"G",\u0122:"G",\u011D:"g",\u011F:"g",\u0121:"g",\u0123:"g",\u0124:"H",\u0126:"H",\u0125:"h",\u0127:"h",\u0128:"I",\u012A:"I",\u012C:"I",\u012E:"I",\u0130:"I",\u0129:"i",\u012B:"i",\u012D:"i",\u012F:"i",\u0131:"i",\u0134:"J",\u0135:"j",\u0136:"K",\u0137:"k",\u0138:"k",\u0139:"L",\u013B:"L",\u013D:"L",\u013F:"L",\u0141:"L",\u013A:"l",\u013C:"l",\u013E:"l",\u0140:"l",\u0142:"l",\u0143:"N",\u0145:"N",\u0147:"N",\u014A:"N",\u0144:"n",\u0146:"n",\u0148:"n",\u014B:"n",\u014C:"O",\u014E:"O",\u0150:"O",\u014D:"o",\u014F:"o",\u0151:"o",\u0154:"R",\u0156:"R",\u0158:"R",\u0155:"r",\u0157:"r",\u0159:"r",\u015A:"S",\u015C:"S",\u015E:"S",\u0160:"S",\u015B:"s",\u015D:"s",\u015F:"s",\u0161:"s",\u0162:"T",\u0164:"T",\u0166:"T",\u0163:"t",\u0165:"t",\u0167:"t",\u0168:"U",\u016A:"U",\u016C:"U",\u016E:"U",\u0170:"U",\u0172:"U",\u0169:"u",\u016B:"u",\u016D:"u",\u016F:"u",\u0171:"u",\u0173:"u",\u0174:"W",\u0175:"w",\u0176:"Y",\u0177:"y",\u0178:"Y",\u0179:"Z",\u017B:"Z",\u017D:"Z",\u017A:"z",\u017C:"z",\u017E:"z",\u0132:"IJ",\u0133:"ij",\u0152:"Oe",\u0153:"oe",\u0149:"'n",\u017F:"s"},la={"&":"&","<":"<",">":">",'"':""","'":"'"},hf={"&":"&","<":"<",">":">",""":'"',"'":"'"},Bs={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Ba=parseFloat,Us=parseInt,go=typeof global=="object"&&global&&global.Object===Object&&global,js=typeof self=="object"&&self&&self.Object===Object&&self,ji=go||js||Function("return this")(),U=typeof Wv=="object"&&Wv&&!Wv.nodeType&&Wv,z=U&&typeof Uy=="object"&&Uy&&!Uy.nodeType&&Uy,G=z&&z.exports===U,$=G&&go.process,Ce=function(){try{var Re=z&&z.require&&z.require("util").types;return Re||$&&$.binding&&$.binding("util")}catch(rt){}}(),Ee=Ce&&Ce.isArrayBuffer,Ae=Ce&&Ce.isDate,Z=Ce&&Ce.isMap,ke=Ce&&Ce.isRegExp,Je=Ce&&Ce.isSet,mt=Ce&&Ce.isTypedArray;function oe(Re,rt,Ye){switch(Ye.length){case 0:return Re.call(rt);case 1:return Re.call(rt,Ye[0]);case 2:return Re.call(rt,Ye[0],Ye[1]);case 3:return Re.call(rt,Ye[0],Ye[1],Ye[2])}return Re.apply(rt,Ye)}function We(Re,rt,Ye,Kt){for(var Xt=-1,pr=Re==null?0:Re.length;++Xt-1}function rn(Re,rt,Ye){for(var Kt=-1,Xt=Re==null?0:Re.length;++Kt-1;);return Ye}function Tl(Re,rt){for(var Ye=Re.length;Ye--&&Dt(rt,Re[Ye],0)>-1;);return Ye}function mf(Re,rt){for(var Ye=Re.length,Kt=0;Ye--;)Re[Ye]===rt&&++Kt;return Kt}var I0=Jn($l),gs=Jn(la);function zs(Re){return"\\"+Bs[Re]}function b0(Re,rt){return Re==null?i:Re[rt]}function B0(Re){return ys.test(Re)}function _s(Re){return To.test(Re)}function Qu(Re){for(var rt,Ye=[];!(rt=Re.next()).done;)Ye.push(rt.value);return Ye}function Tu(Re){var rt=-1,Ye=Array(Re.size);return Re.forEach(function(Kt,Xt){Ye[++rt]=[Xt,Kt]}),Ye}function Ei(Re,rt){return function(Ye){return Re(rt(Ye))}}function xo(Re,rt){for(var Ye=-1,Kt=Re.length,Xt=0,pr=[];++Ye-1}function ca(p,v){var x=this.__data__,P=ns(x,p);return P<0?(++this.size,x.push([p,v])):x[P][1]=v,this}u0.prototype.clear=Ua,u0.prototype.delete=Ef,u0.prototype.get=cc,u0.prototype.has=ws,u0.prototype.set=ca;function jo(p){var v=-1,x=p==null?0:p.length;for(this.clear();++v=v?p:v)),p}function zo(p,v,x,P,W,ee){var he,De=v&T,be=v&B,Et=v&H;if(x&&(he=W?x(p,P,W,ee):x(p)),he!==i)return he;if(!bu(p))return p;var St=tr(p);if(St){if(he=xs(p),!De)return iu(p,he)}else{var At=Iu(p),on=At==Gt||At==Er;if(Zs(p))return mc(p,De);if(At==vr||At==dt||on&&!W){if(he=be||on?{}:Dc(p),!De)return be?rs(p,ol(he,p)):oo(p,Df(he,p))}else{if(!$r[At])return W?p:{};he=Th(p,At,De)}}ee||(ee=new ul);var kn=ee.get(p);if(kn)return kn;ee.set(p,he),bd(p)?p.forEach(function(ar){he.add(zo(ar,v,x,ar,p,ee))}):Dp(p)&&p.forEach(function(ar,ui){he.set(ui,zo(ar,v,x,ui,p,ee))});var rr=Et?be?sr:r1:be?dn:No,br=St?i:rr(p);return it(br||p,function(ar,ui){br&&(ui=ar,ar=p[ui]),Ts(he,ui,zo(ar,v,x,ui,p,ee))}),he}function wf(p){var v=No(p);return function(x){return Wc(x,p,v)}}function Wc(p,v,x){var P=x.length;if(p==null)return!P;for(p=xn(p);P--;){var W=x[P],ee=v[W],he=p[W];if(he===i&&!(W in p)||!ee(he))return!1}return!0}function pc(p,v,x){if(typeof p!="function")throw new ti(_);return Ja(function(){p.apply(i,x)},v)}function Ol(p,v,x,P){var W=-1,ee=sn,he=!0,De=p.length,be=[],Et=v.length;if(!De)return be;x&&(v=Ft(v,_i(x))),P?(ee=rn,he=!1):v.length>=a&&(ee=rl,he=!1,v=new y0(v));e:for(;++WW?0:W+x),P=P===i||P>W?W:Mr(P),P<0&&(P+=W),P=x>P?0:Sp(P);x0&&x(De)?v>1?qi(De,v-1,x,P,W):Dn(W,De):P||(W[W.length]=De)}return W}var g=gc(),y=gc(!0);function R(p,v){return p&&g(p,v,No)}function F(p,v){return p&&y(p,v,No)}function b(p,v){return It(v,function(x){return Ra(p[x])})}function J(p,v){v=Vs(v,p);for(var x=0,P=v.length;p!=null&&xv}function Lt(p,v){return p!=null&&li.call(p,v)}function xr(p,v){return p!=null&&v in xn(p)}function io(p,v,x){return p>=Kn(v,x)&&p=120&&St.length>=120)?new y0(he&&St):i}St=p[0];var At=-1,on=De[0];e:for(;++At-1;)De!==p&&Mo.call(De,be,1),Mo.call(p,be,1);return p}function ad(p,v){for(var x=p?v.length:0,P=x-1;x--;){var W=v[x];if(x==P||W!==ee){var ee=W;D0(W)?Mo.call(p,W,1):A2(p,W)}}return p}function fd(p,v){return p+Ds(Do()*(v-p+1))}function C2(p,v,x,P){for(var W=-1,ee=ni($u((v-p)/(x||1)),0),he=Ye(ee);ee--;)he[P?ee:++W]=p,p+=x;return he}function Yc(p,v){var x="";if(!p||v<1||v>zt)return x;do v%2&&(x+=p),v=Ds(v/2),v&&(p+=p);while(v);return x}function Ir(p,v){return l1(P2(p,v,so),p+"")}function cd(p){return Ha(Nc(p))}function dd(p,v){var x=Nc(p);return Sc(x,ro(v,0,x.length))}function Ya(p,v,x,P){if(!bu(p))return p;v=Vs(v,p);for(var W=-1,ee=v.length,he=ee-1,De=p;De!=null&&++WW?0:W+v),x=x>W?W:x,x<0&&(x+=W),W=v>x?0:x-v>>>0,v>>>=0;for(var ee=Ye(W);++P>>1,he=p[ee];he!==null&&!Bl(he)&&(x?he<=v:he=a){var Et=v?null:fm(p);if(Et)return e0(Et);he=!1,W=rl,be=new y0}else be=v?[]:De;e:for(;++P=P?p:sl(p,v,x)}var Zc=Es||function(p){return ji.clearTimeout(p)};function mc(p,v){if(v)return p.slice();var x=p.length,P=Hi?Hi(x):new p.constructor(x);return p.copy(P),P}function yc(p){var v=new p.constructor(p.byteLength);return new Oo(v).set(new Oo(p)),v}function hd(p,v){var x=v?yc(p.buffer):p.buffer;return new p.constructor(x,p.byteOffset,p.byteLength)}function Eh(p){var v=new p.constructor(p.source,k0.exec(p));return v.lastIndex=p.lastIndex,v}function Cf(p){return Ar?xn(Ar.call(p)):{}}function $c(p,v){var x=v?yc(p.buffer):p.buffer;return new p.constructor(x,p.byteOffset,p.length)}function Dh(p,v){if(p!==v){var x=p!==i,P=p===null,W=p===p,ee=Bl(p),he=v!==i,De=v===null,be=v===v,Et=Bl(v);if(!De&&!Et&&!ee&&p>v||ee&&he&&be&&!De&&!Et||P&&he&&be||!x&&be||!W)return 1;if(!P&&!ee&&!Et&&p=De)return be;var Et=x[P];return be*(Et=="desc"?-1:1)}}return p.index-v.index}function Gs(p,v,x,P){for(var W=-1,ee=p.length,he=x.length,De=-1,be=v.length,Et=ni(ee-he,0),St=Ye(be+Et),At=!P;++De1?x[W-1]:i,he=W>2?x[2]:i;for(ee=p.length>3&&typeof ee=="function"?(W--,ee):i,he&&s0(x[0],x[1],he)&&(ee=W<3?i:ee,W=1),v=xn(v);++P-1?W[ee?v[he]:he]:i}}function t1(p){return cl(function(v){var x=v.length,P=x,W=Vr.prototype.thru;for(p&&v.reverse();P--;){var ee=v[P];if(typeof ee!="function")throw new ti(_);if(W&&!he&&q0(ee)=="wrapper")var he=new Vr([],!0)}for(P=he?P:x;++P1&&di.reverse(),St&&beDe))return!1;var Et=ee.get(p),St=ee.get(v);if(Et&&St)return Et==v&&St==p;var At=-1,on=!0,kn=x&ne?new y0:i;for(ee.set(p,v),ee.set(v,p);++At1?"& ":"")+v[P],v=v.join(x>2?", ":" "),p.replace(gi,`{ -/* [wrapped with `+v+`] */ -`)}function us(p){return tr(p)||pl(p)||!!(v0&&p&&p[v0])}function D0(p,v){var x=typeof p;return v=v==null?zt:v,!!v&&(x=="number"||x!="symbol"&&bs.test(p))&&p>-1&&p%1==0&&p0){if(++v>=ct)return arguments[0]}else v=0;return p.apply(i,arguments)}}function Sc(p,v){var x=-1,P=p.length,W=P-1;for(v=v===i?P:v;++x1?p[v-1]:i;return x=typeof x=="function"?(p.pop(),x):i,Td(p,x)});function zh(p){var v=Y(p);return v.__chain__=!0,v}function Hh(p,v){return v(p),p}function g1(p,v){return v(p)}var $2=cl(function(p){var v=p.length,x=v?p[0]:0,P=this.__wrapped__,W=function(ee){return Wa(ee,p)};return v>1||this.__actions__.length||!(P instanceof at)||!D0(x)?this.thru(W):(P=P.slice(x,+x+(v?1:0)),P.__actions__.push({func:g1,args:[W],thisArg:i}),new Vr(P,this.__chain__).thru(function(ee){return v&&!ee.length&&ee.push(i),ee}))});function qh(){return zh(this)}function ep(){return new Vr(this.value(),this.__chain__)}function Wh(){this.__values__===i&&(this.__values__=fv(this.value()));var p=this.__index__>=this.__values__.length,v=p?i:this.__values__[this.__index__++];return{done:p,value:v}}function _m(){return this}function Em(p){for(var v,x=this;x instanceof ii;){var P=b2(x);P.__index__=0,P.__values__=i,v?W.__wrapped__=P:v=P;var W=P;x=x.__wrapped__}return W.__wrapped__=p,v}function If(){var p=this.__wrapped__;if(p instanceof at){var v=p;return this.__actions__.length&&(v=new at(this)),v=v.reverse(),v.__actions__.push({func:g1,args:[G2],thisArg:i}),new Vr(v,this.__chain__)}return this.thru(G2)}function bf(){return _h(this.__wrapped__,this.__actions__)}var Cd=Ka(function(p,v,x){li.call(p,x)?++p[x]:Gu(p,x,1)});function Dm(p,v,x){var P=tr(p)?Mt:od;return x&&s0(p,v,x)&&(v=i),P(p,Vn(v,3))}function tp(p,v){var x=tr(p)?It:Vc;return x(p,Vn(v,3))}var xd=Ll(z2),np=Ll(a1);function Vh(p,v){return qi(_1(p,v),1)}function rp(p,v){return qi(_1(p,v),kt)}function Gh(p,v,x){return x=x===i?1:Mr(x),qi(_1(p,v),x)}function Yh(p,v){var x=tr(p)?it:Cs;return x(p,Vn(v,3))}function ip(p,v){var x=tr(p)?Ct:pa;return x(p,Vn(v,3))}var wm=Ka(function(p,v,x){li.call(p,x)?p[x].push(v):Gu(p,x,[v])});function Sm(p,v,x,P){p=hl(p)?p:Nc(p),x=x&&!P?Mr(x):0;var W=p.length;return x<0&&(x=ni(W+x,0)),S1(p)?x<=W&&p.indexOf(v,x)>-1:!!W&&Dt(p,v,x)>-1}var Tm=Ir(function(p,v,x){var P=-1,W=typeof v=="function",ee=hl(p)?Ye(p.length):[];return Cs(p,function(he){ee[++P]=W?oe(v,he,x):Ml(he,v,x)}),ee}),Kh=Ka(function(p,v,x){Gu(p,x,v)});function _1(p,v){var x=tr(p)?Ft:S2;return x(p,Vn(v,3))}function Cm(p,v,x,P){return p==null?[]:(tr(v)||(v=v==null?[]:[v]),x=P?i:x,tr(x)||(x=x==null?[]:[x]),g0(p,v,x))}var up=Ka(function(p,v,x){p[x?0:1].push(v)},function(){return[[],[]]});function op(p,v,x){var P=tr(p)?dr:wr,W=arguments.length<3;return P(p,Vn(v,4),x,W,Cs)}function xm(p,v,x){var P=tr(p)?er:wr,W=arguments.length<3;return P(p,Vn(v,4),x,W,pa)}function Rm(p,v){var x=tr(p)?It:Vc;return x(p,Od(Vn(v,3)))}function Xh(p){var v=tr(p)?Ha:cd;return v(p)}function Am(p,v,x){(x?s0(p,v,x):v===i)?v=1:v=Mr(v);var P=tr(p)?qa:dd;return P(p,v)}function Om(p){var v=tr(p)?da:ll;return v(p)}function lp(p){if(p==null)return 0;if(hl(p))return S1(p)?tu(p):p.length;var v=Iu(p);return v==w||v==Qt?p.size:Va(p).length}function sp(p,v,x){var P=tr(p)?Cr:yh;return x&&s0(p,v,x)&&(v=i),P(p,Vn(v,3))}var Ca=Ir(function(p,v){if(p==null)return[];var x=v.length;return x>1&&s0(p,v[0],v[1])?v=[]:x>2&&s0(v[0],v[1],v[2])&&(v=[v[0]]),g0(p,qi(v,1),[])}),E1=fa||function(){return ji.Date.now()};function ap(p,v){if(typeof v!="function")throw new ti(_);return p=Mr(p),function(){if(--p<1)return v.apply(this,arguments)}}function Qh(p,v,x){return v=x?i:v,v=p&&v==null?p.length:v,hn(p,me,i,i,i,i,v)}function Rd(p,v){var x;if(typeof v!="function")throw new ti(_);return p=Mr(p),function(){return--p>0&&(x=v.apply(this,arguments)),p<=1&&(v=i),x}}var D1=Ir(function(p,v,x){var P=m;if(x.length){var W=xo(x,yr(D1));P|=_e}return hn(p,P,v,x,W)}),Jh=Ir(function(p,v,x){var P=m|pe;if(x.length){var W=xo(x,yr(Jh));P|=_e}return hn(v,P,p,x,W)});function fp(p,v,x){v=x?i:v;var P=hn(p,ve,i,i,i,i,i,v);return P.placeholder=fp.placeholder,P}function Zh(p,v,x){v=x?i:v;var P=hn(p,ue,i,i,i,i,i,v);return P.placeholder=Zh.placeholder,P}function cp(p,v,x){var P,W,ee,he,De,be,Et=0,St=!1,At=!1,on=!0;if(typeof p!="function")throw new ti(_);v=vl(v)||0,bu(x)&&(St=!!x.leading,At="maxWait"in x,ee=At?ni(vl(x.maxWait)||0,v):ee,on="trailing"in x?!!x.trailing:on);function kn(ao){var Ms=P,C0=W;return P=W=i,Et=ao,he=p.apply(C0,Ms),he}function rr(ao){return Et=ao,De=Ja(ui,v),St?kn(ao):he}function br(ao){var Ms=ao-be,C0=ao-Et,kv=v-Ms;return At?Kn(kv,ee-C0):kv}function ar(ao){var Ms=ao-be,C0=ao-Et;return be===i||Ms>=v||Ms<0||At&&C0>=ee}function ui(){var ao=E1();if(ar(ao))return di(ao);De=Ja(ui,br(ao))}function di(ao){return De=i,on&&P?kn(ao):(P=W=i,he)}function zl(){De!==i&&Zc(De),Et=0,P=be=W=De=i}function Zi(){return De===i?he:di(E1())}function a0(){var ao=E1(),Ms=ar(ao);if(P=arguments,W=this,be=ao,Ms){if(De===i)return rr(be);if(At)return Zc(De),De=Ja(ui,v),kn(be)}return De===i&&(De=Ja(ui,v)),he}return a0.cancel=zl,a0.flush=Zi,a0}var $h=Ir(function(p,v){return pc(p,1,v)}),ev=Ir(function(p,v,x){return pc(p,vl(v)||0,x)});function dp(p){return hn(p,we)}function Ad(p,v){if(typeof p!="function"||v!=null&&typeof v!="function")throw new ti(_);var x=function(){var P=arguments,W=v?v.apply(this,P):P[0],ee=x.cache;if(ee.has(W))return ee.get(W);var he=p.apply(this,P);return x.cache=ee.set(W,he)||ee,he};return x.cache=new(Ad.Cache||jo),x}Ad.Cache=jo;function Od(p){if(typeof p!="function")throw new ti(_);return function(){var v=arguments;switch(v.length){case 0:return!p.call(this);case 1:return!p.call(this,v[0]);case 2:return!p.call(this,v[0],v[1]);case 3:return!p.call(this,v[0],v[1],v[2])}return!p.apply(this,v)}}function qo(p){return Rd(2,p)}var Md=k2(function(p,v){v=v.length==1&&tr(v[0])?Ft(v[0],_i(Vn())):Ft(qi(v,1),_i(Vn()));var x=v.length;return Ir(function(P){for(var W=-1,ee=Kn(P.length,x);++W=v}),pl=uo(function(){return arguments}())?uo:function(p){return Yu(p)&&li.call(p,"callee")&&!Uo.call(p,"callee")},tr=Ye.isArray,Js=Ee?_i(Ee):Ve;function hl(p){return p!=null&&Pd(p.length)&&!Ra(p)}function lo(p){return Yu(p)&&hl(p)}function rv(p){return p===!0||p===!1||Yu(p)&>(p)==an}var Zs=r0||jp,yp=Ae?_i(Ae):ze;function Fm(p){return Yu(p)&&p.nodeType===1&&!xc(p)}function iv(p){if(p==null)return!0;if(hl(p)&&(tr(p)||typeof p=="string"||typeof p.splice=="function"||Zs(p)||Aa(p)||pl(p)))return!p.length;var v=Iu(p);if(v==w||v==Qt)return!p.size;if(Nf(p))return!Va(p).length;for(var x in p)if(li.call(p,x))return!1;return!0}function gp(p,v){return lt(p,v)}function Pm(p,v,x){x=typeof x=="function"?x:i;var P=x?x(p,v):i;return P===i?lt(p,v,i,x):!!P}function _p(p){if(!Yu(p))return!1;var v=gt(p);return v==ln||v==lr||typeof p.message=="string"&&typeof p.name=="string"&&!xc(p)}function Cc(p){return typeof p=="number"&&nu(p)}function Ra(p){if(!bu(p))return!1;var v=gt(p);return v==Gt||v==Er||v==nn||v==fr}function Ep(p){return typeof p=="number"&&p==Mr(p)}function Pd(p){return typeof p=="number"&&p>-1&&p%1==0&&p<=zt}function bu(p){var v=typeof p;return p!=null&&(v=="object"||v=="function")}function Yu(p){return p!=null&&typeof p=="object"}var Dp=Z?_i(Z):Wn;function wp(p,v){return p===v||si(p,v,jn(v))}function uv(p,v,x){return x=typeof x=="function"?x:i,si(p,v,jn(v),x)}function Im(p){return ov(p)&&p!=+p}function bm(p){if(Nl(p))throw new Xt(c);return ur(p)}function Bm(p){return p===null}function Id(p){return p==null}function ov(p){return typeof p=="number"||Yu(p)&>(p)==jt}function xc(p){if(!Yu(p)||gt(p)!=vr)return!1;var v=il(p);if(v===null)return!0;var x=li.call(v,"constructor")&&v.constructor;return typeof x=="function"&&x instanceof x&&Fu.call(x)==aa}var w1=ke?_i(ke):ci;function Um(p){return Ep(p)&&p>=-zt&&p<=zt}var bd=Je?_i(Je):Qi;function S1(p){return typeof p=="string"||!tr(p)&&Yu(p)&>(p)==wu}function Bl(p){return typeof p=="symbol"||Yu(p)&>(p)==po}var Aa=mt?_i(mt):Gr;function lv(p){return p===i}function jm(p){return Yu(p)&&Iu(p)==J0}function sv(p){return Yu(p)&>(p)==Ps}var av=yd(ld),zm=yd(function(p,v){return p<=v});function fv(p){if(!p)return[];if(hl(p))return S1(p)?ei(p):iu(p);if(Pu&&p[Pu])return Qu(p[Pu]());var v=Iu(p),x=v==w?Tu:v==Qt?e0:Nc;return x(p)}function Oa(p){if(!p)return p===0?p:0;if(p=vl(p),p===kt||p===-kt){var v=p<0?-1:1;return v*nt}return p===p?p:0}function Mr(p){var v=Oa(p),x=v%1;return v===v?x?v-x:v:0}function Sp(p){return p?ro(Mr(p),0,fe):0}function vl(p){if(typeof p=="number")return p;if(Bl(p))return X;if(bu(p)){var v=typeof p.valueOf=="function"?p.valueOf():p;p=bu(v)?v+"":v}if(typeof p!="string")return p===0?p:+p;p=Nu(p);var x=f0.test(p);return x||L0.test(p)?Us(p.slice(2),x?2:8):ai.test(p)?X:+p}function gu(p){return ko(p,dn(p))}function T1(p){return p?ro(Mr(p),-zt,zt):p===0?p:0}function Ui(p){return p==null?"":al(p)}var Tp=o0(function(p,v){if(Nf(v)||hl(v)){ko(v,No(v),p);return}for(var x in v)li.call(v,x)&&Ts(p,x,v[x])}),Bd=o0(function(p,v){ko(v,dn(v),p)}),T0=o0(function(p,v,x,P){ko(v,dn(v),p,P)}),Os=o0(function(p,v,x,P){ko(v,No(v),p,P)}),Bf=cl(Wa);function Ud(p,v){var x=ri(p);return v==null?x:Df(x,v)}var Cp=Ir(function(p,v){p=xn(p);var x=-1,P=v.length,W=P>2?v[2]:i;for(W&&s0(v[0],v[1],W)&&(P=1);++x1),ee}),ko(p,sr(p),x),P&&(x=zo(x,T|B|H,cm));for(var W=v.length;W--;)A2(x,v[W]);return x});function A1(p,v){return tf(p,Od(Vn(v)))}var Ap=cl(function(p,v){return p==null?{}:vh(p,v)});function tf(p,v){if(p==null)return{};var x=Ft(sr(p),function(P){return[P]});return v=Vn(v),mh(p,x,function(P,W){return v(P,W[0])})}function Hm(p,v,x){v=Vs(v,p);var P=-1,W=v.length;for(W||(W=1,p=i);++Pv){var P=p;p=v,v=P}if(x||p%1||v%1){var W=Do();return Kn(p+W*(v-p+Ba("1e-"+((W+"").length-1))),v)}return fd(p,v)}var Gd=xf(function(p,v,x){return v=v.toLowerCase(),p+(x?W0(v):v)});function W0(p){return kp(Ui(p).toLowerCase())}function Yd(p){return p=Ui(p),p&&p.replace($n,I0).replace(Zo,"")}function Wm(p,v,x){p=Ui(p),v=al(v);var P=p.length;x=x===i?P:ro(Mr(x),0,P);var W=x;return x-=v.length,x>=0&&p.slice(x,W)==v}function k1(p){return p=Ui(p),p&&Is.test(p)?p.replace(au,gs):p}function Vm(p){return p=Ui(p),p&&en.test(p)?p.replace(yi,"\\$&"):p}var Gm=xf(function(p,v,x){return p+(x?"-":"")+v.toLowerCase()}),dv=xf(function(p,v,x){return p+(x?" ":"")+v.toLowerCase()}),Ym=wh("toLowerCase");function pv(p,v,x){p=Ui(p),v=Mr(v);var P=v?tu(p):0;if(!v||P>=v)return p;var W=(v-P)/2;return Ea(Ds(W),x)+p+Ea($u(W),x)}function Km(p,v,x){p=Ui(p),v=Mr(v);var P=v?tu(p):0;return v&&P>>0,x?(p=Ui(p),p&&(typeof v=="string"||v!=null&&!w1(v))&&(v=al(v),!v&&B0(p))?ma(ei(p),0,x):p.split(v,x)):[]}var Hf=xf(function(p,v,x){return p+(x?" ":"")+kp(v)});function vv(p,v,x){return p=Ui(p),x=x==null?0:ro(Mr(x),0,p.length),v=al(v),p.slice(x,x+v.length)==v}function mv(p,v,x){var P=Y.templateSettings;x&&s0(p,v,x)&&(v=i),p=Ui(p),v=T0({},v,P,Af);var W=T0({},v.imports,P.imports,Af),ee=No(W),he=P0(W,ee),De,be,Et=0,St=v.interpolate||tl,At="__p += '",on=yu((v.escape||tl).source+"|"+St.source+"|"+(St===ho?Ql:tl).source+"|"+(v.evaluate||tl).source+"|$","g"),kn="//# sourceURL="+(li.call(v,"sourceURL")?(v.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++fc+"]")+` -`;p.replace(on,function(ar,ui,di,zl,Zi,a0){return di||(di=zl),At+=p.slice(Et,a0).replace(c0,zs),ui&&(De=!0,At+=`' + -__e(`+ui+`) + -'`),Zi&&(be=!0,At+=`'; -`+Zi+`; -__p += '`),di&&(At+=`' + -((__t = (`+di+`)) == null ? '' : __t) + -'`),Et=a0+ar.length,ar}),At+=`'; -`;var rr=li.call(v,"variable")&&v.variable;if(!rr)At=`with (obj) { -`+At+` -} -`;else if(Jo.test(rr))throw new Xt(t);At=(be?At.replace(Xr,""):At).replace(O0,"$1").replace(M0,"$1;"),At="function("+(rr||"obj")+`) { -`+(rr?"":`obj || (obj = {}); -`)+"var __t, __p = ''"+(De?", __e = _.escape":"")+(be?`, __j = Array.prototype.join; -function print() { __p += __j.call(arguments, '') } -`:`; -`)+At+`return __p -}`;var br=wv(function(){return pr(ee,kn+"return "+At).apply(i,he)});if(br.source=At,_p(br))throw br;return br}function yv(p){return Ui(p).toLowerCase()}function Kd(p){return Ui(p).toUpperCase()}function Xd(p,v,x){if(p=Ui(p),p&&(x||v===i))return Nu(p);if(!p||!(v=al(v)))return p;var P=ei(p),W=ei(v),ee=vf(P,W),he=Tl(P,W)+1;return ma(P,ee,he).join("")}function Mp(p,v,x){if(p=Ui(p),p&&(x||v===i))return p.slice(0,h0(p)+1);if(!p||!(v=al(v)))return p;var P=ei(p),W=Tl(P,ei(v))+1;return ma(P,0,W).join("")}function gv(p,v,x){if(p=Ui(p),p&&(x||v===i))return p.replace(bn,"");if(!p||!(v=al(v)))return p;var P=ei(p),W=vf(P,ei(v));return ma(P,W).join("")}function Qd(p,v){var x=Ie,P=je;if(bu(v)){var W="separator"in v?v.separator:W;x="length"in v?Mr(v.length):x,P="omission"in v?al(v.omission):P}p=Ui(p);var ee=p.length;if(B0(p)){var he=ei(p);ee=he.length}if(x>=ee)return p;var De=x-tu(P);if(De<1)return P;var be=he?ma(he,0,De).join(""):p.slice(0,De);if(W===i)return be+P;if(he&&(De+=be.length-De),w1(W)){if(p.slice(De).search(W)){var Et,St=be;for(W.global||(W=yu(W.source,Ui(k0.exec(W))+"g")),W.lastIndex=0;Et=W.exec(St);)var At=Et.index;be=be.slice(0,At===i?De:At)}}else if(p.indexOf(al(W),De)!=De){var on=be.lastIndexOf(W);on>-1&&(be=be.slice(0,on))}return be+P}function _v(p){return p=Ui(p),p&&ki.test(p)?p.replace(Po,Bi):p}var Ev=xf(function(p,v,x){return p+(x?" ":"")+v.toUpperCase()}),kp=wh("toUpperCase");function Dv(p,v,x){return p=Ui(p),v=x?i:v,v===i?_s(p)?gf(p):_o(p):p.match(v)||[]}var wv=Ir(function(p,v){try{return oe(p,i,v)}catch(x){return _p(x)?x:new Xt(x)}}),$m=cl(function(p,v){return it(v,function(x){x=Fl(x),Gu(p,x,D1(p[x],p))}),p});function Sv(p){var v=p==null?0:p.length,x=Vn();return p=v?Ft(p,function(P){if(typeof P[1]!="function")throw new ti(_);return[x(P[0]),P[1]]}):[],Ir(function(P){for(var W=-1;++Wzt)return[];var x=fe,P=Kn(p,fe);v=Vn(v),p-=fe;for(var W=Co(P,v);++x0||v<0)?new at(x):(p<0?x=x.takeRight(-p):p&&(x=x.drop(p)),v!==i&&(v=Mr(v),x=v<0?x.dropRight(-v):x.take(v-p)),x)},at.prototype.takeRightWhile=function(p){return this.reverse().takeWhile(p).reverse()},at.prototype.toArray=function(){return this.take(fe)},R(at.prototype,function(p,v){var x=/^(?:filter|find|map|reject)|While$/.test(v),P=/^(?:head|last)$/.test(v),W=Y[P?"take"+(v=="last"?"Right":""):v],ee=P||/^find/.test(v);!W||(Y.prototype[v]=function(){var he=this.__wrapped__,De=P?[1]:arguments,be=he instanceof at,Et=De[0],St=be||tr(he),At=function(ui){var di=W.apply(Y,Dn([ui],De));return P&&on?di[0]:di};St&&x&&typeof Et=="function"&&Et.length!=1&&(be=St=!1);var on=this.__chain__,kn=!!this.__actions__.length,rr=ee&&!on,br=be&&!kn;if(!ee&&St){he=br?he:new at(this);var ar=p.apply(he,De);return ar.__actions__.push({func:g1,args:[At],thisArg:i}),new Vr(ar,on)}return rr&&br?p.apply(this,De):(ar=this.thru(At),rr?P?ar.value()[0]:ar.value():ar)})}),it(["pop","push","shift","sort","splice","unshift"],function(p){var v=Jr[p],x=/^(?:push|sort|unshift)$/.test(p)?"tap":"thru",P=/^(?:pop|shift)$/.test(p);Y.prototype[p]=function(){var W=arguments;if(P&&!this.__chain__){var ee=this.value();return v.apply(tr(ee)?ee:[],W)}return this[x](function(he){return v.apply(tr(he)?he:[],W)})}}),R(at.prototype,function(p,v){var x=Y[v];if(x){var P=x.name+"";li.call(On,P)||(On[P]=[]),On[P].push({name:v,func:x})}}),On[ga(i,pe).name]=[{name:"wrapper",func:i}],at.prototype.clone=Di,at.prototype.reverse=ru,at.prototype.value=wo,Y.prototype.at=$2,Y.prototype.chain=qh,Y.prototype.commit=ep,Y.prototype.next=Wh,Y.prototype.plant=Em,Y.prototype.reverse=If,Y.prototype.toJSON=Y.prototype.valueOf=Y.prototype.value=bf,Y.prototype.first=Y.prototype.head,Pu&&(Y.prototype[Pu]=_m),Y},n0=t0();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(ji._=n0,define(function(){return n0})):z?((z.exports=n0)._=n0,U._=n0):ji._=n0}).call(Wv)});var yD=Ke((wW,mD)=>{"use strict";var Pi=mD.exports;mD.exports.default=Pi;var Du="[",jy="]",Vv="\x07",P_=";",LS=process.env.TERM_PROGRAM==="Apple_Terminal";Pi.cursorTo=(i,o)=>{if(typeof i!="number")throw new TypeError("The `x` argument is required");return typeof o!="number"?Du+(i+1)+"G":Du+(o+1)+";"+(i+1)+"H"};Pi.cursorMove=(i,o)=>{if(typeof i!="number")throw new TypeError("The `x` argument is required");let a="";return i<0?a+=Du+-i+"D":i>0&&(a+=Du+i+"C"),o<0?a+=Du+-o+"A":o>0&&(a+=Du+o+"B"),a};Pi.cursorUp=(i=1)=>Du+i+"A";Pi.cursorDown=(i=1)=>Du+i+"B";Pi.cursorForward=(i=1)=>Du+i+"C";Pi.cursorBackward=(i=1)=>Du+i+"D";Pi.cursorLeft=Du+"G";Pi.cursorSavePosition=LS?"7":Du+"s";Pi.cursorRestorePosition=LS?"8":Du+"u";Pi.cursorGetPosition=Du+"6n";Pi.cursorNextLine=Du+"E";Pi.cursorPrevLine=Du+"F";Pi.cursorHide=Du+"?25l";Pi.cursorShow=Du+"?25h";Pi.eraseLines=i=>{let o="";for(let a=0;a[jy,"8",P_,P_,o,Vv,i,jy,"8",P_,P_,Vv].join("");Pi.image=(i,o={})=>{let a=`${jy}1337;File=inline=1`;return o.width&&(a+=`;width=${o.width}`),o.height&&(a+=`;height=${o.height}`),o.preserveAspectRatio===!1&&(a+=";preserveAspectRatio=0"),a+":"+i.toString("base64")+Vv};Pi.iTerm={setCwd:(i=process.cwd())=>`${jy}50;CurrentDir=${i}${Vv}`,annotation:(i,o={})=>{let a=`${jy}1337;`,c=typeof o.x!="undefined",_=typeof o.y!="undefined";if((c||_)&&!(c&&_&&typeof o.length!="undefined"))throw new Error("`x`, `y` and `length` must be defined when `x` or `y` is defined");return i=i.replace(/\|/g,""),a+=o.isHidden?"AddHiddenAnnotation=":"AddAnnotation=",o.length>0?a+=(c?[i,o.length,o.x,o.y]:[o.length,i]).join("|"):a+=i,a+Vv}}});var PS=Ke((SW,gD)=>{"use strict";var NS=(i,o)=>{for(let a of Reflect.ownKeys(o))Object.defineProperty(i,a,Object.getOwnPropertyDescriptor(o,a));return i};gD.exports=NS;gD.exports.default=NS});var bS=Ke((TW,I_)=>{"use strict";var AI=PS(),b_=new WeakMap,IS=(i,o={})=>{if(typeof i!="function")throw new TypeError("Expected a function");let a,c=0,_=i.displayName||i.name||"",t=function(...M){if(b_.set(t,++c),c===1)a=i.apply(this,M),i=null;else if(o.throw===!0)throw new Error(`Function \`${_}\` can only be called once`);return a};return AI(t,i),b_.set(t,c),t};I_.exports=IS;I_.exports.default=IS;I_.exports.callCount=i=>{if(!b_.has(i))throw new Error(`The given function \`${i.name}\` is not wrapped by the \`onetime\` package`);return b_.get(i)}});var BS=Ke((CW,B_)=>{B_.exports=["SIGABRT","SIGALRM","SIGHUP","SIGINT","SIGTERM"];process.platform!=="win32"&&B_.exports.push("SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&B_.exports.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT","SIGUNUSED")});var wD=Ke((xW,zy)=>{var OI=require("assert"),Hy=BS(),MI=/^win/i.test(process.platform),U_=require("events");typeof U_!="function"&&(U_=U_.EventEmitter);var Yl;process.__signal_exit_emitter__?Yl=process.__signal_exit_emitter__:(Yl=process.__signal_exit_emitter__=new U_,Yl.count=0,Yl.emitted={});Yl.infinite||(Yl.setMaxListeners(Infinity),Yl.infinite=!0);zy.exports=function(i,o){OI.equal(typeof i,"function","a callback must be provided for exit handler"),qy===!1&&US();var a="exit";o&&o.alwaysLast&&(a="afterexit");var c=function(){Yl.removeListener(a,i),Yl.listeners("exit").length===0&&Yl.listeners("afterexit").length===0&&_D()};return Yl.on(a,i),c};zy.exports.unload=_D;function _D(){!qy||(qy=!1,Hy.forEach(function(i){try{process.removeListener(i,ED[i])}catch(o){}}),process.emit=DD,process.reallyExit=jS,Yl.count-=1)}function Gv(i,o,a){Yl.emitted[i]||(Yl.emitted[i]=!0,Yl.emit(i,o,a))}var ED={};Hy.forEach(function(i){ED[i]=function(){var a=process.listeners(i);a.length===Yl.count&&(_D(),Gv("exit",null,i),Gv("afterexit",null,i),MI&&i==="SIGHUP"&&(i="SIGINT"),process.kill(process.pid,i))}});zy.exports.signals=function(){return Hy};zy.exports.load=US;var qy=!1;function US(){qy||(qy=!0,Yl.count+=1,Hy=Hy.filter(function(i){try{return process.on(i,ED[i]),!0}catch(o){return!1}}),process.emit=LI,process.reallyExit=kI)}var jS=process.reallyExit;function kI(i){process.exitCode=i||0,Gv("exit",process.exitCode,null),Gv("afterexit",process.exitCode,null),jS.call(process,process.exitCode)}var DD=process.emit;function LI(i,o){if(i==="exit"){o!==void 0&&(process.exitCode=o);var a=DD.apply(this,arguments);return Gv("exit",process.exitCode,null),Gv("afterexit",process.exitCode,null),a}else return DD.apply(this,arguments)}});var HS=Ke((RW,zS)=>{"use strict";var NI=bS(),FI=wD();zS.exports=NI(()=>{FI(()=>{process.stderr.write("[?25h")},{alwaysLast:!0})})});var SD=Ke(Yv=>{"use strict";var PI=HS(),j_=!1;Yv.show=(i=process.stderr)=>{!i.isTTY||(j_=!1,i.write("[?25h"))};Yv.hide=(i=process.stderr)=>{!i.isTTY||(PI(),j_=!0,i.write("[?25l"))};Yv.toggle=(i,o)=>{i!==void 0&&(j_=i),j_?Yv.show(o):Yv.hide(o)}});var GS=Ke(Wy=>{"use strict";var qS=Wy&&Wy.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Wy,"__esModule",{value:!0});var WS=qS(yD()),VS=qS(SD()),II=(i,{showCursor:o=!1}={})=>{let a=0,c="",_=!1,t=M=>{!o&&!_&&(VS.default.hide(),_=!0);let N=M+` -`;N!==c&&(c=N,i.write(WS.default.eraseLines(a)+N),a=N.split(` -`).length)};return t.clear=()=>{i.write(WS.default.eraseLines(a)),c="",a=0},t.done=()=>{c="",a=0,o||(VS.default.show(),_=!1)},t};Wy.default={create:II}});var KS=Ke((MW,YS)=>{YS.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY_BUILD_BASE",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}}]});var JS=Ke(Pa=>{"use strict";var XS=KS(),jc=process.env;Object.defineProperty(Pa,"_vendors",{value:XS.map(function(i){return i.constant})});Pa.name=null;Pa.isPR=null;XS.forEach(function(i){var o=Array.isArray(i.env)?i.env:[i.env],a=o.every(function(c){return QS(c)});if(Pa[i.constant]=a,a)switch(Pa.name=i.name,typeof i.pr){case"string":Pa.isPR=!!jc[i.pr];break;case"object":"env"in i.pr?Pa.isPR=i.pr.env in jc&&jc[i.pr.env]!==i.pr.ne:"any"in i.pr?Pa.isPR=i.pr.any.some(function(c){return!!jc[c]}):Pa.isPR=QS(i.pr);break;default:Pa.isPR=null}});Pa.isCI=!!(jc.CI||jc.CONTINUOUS_INTEGRATION||jc.BUILD_NUMBER||jc.RUN_ID||Pa.name);function QS(i){return typeof i=="string"?!!jc[i]:Object.keys(i).every(function(o){return jc[o]===i[o]})}});var $S=Ke((LW,ZS)=>{"use strict";ZS.exports=JS().isCI});var tT=Ke((NW,eT)=>{"use strict";var bI=i=>{let o=new Set;do for(let a of Reflect.ownKeys(i))o.add([i,a]);while((i=Reflect.getPrototypeOf(i))&&i!==Object.prototype);return o};eT.exports=(i,{include:o,exclude:a}={})=>{let c=_=>{let t=M=>typeof M=="string"?_===M:M.test(_);return o?o.some(t):a?!a.some(t):!0};for(let[_,t]of bI(i.constructor.prototype)){if(t==="constructor"||!c(t))continue;let M=Reflect.getOwnPropertyDescriptor(_,t);M&&typeof M.value=="function"&&(i[t]=i[t].bind(i))}return i}});var sT=Ke(lu=>{"use strict";Object.defineProperty(lu,"__esModule",{value:!0});var Kv,Vy,z_,H_,TD;typeof window=="undefined"||typeof MessageChannel!="function"?(Xv=null,CD=null,xD=function(){if(Xv!==null)try{var i=lu.unstable_now();Xv(!0,i),Xv=null}catch(o){throw setTimeout(xD,0),o}},nT=Date.now(),lu.unstable_now=function(){return Date.now()-nT},Kv=function(i){Xv!==null?setTimeout(Kv,0,i):(Xv=i,setTimeout(xD,0))},Vy=function(i,o){CD=setTimeout(i,o)},z_=function(){clearTimeout(CD)},H_=function(){return!1},TD=lu.unstable_forceFrameRate=function(){}):(q_=window.performance,RD=window.Date,rT=window.setTimeout,iT=window.clearTimeout,typeof console!="undefined"&&(uT=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),typeof uT!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")),typeof q_=="object"&&typeof q_.now=="function"?lu.unstable_now=function(){return q_.now()}:(oT=RD.now(),lu.unstable_now=function(){return RD.now()-oT}),Gy=!1,Yy=null,W_=-1,AD=5,OD=0,H_=function(){return lu.unstable_now()>=OD},TD=function(){},lu.unstable_forceFrameRate=function(i){0>i||125G_(M,a))O!==void 0&&0>G_(O,M)?(i[c]=O,i[N]=a,c=N):(i[c]=M,i[t]=a,c=t);else if(O!==void 0&&0>G_(O,a))i[c]=O,i[N]=a,c=N;else break e}}return o}return null}function G_(i,o){var a=i.sortIndex-o.sortIndex;return a!==0?a:i.id-o.id}var ec=[],d2=[],BI=1,Fs=null,ps=3,K_=!1,$p=!1,Ky=!1;function X_(i){for(var o=df(d2);o!==null;){if(o.callback===null)Y_(d2);else if(o.startTime<=i)Y_(d2),o.sortIndex=o.expirationTime,kD(ec,o);else break;o=df(d2)}}function LD(i){if(Ky=!1,X_(i),!$p)if(df(ec)!==null)$p=!0,Kv(ND);else{var o=df(d2);o!==null&&Vy(LD,o.startTime-i)}}function ND(i,o){$p=!1,Ky&&(Ky=!1,z_()),K_=!0;var a=ps;try{for(X_(o),Fs=df(ec);Fs!==null&&(!(Fs.expirationTime>o)||i&&!H_());){var c=Fs.callback;if(c!==null){Fs.callback=null,ps=Fs.priorityLevel;var _=c(Fs.expirationTime<=o);o=lu.unstable_now(),typeof _=="function"?Fs.callback=_:Fs===df(ec)&&Y_(ec),X_(o)}else Y_(ec);Fs=df(ec)}if(Fs!==null)var t=!0;else{var M=df(d2);M!==null&&Vy(LD,M.startTime-o),t=!1}return t}finally{Fs=null,ps=a,K_=!1}}function lT(i){switch(i){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var UI=TD;lu.unstable_ImmediatePriority=1;lu.unstable_UserBlockingPriority=2;lu.unstable_NormalPriority=3;lu.unstable_IdlePriority=5;lu.unstable_LowPriority=4;lu.unstable_runWithPriority=function(i,o){switch(i){case 1:case 2:case 3:case 4:case 5:break;default:i=3}var a=ps;ps=i;try{return o()}finally{ps=a}};lu.unstable_next=function(i){switch(ps){case 1:case 2:case 3:var o=3;break;default:o=ps}var a=ps;ps=o;try{return i()}finally{ps=a}};lu.unstable_scheduleCallback=function(i,o,a){var c=lu.unstable_now();if(typeof a=="object"&&a!==null){var _=a.delay;_=typeof _=="number"&&0<_?c+_:c,a=typeof a.timeout=="number"?a.timeout:lT(i)}else a=lT(i),_=c;return a=_+a,i={id:BI++,callback:o,priorityLevel:i,startTime:_,expirationTime:a,sortIndex:-1},_>c?(i.sortIndex=_,kD(d2,i),df(ec)===null&&i===df(d2)&&(Ky?z_():Ky=!0,Vy(LD,_-c))):(i.sortIndex=a,kD(ec,i),$p||K_||($p=!0,Kv(ND))),i};lu.unstable_cancelCallback=function(i){i.callback=null};lu.unstable_wrapCallback=function(i){var o=ps;return function(){var a=ps;ps=o;try{return i.apply(this,arguments)}finally{ps=a}}};lu.unstable_getCurrentPriorityLevel=function(){return ps};lu.unstable_shouldYield=function(){var i=lu.unstable_now();X_(i);var o=df(ec);return o!==Fs&&Fs!==null&&o!==null&&o.callback!==null&&o.startTime<=i&&o.expirationTime{"use strict";process.env.NODE_ENV!=="production"&&function(){"use strict";Object.defineProperty(Ii,"__esModule",{value:!0});var i=!1,o=!1,a=!0,c,_,t,M,N;if(typeof window=="undefined"||typeof MessageChannel!="function"){var O=null,T=null,B=function(){if(O!==null)try{var wt=Ii.unstable_now(),bt=!0;O(bt,wt),O=null}catch(Hn){throw setTimeout(B,0),Hn}},H=Date.now();Ii.unstable_now=function(){return Date.now()-H},c=function(wt){O!==null?setTimeout(c,0,wt):(O=wt,setTimeout(B,0))},_=function(wt,bt){T=setTimeout(wt,bt)},t=function(){clearTimeout(T)},M=function(){return!1},N=Ii.unstable_forceFrameRate=function(){}}else{var q=window.performance,ne=window.Date,m=window.setTimeout,pe=window.clearTimeout;if(typeof console!="undefined"){var ge=window.requestAnimationFrame,ve=window.cancelAnimationFrame;typeof ge!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),typeof ve!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if(typeof q=="object"&&typeof q.now=="function")Ii.unstable_now=function(){return q.now()};else{var ue=ne.now();Ii.unstable_now=function(){return ne.now()-ue}}var _e=!1,ce=null,me=-1,re=5,we=0,Ie=300,je=!1;if(o&&navigator!==void 0&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0){var ct=navigator.scheduling;M=function(){var wt=Ii.unstable_now();return wt>=we?je||ct.isInputPending()?!0:wt>=Ie:!1},N=function(){je=!0}}else M=function(){return Ii.unstable_now()>=we},N=function(){};Ii.unstable_forceFrameRate=function(wt){if(wt<0||wt>125){console.error("forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported");return}wt>0?re=Math.floor(1e3/wt):re=5};var pt=function(){if(ce!==null){var wt=Ii.unstable_now();we=wt+re;var bt=!0;try{var Hn=ce(bt,wt);Hn?tt.postMessage(null):(_e=!1,ce=null)}catch(qr){throw tt.postMessage(null),qr}}else _e=!1;je=!1},Xe=new MessageChannel,tt=Xe.port2;Xe.port1.onmessage=pt,c=function(wt){ce=wt,_e||(_e=!0,tt.postMessage(null))},_=function(wt,bt){me=m(function(){wt(Ii.unstable_now())},bt)},t=function(){pe(me),me=-1}}function He(wt,bt){var Hn=wt.length;wt.push(bt),nt(wt,bt,Hn)}function kt(wt){var bt=wt[0];return bt===void 0?null:bt}function zt(wt){var bt=wt[0];if(bt!==void 0){var Hn=wt.pop();return Hn!==bt&&(wt[0]=Hn,X(wt,Hn,0)),bt}else return null}function nt(wt,bt,Hn){for(var qr=Hn;;){var Ki=Math.floor((qr-1)/2),Qr=wt[Ki];if(Qr!==void 0&&fe(Qr,bt)>0)wt[Ki]=bt,wt[qr]=Qr,qr=Ki;else return}}function X(wt,bt,Hn){for(var qr=Hn,Ki=wt.length;qrfr){if(fr*=2,fr>jr){console.error("Scheduler Profiling: Event log exceeded maximum size. Don't forget to call `stopLoggingProfilingEvents()`."),Dr();return}var Hn=new Int32Array(fr*4);Hn.set(Qt),zr=Hn.buffer,Qt=Hn}Qt.set(wt,bt)}}function mi(){fr=vr,zr=new ArrayBuffer(fr*4),Qt=new Int32Array(zr),wu=0}function Dr(){var wt=zr;return fr=0,zr=null,Qt=null,wu=0,wt}function el(wt,bt){a&&(Gt[Xn]++,Qt!==null&&su([po,bt*1e3,wt.id,wt.priorityLevel]))}function Ko(wt,bt){a&&(Gt[Er]=xe,Gt[w]=0,Gt[Xn]--,Qt!==null&&su([A0,bt*1e3,wt.id]))}function Uu(wt,bt){a&&(Gt[Xn]--,Qt!==null&&su([Ps,bt*1e3,wt.id]))}function Xo(wt,bt){a&&(Gt[Er]=xe,Gt[w]=0,Gt[Xn]--,Qt!==null&&su([J0,bt*1e3,wt.id]))}function Xr(wt,bt){a&&(an++,Gt[Er]=wt.priorityLevel,Gt[w]=wt.id,Gt[jt]=an,Qt!==null&&su([Z0,bt*1e3,wt.id,an]))}function O0(wt,bt){a&&(Gt[Er]=xe,Gt[w]=0,Gt[jt]=0,Qt!==null&&su([$0,bt*1e3,wt.id,an]))}function M0(wt){a&&(Mn++,Qt!==null&&su([Wt,wt*1e3,Mn]))}function Po(wt){a&&Qt!==null&&su([xi,wt*1e3,Mn])}var au=1073741823,ki=-1,Is=250,Xl=5e3,Io=1e4,ho=au,Hr=[],Ri=[],Qo=1,yi=!1,en=null,bn=dt,Ai=!1,gi=!1,Vt=!1;function Au(wt){for(var bt=kt(Ri);bt!==null;){if(bt.callback===null)zt(Ri);else if(bt.startTime<=wt)zt(Ri),bt.sortIndex=bt.expirationTime,He(Hr,bt),a&&(el(bt,wt),bt.isQueued=!0);else return;bt=kt(Ri)}}function eu(wt){if(Vt=!1,Au(wt),!gi)if(kt(Hr)!==null)gi=!0,c(Jo);else{var bt=kt(Ri);bt!==null&&_(eu,bt.startTime-wt)}}function Jo(wt,bt){a&&Po(bt),gi=!1,Vt&&(Vt=!1,t()),Ai=!0;var Hn=bn;try{if(a)try{return Yi(wt,bt)}catch(Qr){if(en!==null){var qr=Ii.unstable_now();Xo(en,qr),en.isQueued=!1}throw Qr}else return Yi(wt,bt)}finally{if(en=null,bn=Hn,Ai=!1,a){var Ki=Ii.unstable_now();M0(Ki)}}}function Yi(wt,bt){var Hn=bt;for(Au(Hn),en=kt(Hr);en!==null&&!(i&&yi)&&!(en.expirationTime>Hn&&(!wt||M()));){var qr=en.callback;if(qr!==null){en.callback=null,bn=en.priorityLevel;var Ki=en.expirationTime<=Hn;Xr(en,Hn);var Qr=qr(Ki);Hn=Ii.unstable_now(),typeof Qr=="function"?(en.callback=Qr,O0(en,Hn)):(a&&(Ko(en,Hn),en.isQueued=!1),en===kt(Hr)&&zt(Hr)),Au(Hn)}else zt(Hr);en=kt(Hr)}if(en!==null)return!0;var Ou=kt(Ri);return Ou!==null&&_(eu,Ou.startTime-Hn),!1}function Ql(wt,bt){switch(wt){case le:case qe:case dt:case Rt:case nn:break;default:wt=dt}var Hn=bn;bn=wt;try{return bt()}finally{bn=Hn}}function k0(wt){var bt;switch(bn){case le:case qe:case dt:bt=dt;break;default:bt=bn;break}var Hn=bn;bn=bt;try{return wt()}finally{bn=Hn}}function ai(wt){var bt=bn;return function(){var Hn=bn;bn=bt;try{return wt.apply(this,arguments)}finally{bn=Hn}}}function f0(wt){switch(wt){case le:return ki;case qe:return Is;case nn:return ho;case Rt:return Io;case dt:default:return Xl}}function Jl(wt,bt,Hn){var qr=Ii.unstable_now(),Ki,Qr;if(typeof Hn=="object"&&Hn!==null){var Ou=Hn.delay;typeof Ou=="number"&&Ou>0?Ki=qr+Ou:Ki=qr,Qr=typeof Hn.timeout=="number"?Hn.timeout:f0(wt)}else Qr=f0(wt),Ki=qr;var vo=Ki+Qr,Li={id:Qo++,callback:bt,priorityLevel:wt,startTime:Ki,expirationTime:vo,sortIndex:-1};return a&&(Li.isQueued=!1),Ki>qr?(Li.sortIndex=Ki,He(Ri,Li),kt(Hr)===null&&Li===kt(Ri)&&(Vt?t():Vt=!0,_(eu,Ki-qr))):(Li.sortIndex=vo,He(Hr,Li),a&&(el(Li,qr),Li.isQueued=!0),!gi&&!Ai&&(gi=!0,c(Jo))),Li}function L0(){yi=!0}function bs(){yi=!1,!gi&&!Ai&&(gi=!0,c(Jo))}function $n(){return kt(Hr)}function tl(wt){if(a&&wt.isQueued){var bt=Ii.unstable_now();Uu(wt,bt),wt.isQueued=!1}wt.callback=null}function c0(){return bn}function bo(){var wt=Ii.unstable_now();Au(wt);var bt=kt(Hr);return bt!==en&&en!==null&&bt!==null&&bt.callback!==null&&bt.startTime<=wt&&bt.expirationTime{"use strict";process.env.NODE_ENV==="production"?FD.exports=sT():FD.exports=aT()});var fT=Ke((bW,Xy)=>{Xy.exports=function i(o){"use strict";var a=Iy(),c=Mi(),_=Q_();function t(g){for(var y="https://reactjs.org/docs/error-decoder.html?invariant="+g,R=1;RQo||(g.current=Ri[Qo],Ri[Qo]=null,Qo--)}function en(g,y){Qo++,Ri[Qo]=g.current,g.current=y}var bn={},Ai={current:bn},gi={current:!1},Vt=bn;function Au(g,y){var R=g.type.contextTypes;if(!R)return bn;var F=g.stateNode;if(F&&F.__reactInternalMemoizedUnmaskedChildContext===y)return F.__reactInternalMemoizedMaskedChildContext;var b={},J;for(J in R)b[J]=y[J];return F&&(g=g.stateNode,g.__reactInternalMemoizedUnmaskedChildContext=y,g.__reactInternalMemoizedMaskedChildContext=b),b}function eu(g){return g=g.childContextTypes,g!=null}function Jo(g){yi(gi,g),yi(Ai,g)}function Yi(g){yi(gi,g),yi(Ai,g)}function Ql(g,y,R){if(Ai.current!==bn)throw Error(t(168));en(Ai,y,g),en(gi,R,g)}function k0(g,y,R){var F=g.stateNode;if(g=y.childContextTypes,typeof F.getChildContext!="function")return R;F=F.getChildContext();for(var b in F)if(!(b in g))throw Error(t(108,Ie(y)||"Unknown",b));return a({},R,{},F)}function ai(g){var y=g.stateNode;return y=y&&y.__reactInternalMemoizedMergedChildContext||bn,Vt=Ai.current,en(Ai,y,g),en(gi,gi.current,g),!0}function f0(g,y,R){var F=g.stateNode;if(!F)throw Error(t(169));R?(y=k0(g,y,Vt),F.__reactInternalMemoizedMergedChildContext=y,yi(gi,g),yi(Ai,g),en(Ai,y,g)):yi(gi,g),en(gi,R,g)}var Jl=_.unstable_runWithPriority,L0=_.unstable_scheduleCallback,bs=_.unstable_cancelCallback,$n=_.unstable_shouldYield,tl=_.unstable_requestPaint,c0=_.unstable_now,bo=_.unstable_getCurrentPriorityLevel,Sl=_.unstable_ImmediatePriority,N0=_.unstable_UserBlockingPriority,wt=_.unstable_NormalPriority,bt=_.unstable_LowPriority,Hn=_.unstable_IdlePriority,qr={},Ki=tl!==void 0?tl:function(){},Qr=null,Ou=null,vo=!1,Li=c0(),mo=1e4>Li?c0:function(){return c0()-Li};function vs(){switch(bo()){case Sl:return 99;case N0:return 98;case wt:return 97;case bt:return 96;case Hn:return 95;default:throw Error(t(332))}}function Tt(g){switch(g){case 99:return Sl;case 98:return N0;case 97:return wt;case 96:return bt;case 95:return Hn;default:throw Error(t(332))}}function d0(g,y){return g=Tt(g),Jl(g,y)}function nl(g,y,R){return g=Tt(g),L0(g,y,R)}function Zl(g){return Qr===null?(Qr=[g],Ou=L0(Sl,ms)):Qr.push(g),qr}function ju(){if(Ou!==null){var g=Ou;Ou=null,bs(g)}ms()}function ms(){if(!vo&&Qr!==null){vo=!0;var g=0;try{var y=Qr;d0(99,function(){for(;g=y&&(h0=!0),g.firstContext=null)}function ku(g,y){if(Mu!==g&&y!==!1&&y!==0)if((typeof y!="number"||y===1073741823)&&(Mu=g,y=1073741823),y={context:g,observedBits:y,next:null},Si===null){if(cr===null)throw Error(t(308));Si=y,cr.dependencies={expirationTime:0,firstContext:y,responders:null}}else Si=Si.next=y;return ln?g._currentValue:g._currentValue2}var p0=!1;function qu(g){return{baseState:g,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Ia(g){return{baseState:g.baseState,firstUpdate:g.firstUpdate,lastUpdate:g.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function yo(g,y){return{expirationTime:g,suspenseConfig:y,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function ua(g,y){g.lastUpdate===null?g.firstUpdate=g.lastUpdate=y:(g.lastUpdate.next=y,g.lastUpdate=y)}function Zo(g,y){var R=g.alternate;if(R===null){var F=g.updateQueue,b=null;F===null&&(F=g.updateQueue=qu(g.memoizedState))}else F=g.updateQueue,b=R.updateQueue,F===null?b===null?(F=g.updateQueue=qu(g.memoizedState),b=R.updateQueue=qu(R.memoizedState)):F=g.updateQueue=Ia(b):b===null&&(b=R.updateQueue=Ia(F));b===null||F===b?ua(F,y):F.lastUpdate===null||b.lastUpdate===null?(ua(F,y),ua(b,y)):(ua(F,y),b.lastUpdate=y)}function oa(g,y){var R=g.updateQueue;R=R===null?g.updateQueue=qu(g.memoizedState):ba(g,R),R.lastCapturedUpdate===null?R.firstCapturedUpdate=R.lastCapturedUpdate=y:(R.lastCapturedUpdate.next=y,R.lastCapturedUpdate=y)}function ba(g,y){var R=g.alternate;return R!==null&&y===R.updateQueue&&(y=g.updateQueue=Ia(y)),y}function ys(g,y,R,F,b,J){switch(R.tag){case 1:return g=R.payload,typeof g=="function"?g.call(J,F,b):g;case 3:g.effectTag=g.effectTag&-4097|64;case 0:if(g=R.payload,b=typeof g=="function"?g.call(J,F,b):g,b==null)break;return a({},F,b);case 2:p0=!0}return F}function To(g,y,R,F,b){p0=!1,y=ba(g,y);for(var J=y.baseState,de=null,gt=0,xt=y.firstUpdate,Lt=J;xt!==null;){var xr=xt.expirationTime;xrci?(Qi=ur,ur=null):Qi=ur.sibling;var Gr=du(Ve,ur,lt[ci],$t);if(Gr===null){ur===null&&(ur=Qi);break}g&&ur&&Gr.alternate===null&&y(Ve,ur),ze=J(Gr,ze,ci),si===null?Wn=Gr:si.sibling=Gr,si=Gr,ur=Qi}if(ci===lt.length)return R(Ve,ur),Wn;if(ur===null){for(;cici?(Qi=ur,ur=null):Qi=ur.sibling;var Cu=du(Ve,ur,Gr.value,$t);if(Cu===null){ur===null&&(ur=Qi);break}g&&ur&&Cu.alternate===null&&y(Ve,ur),ze=J(Cu,ze,ci),si===null?Wn=Cu:si.sibling=Cu,si=Cu,ur=Qi}if(Gr.done)return R(Ve,ur),Wn;if(ur===null){for(;!Gr.done;ci++,Gr=lt.next())Gr=io(Ve,Gr.value,$t),Gr!==null&&(ze=J(Gr,ze,ci),si===null?Wn=Gr:si.sibling=Gr,si=Gr);return Wn}for(ur=F(Ve,ur);!Gr.done;ci++,Gr=lt.next())Gr=Ho(ur,Ve,ci,Gr.value,$t),Gr!==null&&(g&&Gr.alternate!==null&&ur.delete(Gr.key===null?ci:Gr.key),ze=J(Gr,ze,ci),si===null?Wn=Gr:si.sibling=Gr,si=Gr);return g&&ur.forEach(function(Va){return y(Ve,Va)}),Wn}return function(Ve,ze,lt,$t){var Wn=typeof lt=="object"&<!==null&<.type===B&<.key===null;Wn&&(lt=lt.props.children);var si=typeof lt=="object"&<!==null;if(si)switch(lt.$$typeof){case O:e:{for(si=lt.key,Wn=ze;Wn!==null;){if(Wn.key===si)if(Wn.tag===7?lt.type===B:Wn.elementType===lt.type){R(Ve,Wn.sibling),ze=b(Wn,lt.type===B?lt.props.children:lt.props,$t),ze.ref=js(Ve,Wn,lt),ze.return=Ve,Ve=ze;break e}else{R(Ve,Wn);break}else y(Ve,Wn);Wn=Wn.sibling}lt.type===B?(ze=ro(lt.props.children,Ve.mode,$t,lt.key),ze.return=Ve,Ve=ze):($t=Wa(lt.type,lt.key,lt.props,null,Ve.mode,$t),$t.ref=js(Ve,ze,lt),$t.return=Ve,Ve=$t)}return de(Ve);case T:e:{for(Wn=lt.key;ze!==null;){if(ze.key===Wn)if(ze.tag===4&&ze.stateNode.containerInfo===lt.containerInfo&&ze.stateNode.implementation===lt.implementation){R(Ve,ze.sibling),ze=b(ze,lt.children||[],$t),ze.return=Ve,Ve=ze;break e}else{R(Ve,ze);break}else y(Ve,ze);ze=ze.sibling}ze=wf(lt,Ve.mode,$t),ze.return=Ve,Ve=ze}return de(Ve)}if(typeof lt=="string"||typeof lt=="number")return lt=""+lt,ze!==null&&ze.tag===6?(R(Ve,ze.sibling),ze=b(ze,lt,$t),ze.return=Ve,Ve=ze):(R(Ve,ze),ze=zo(lt,Ve.mode,$t),ze.return=Ve,Ve=ze),de(Ve);if(go(lt))return Ml(Ve,ze,lt,$t);if(re(lt))return uo(Ve,ze,lt,$t);if(si&&ji(Ve,lt),typeof lt=="undefined"&&!Wn)switch(Ve.tag){case 1:case 0:throw Ve=Ve.type,Error(t(152,Ve.displayName||Ve.name||"Component"))}return R(Ve,ze)}}var z=U(!0),G=U(!1),$={},Ce={current:$},Ee={current:$},Ae={current:$};function Z(g){if(g===$)throw Error(t(174));return g}function ke(g,y){en(Ae,y,g),en(Ee,g,g),en(Ce,$,g),y=kt(y),yi(Ce,g),en(Ce,y,g)}function Je(g){yi(Ce,g),yi(Ee,g),yi(Ae,g)}function mt(g){var y=Z(Ae.current),R=Z(Ce.current);y=zt(R,g.type,y),R!==y&&(en(Ee,g,g),en(Ce,y,g))}function oe(g){Ee.current===g&&(yi(Ce,g),yi(Ee,g))}var We={current:0};function it(g){for(var y=g;y!==null;){if(y.tag===13){var R=y.memoizedState;if(R!==null&&(R=R.dehydrated,R===null||Xr(R)||O0(R)))return y}else if(y.tag===19&&y.memoizedProps.revealOrder!==void 0){if((y.effectTag&64)!=0)return y}else if(y.child!==null){y.child.return=y,y=y.child;continue}if(y===g)break;for(;y.sibling===null;){if(y.return===null||y.return===g)return null;y=y.return}y.sibling.return=y.return,y=y.sibling}return null}function Ct(g,y){return{responder:g,props:y}}var Mt=M.ReactCurrentDispatcher,It=M.ReactCurrentBatchConfig,sn=0,rn=null,Ft=null,Dn=null,dr=null,er=null,Cr=null,An=0,Lr=null,_o=0,Nr=!1,ut=null,Dt=0;function et(){throw Error(t(321))}function Pt(g,y){if(y===null)return!1;for(var R=0;RAn&&(An=xr,ja(An))):(dc(xr,xt.suspenseConfig),J=xt.eagerReducer===g?xt.eagerState:g(J,xt.action)),de=xt,xt=xt.next}while(xt!==null&&xt!==F);Lt||(gt=de,b=J),Ne(J,y.memoizedState)||(h0=!0),y.memoizedState=J,y.baseUpdate=gt,y.baseState=b,R.lastRenderedState=J}return[y.memoizedState,R.dispatch]}function Co(g){var y=Jn();return typeof g=="function"&&(g=g()),y.memoizedState=y.baseState=g,g=y.queue={last:null,dispatch:null,lastRenderedReducer:fu,lastRenderedState:g},g=g.dispatch=zs.bind(null,rn,g),[y.memoizedState,g]}function $o(g){return Lu(fu,g)}function Nu(g,y,R,F){return g={tag:g,create:y,destroy:R,deps:F,next:null},Lr===null?(Lr={lastEffect:null},Lr.lastEffect=g.next=g):(y=Lr.lastEffect,y===null?Lr.lastEffect=g.next=g:(R=y.next,y.next=g,g.next=R,Lr.lastEffect=g)),g}function _i(g,y,R,F){var b=Jn();_o|=g,b.memoizedState=Nu(y,R,void 0,F===void 0?null:F)}function P0(g,y,R,F){var b=wr();F=F===void 0?null:F;var J=void 0;if(Ft!==null){var de=Ft.memoizedState;if(J=de.destroy,F!==null&&Pt(F,de.deps)){Nu(0,R,J,F);return}}_o|=g,b.memoizedState=Nu(y,R,J,F)}function rl(g,y){return _i(516,192,g,y)}function vf(g,y){return P0(516,192,g,y)}function Tl(g,y){if(typeof y=="function")return g=g(),y(g),function(){y(null)};if(y!=null)return g=g(),y.current=g,function(){y.current=null}}function mf(){}function I0(g,y){return Jn().memoizedState=[g,y===void 0?null:y],g}function gs(g,y){var R=wr();y=y===void 0?null:y;var F=R.memoizedState;return F!==null&&y!==null&&Pt(y,F[1])?F[0]:(R.memoizedState=[g,y],g)}function zs(g,y,R){if(!(25>Dt))throw Error(t(301));var F=g.alternate;if(g===rn||F!==null&&F===rn)if(Nr=!0,g={expirationTime:sn,suspenseConfig:null,action:R,eagerReducer:null,eagerState:null,next:null},ut===null&&(ut=new Map),R=ut.get(y),R===void 0)ut.set(y,g);else{for(y=R;y.next!==null;)y=y.next;y.next=g}else{var b=wo(),J=fi.suspense;b=Un(b,g,J),J={expirationTime:b,suspenseConfig:J,action:R,eagerReducer:null,eagerState:null,next:null};var de=y.last;if(de===null)J.next=J;else{var gt=de.next;gt!==null&&(J.next=gt),de.next=J}if(y.last=J,g.expirationTime===0&&(F===null||F.expirationTime===0)&&(F=y.lastRenderedReducer,F!==null))try{var xt=y.lastRenderedState,Lt=F(xt,R);if(J.eagerReducer=F,J.eagerState=Lt,Ne(Lt,xt))return}catch(xr){}finally{}to(g,b)}}var b0={readContext:ku,useCallback:et,useContext:et,useEffect:et,useImperativeHandle:et,useLayoutEffect:et,useMemo:et,useReducer:et,useRef:et,useState:et,useDebugValue:et,useResponder:et,useDeferredValue:et,useTransition:et},B0={readContext:ku,useCallback:I0,useContext:ku,useEffect:rl,useImperativeHandle:function(g,y,R){return R=R!=null?R.concat([g]):null,_i(4,36,Tl.bind(null,y,g),R)},useLayoutEffect:function(g,y){return _i(4,36,g,y)},useMemo:function(g,y){var R=Jn();return y=y===void 0?null:y,g=g(),R.memoizedState=[g,y],g},useReducer:function(g,y,R){var F=Jn();return y=R!==void 0?R(y):y,F.memoizedState=F.baseState=y,g=F.queue={last:null,dispatch:null,lastRenderedReducer:g,lastRenderedState:y},g=g.dispatch=zs.bind(null,rn,g),[F.memoizedState,g]},useRef:function(g){var y=Jn();return g={current:g},y.memoizedState=g},useState:Co,useDebugValue:mf,useResponder:Ct,useDeferredValue:function(g,y){var R=Co(g),F=R[0],b=R[1];return rl(function(){_.unstable_next(function(){var J=It.suspense;It.suspense=y===void 0?null:y;try{b(g)}finally{It.suspense=J}})},[g,y]),F},useTransition:function(g){var y=Co(!1),R=y[0],F=y[1];return[I0(function(b){F(!0),_.unstable_next(function(){var J=It.suspense;It.suspense=g===void 0?null:g;try{F(!1),b()}finally{It.suspense=J}})},[g,R]),R]}},_s={readContext:ku,useCallback:gs,useContext:ku,useEffect:vf,useImperativeHandle:function(g,y,R){return R=R!=null?R.concat([g]):null,P0(4,36,Tl.bind(null,y,g),R)},useLayoutEffect:function(g,y){return P0(4,36,g,y)},useMemo:function(g,y){var R=wr();y=y===void 0?null:y;var F=R.memoizedState;return F!==null&&y!==null&&Pt(y,F[1])?F[0]:(g=g(),R.memoizedState=[g,y],g)},useReducer:Lu,useRef:function(){return wr().memoizedState},useState:$o,useDebugValue:mf,useResponder:Ct,useDeferredValue:function(g,y){var R=$o(g),F=R[0],b=R[1];return vf(function(){_.unstable_next(function(){var J=It.suspense;It.suspense=y===void 0?null:y;try{b(g)}finally{It.suspense=J}})},[g,y]),F},useTransition:function(g){var y=$o(!1),R=y[0],F=y[1];return[gs(function(b){F(!0),_.unstable_next(function(){var J=It.suspense;It.suspense=g===void 0?null:g;try{F(!1),b()}finally{It.suspense=J}})},[g,R]),R]}},Qu=null,Tu=null,Ei=!1;function xo(g,y){var R=H0(5,null,null,0);R.elementType="DELETED",R.type="DELETED",R.stateNode=y,R.return=g,R.effectTag=8,g.lastEffect!==null?(g.lastEffect.nextEffect=R,g.lastEffect=R):g.firstEffect=g.lastEffect=R}function e0(g,y){switch(g.tag){case 5:return y=Uu(y,g.type,g.pendingProps),y!==null?(g.stateNode=y,!0):!1;case 6:return y=Xo(y,g.pendingProps),y!==null?(g.stateNode=y,!0):!1;case 13:return!1;default:return!1}}function U0(g){if(Ei){var y=Tu;if(y){var R=y;if(!e0(g,y)){if(y=M0(R),!y||!e0(g,y)){g.effectTag=g.effectTag&-1025|2,Ei=!1,Qu=g;return}xo(Qu,R)}Qu=g,Tu=Po(y)}else g.effectTag=g.effectTag&-1025|2,Ei=!1,Qu=g}}function sa(g){for(g=g.return;g!==null&&g.tag!==5&&g.tag!==3&&g.tag!==13;)g=g.return;Qu=g}function es(g){if(!w||g!==Qu)return!1;if(!Ei)return sa(g),Ei=!0,!1;var y=g.type;if(g.tag!==5||y!=="head"&&y!=="body"&&!dt(y,g.memoizedProps))for(y=Tu;y;)xo(g,y),y=M0(y);if(sa(g),g.tag===13){if(!w)throw Error(t(316));if(g=g.memoizedState,g=g!==null?g.dehydrated:null,!g)throw Error(t(317));Tu=Is(g)}else Tu=Qu?M0(g.stateNode):null;return!0}function tu(){w&&(Tu=Qu=null,Ei=!1)}var ei=M.ReactCurrentOwner,h0=!1;function Bi(g,y,R,F){y.child=g===null?G(y,null,R,F):z(y,g.child,R,F)}function Ci(g,y,R,F,b){R=R.render;var J=y.ref;return F0(y,b),F=un(g,y,R,F,J,b),g!==null&&!h0?(y.updateQueue=g.updateQueue,y.effectTag&=-517,g.expirationTime<=b&&(g.expirationTime=0),yu(g,y,b)):(y.effectTag|=1,Bi(g,y,F,b),y.child)}function yf(g,y,R,F,b,J){if(g===null){var de=R.type;return typeof de=="function"&&!Df(de)&&de.defaultProps===void 0&&R.compare===null&&R.defaultProps===void 0?(y.tag=15,y.type=de,gf(g,y,de,F,b,J)):(g=Wa(R.type,null,F,null,y.mode,J),g.ref=y.ref,g.return=y,y.child=g)}return de=g.child,by)&&Vr.set(g,y)))}}function i0(g,y){g.expirationTimeg?y:g)}function no(g){if(g.lastExpiredTime!==0)g.callbackExpirationTime=1073741823,g.callbackPriority=99,g.callbackNode=Zl(u0.bind(null,g));else{var y=m0(g),R=g.callbackNode;if(y===0)R!==null&&(g.callbackNode=null,g.callbackExpirationTime=0,g.callbackPriority=90);else{var F=wo();if(y===1073741823?F=99:y===1||y===2?F=95:(F=10*(1073741821-y)-10*(1073741821-F),F=0>=F?99:250>=F?98:5250>=F?97:95),R!==null){var b=g.callbackPriority;if(g.callbackExpirationTime===y&&b>=F)return;R!==qr&&bs(R)}g.callbackExpirationTime=y,g.callbackPriority=F,y=y===1073741823?Zl(u0.bind(null,g)):nl(F,j0.bind(null,g),{timeout:10*(1073741821-y)-mo()}),g.callbackNode=y}}}function j0(g,y){if(ru=0,y)return y=wo(),pa(g,y),no(g),null;var R=m0(g);if(R!==0){if(y=g.callbackNode,(Fn&(nu|cu))!==Rr)throw Error(t(327));if(Ws(),g===ae&&R===Fe||ws(g,R),ie!==null){var F=Fn;Fn|=nu;var b=jo(g);do try{rd();break}catch(gt){ca(g,gt)}while(1);if(zu(),Fn=F,$u.current=b,Oe===ni)throw y=st,ws(g,R),Ol(g,R),no(g),y;if(ie===null)switch(b=g.finishedWork=g.current.alternate,g.finishedExpirationTime=R,F=Oe,ae=null,F){case Ni:case ni:throw Error(t(345));case Kn:pa(g,2=R){g.lastPingedTime=R,ws(g,R);break}}if(J=m0(g),J!==0&&J!==R)break;if(F!==0&&F!==R){g.lastPingedTime=F;break}g.timeoutHandle=an(Rl.bind(null,g),b);break}Rl(g);break;case Eo:if(Ol(g,R),F=g.lastSuspendedTime,R===F&&(g.nextKnownPendingLevel=qc(b)),_n&&(b=g.lastPingedTime,b===0||b>=R)){g.lastPingedTime=R,ws(g,R);break}if(b=m0(g),b!==0&&b!==R)break;if(F!==0&&F!==R){g.lastPingedTime=F;break}if(Jt!==1073741823?F=10*(1073741821-Jt)-mo():yt===1073741823?F=0:(F=10*(1073741821-yt)-5e3,b=mo(),R=10*(1073741821-R)-b,F=b-F,0>F&&(F=0),F=(120>F?120:480>F?480:1080>F?1080:1920>F?1920:3e3>F?3e3:4320>F?4320:1960*_f(F/1960))-F,R=F?F=0:(b=de.busyDelayMs|0,J=mo()-(10*(1073741821-J)-(de.timeoutMs|0||5e3)),F=J<=b?0:b+F-J),10 component higher in the tree to provide a loading indicator or placeholder to display.`+Hr(b))}Oe!==Do&&(Oe=Kn),J=Cl(J,b),xt=F;do{switch(xt.tag){case 3:de=J,xt.effectTag|=4096,xt.expirationTime=y;var ze=Es(xt,de,y);oa(xt,ze);break e;case 1:de=J;var lt=xt.type,$t=xt.stateNode;if((xt.effectTag&64)==0&&(typeof lt.getDerivedStateFromError=="function"||$t!==null&&typeof $t.componentDidCatch=="function"&&(mr===null||!mr.has($t)))){xt.effectTag|=4096,xt.expirationTime=y;var Wn=fa(xt,de,y);oa(xt,Wn);break e}}xt=xt.return}while(xt!==null)}ie=y0(ie)}catch(si){y=si;continue}break}while(1)}function jo(){var g=$u.current;return $u.current=b0,g===null?b0:g}function dc(g,y){gSn&&(Sn=g)}function D2(){for(;ie!==null;)ie=id(ie)}function rd(){for(;ie!==null&&!$n();)ie=id(ie)}function id(g){var y=qa(g.alternate,g,Fe);return g.memoizedProps=g.pendingProps,y===null&&(y=y0(g)),Ds.current=null,y}function y0(g){ie=g;do{var y=ie.alternate;if(g=ie.return,(ie.effectTag&2048)==0){e:{var R=y;y=ie;var F=Fe,b=y.pendingProps;switch(y.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:eu(y.type)&&Jo(y);break;case 3:Je(y),Yi(y),b=y.stateNode,b.pendingContext&&(b.context=b.pendingContext,b.pendingContext=null),(R===null||R.child===null)&&es(y)&&Ju(y),Jr(y);break;case 5:oe(y);var J=Z(Ae.current);if(F=y.type,R!==null&&y.stateNode!=null)Wu(R,y,F,b,J),R.ref!==y.ref&&(y.effectTag|=128);else if(b){if(R=Z(Ce.current),es(y)){if(b=y,!w)throw Error(t(175));R=au(b.stateNode,b.type,b.memoizedProps,J,R,b),b.updateQueue=R,R=R!==null,R&&Ju(y)}else{var de=fe(F,b,J,R,y);ti(de,y,!1,!1),y.stateNode=de,le(de,F,b,J,R)&&Ju(y)}y.ref!==null&&(y.effectTag|=128)}else if(y.stateNode===null)throw Error(t(166));break;case 6:if(R&&y.stateNode!=null)Rn(R,y,R.memoizedProps,b);else{if(typeof b!="string"&&y.stateNode===null)throw Error(t(166));if(R=Z(Ae.current),J=Z(Ce.current),es(y)){if(R=y,!w)throw Error(t(176));(R=ki(R.stateNode,R.memoizedProps,R))&&Ju(y)}else y.stateNode=nn(b,R,J,y)}break;case 11:break;case 13:if(yi(We,y),b=y.memoizedState,(y.effectTag&64)!=0){y.expirationTime=F;break e}b=b!==null,J=!1,R===null?y.memoizedProps.fallback!==void 0&&es(y):(F=R.memoizedState,J=F!==null,b||F===null||(F=R.child.sibling,F!==null&&(de=y.firstEffect,de!==null?(y.firstEffect=F,F.nextEffect=de):(y.firstEffect=y.lastEffect=F,F.nextEffect=null),F.effectTag=8))),b&&!J&&(y.mode&2)!=0&&(R===null&&y.memoizedProps.unstable_avoidThisFallback!==!0||(We.current&1)!=0?Oe===Ni&&(Oe=eo):((Oe===Ni||Oe===eo)&&(Oe=Eo),Sn!==0&&ae!==null&&(Ol(ae,Fe),Cs(ae,Sn)))),Er&&b&&(y.effectTag|=4),Gt&&(b||J)&&(y.effectTag|=4);break;case 7:break;case 8:break;case 12:break;case 4:Je(y),Jr(y);break;case 10:Su(y);break;case 9:break;case 14:break;case 17:eu(y.type)&&Jo(y);break;case 19:if(yi(We,y),b=y.memoizedState,b===null)break;if(J=(y.effectTag&64)!=0,de=b.rendering,de===null){if(J)Fu(b,!1);else if(Oe!==Ni||R!==null&&(R.effectTag&64)!=0)for(R=y.child;R!==null;){if(de=it(R),de!==null){for(y.effectTag|=64,Fu(b,!1),R=de.updateQueue,R!==null&&(y.updateQueue=R,y.effectTag|=4),b.lastEffect===null&&(y.firstEffect=null),y.lastEffect=b.lastEffect,R=F,b=y.child;b!==null;)J=b,F=R,J.effectTag&=2,J.nextEffect=null,J.firstEffect=null,J.lastEffect=null,de=J.alternate,de===null?(J.childExpirationTime=0,J.expirationTime=F,J.child=null,J.memoizedProps=null,J.memoizedState=null,J.updateQueue=null,J.dependencies=null):(J.childExpirationTime=de.childExpirationTime,J.expirationTime=de.expirationTime,J.child=de.child,J.memoizedProps=de.memoizedProps,J.memoizedState=de.memoizedState,J.updateQueue=de.updateQueue,F=de.dependencies,J.dependencies=F===null?null:{expirationTime:F.expirationTime,firstContext:F.firstContext,responders:F.responders}),b=b.sibling;en(We,We.current&1|2,y),y=y.child;break e}R=R.sibling}}else{if(!J)if(R=it(de),R!==null){if(y.effectTag|=64,J=!0,R=R.updateQueue,R!==null&&(y.updateQueue=R,y.effectTag|=4),Fu(b,!0),b.tail===null&&b.tailMode==="hidden"&&!de.alternate){y=y.lastEffect=b.lastEffect,y!==null&&(y.nextEffect=null);break}}else mo()>b.tailExpiration&&1b&&(b=F),de>b&&(b=de),J=J.sibling;R.childExpirationTime=b}if(y!==null)return y;g!==null&&(g.effectTag&2048)==0&&(g.firstEffect===null&&(g.firstEffect=ie.firstEffect),ie.lastEffect!==null&&(g.lastEffect!==null&&(g.lastEffect.nextEffect=ie.firstEffect),g.lastEffect=ie.lastEffect),1g?y:g}function Rl(g){var y=vs();return d0(99,ul.bind(null,g,y)),null}function ul(g,y){do Ws();while(ri!==null);if((Fn&(nu|cu))!==Rr)throw Error(t(327));var R=g.finishedWork,F=g.finishedExpirationTime;if(R===null)return null;if(g.finishedWork=null,g.finishedExpirationTime=0,R===g.current)throw Error(t(177));g.callbackNode=null,g.callbackExpirationTime=0,g.callbackPriority=90,g.nextKnownPendingLevel=0;var b=qc(R);if(g.firstPendingTime=b,F<=g.lastSuspendedTime?g.firstSuspendedTime=g.lastSuspendedTime=g.nextKnownPendingLevel=0:F<=g.firstSuspendedTime&&(g.firstSuspendedTime=F-1),F<=g.lastPingedTime&&(g.lastPingedTime=0),F<=g.lastExpiredTime&&(g.lastExpiredTime=0),g===ae&&(ie=ae=null,Fe=0),1=R?Xt(g,y,R):(en(We,We.current&1,y),y=yu(g,y,R),y!==null?y.sibling:null);en(We,We.current&1,y);break;case 19:if(F=y.childExpirationTime>=R,(g.effectTag&64)!=0){if(F)return xn(g,y,R);y.effectTag|=64}if(b=y.memoizedState,b!==null&&(b.rendering=null,b.tail=null),en(We,We.current,y),!F)return null}return yu(g,y,R)}h0=!1}}else h0=!1;switch(y.expirationTime=0,y.tag){case 2:if(F=y.type,g!==null&&(g.alternate=null,y.alternate=null,y.effectTag|=2),g=y.pendingProps,b=Au(y,Ai.current),F0(y,R),b=un(null,y,F,g,b,R),y.effectTag|=1,typeof b=="object"&&b!==null&&typeof b.render=="function"&&b.$$typeof===void 0){if(y.tag=1,fn(),eu(F)){var J=!0;ai(y)}else J=!1;y.memoizedState=b.state!==null&&b.state!==void 0?b.state:null;var de=F.getDerivedStateFromProps;typeof de=="function"&&$l(y,F,de,g),b.updater=la,y.stateNode=b,b._reactInternalFiber=y,Us(y,F,g,R),y=rt(null,y,F,!0,J,R)}else y.tag=0,Bi(null,y,b,R),y=y.child;return y;case 16:if(b=y.elementType,g!==null&&(g.alternate=null,y.alternate=null,y.effectTag|=2),g=y.pendingProps,we(b),b._status!==1)throw b._result;switch(b=b._result,y.type=b,J=y.tag=ol(b),g=Yn(b,g),J){case 0:y=n0(null,y,b,g,R);break;case 1:y=Re(null,y,b,g,R);break;case 11:y=Ci(null,y,b,g,R);break;case 14:y=yf(null,y,b,Yn(b.type,g),F,R);break;default:throw Error(t(306,b,""))}return y;case 0:return F=y.type,b=y.pendingProps,b=y.elementType===F?b:Yn(F,b),n0(g,y,F,b,R);case 1:return F=y.type,b=y.pendingProps,b=y.elementType===F?b:Yn(F,b),Re(g,y,F,b,R);case 3:if(Ye(y),F=y.updateQueue,F===null)throw Error(t(282));if(b=y.memoizedState,b=b!==null?b.element:null,To(y,F,y.pendingProps,null,R),F=y.memoizedState.element,F===b)tu(),y=yu(g,y,R);else{if((b=y.stateNode.hydrate)&&(w?(Tu=Po(y.stateNode.containerInfo),Qu=y,b=Ei=!0):b=!1),b)for(R=G(y,null,F,R),y.child=R;R;)R.effectTag=R.effectTag&-3|1024,R=R.sibling;else Bi(g,y,F,R),tu();y=y.child}return y;case 5:return mt(y),g===null&&U0(y),F=y.type,b=y.pendingProps,J=g!==null?g.memoizedProps:null,de=b.children,dt(F,b)?de=null:J!==null&&dt(F,J)&&(y.effectTag|=16),t0(g,y),y.mode&4&&R!==1&&Rt(F,b)?(y.expirationTime=y.childExpirationTime=1,y=null):(Bi(g,y,de,R),y=y.child),y;case 6:return g===null&&U0(y),null;case 13:return Xt(g,y,R);case 4:return ke(y,y.stateNode.containerInfo),F=y.pendingProps,g===null?y.child=z(y,null,F,R):Bi(g,y,F,R),y.child;case 11:return F=y.type,b=y.pendingProps,b=y.elementType===F?b:Yn(F,b),Ci(g,y,F,b,R);case 7:return Bi(g,y,y.pendingProps,R),y.child;case 8:return Bi(g,y,y.pendingProps.children,R),y.child;case 12:return Bi(g,y,y.pendingProps.children,R),y.child;case 10:e:{if(F=y.type._context,b=y.pendingProps,de=y.memoizedProps,J=b.value,Hu(y,J),de!==null){var gt=de.value;if(J=Ne(gt,J)?0:(typeof F._calculateChangedBits=="function"?F._calculateChangedBits(gt,J):1073741823)|0,J===0){if(de.children===b.children&&!gi.current){y=yu(g,y,R);break e}}else for(gt=y.child,gt!==null&&(gt.return=y);gt!==null;){var xt=gt.dependencies;if(xt!==null){de=gt.child;for(var Lt=xt.firstContext;Lt!==null;){if(Lt.context===F&&(Lt.observedBits&J)!=0){gt.tag===1&&(Lt=yo(R,null),Lt.tag=2,Zo(gt,Lt)),gt.expirationTime=y&&g<=y}function Ol(g,y){var R=g.firstSuspendedTime,F=g.lastSuspendedTime;Ry||R===0)&&(g.lastSuspendedTime=y),y<=g.lastPingedTime&&(g.lastPingedTime=0),y<=g.lastExpiredTime&&(g.lastExpiredTime=0)}function Cs(g,y){y>g.firstPendingTime&&(g.firstPendingTime=y);var R=g.firstSuspendedTime;R!==0&&(y>=R?g.firstSuspendedTime=g.lastSuspendedTime=g.nextKnownPendingLevel=0:y>=g.lastSuspendedTime&&(g.lastSuspendedTime=y+1),y>g.nextKnownPendingLevel&&(g.nextKnownPendingLevel=y))}function pa(g,y){var R=g.lastExpiredTime;(R===0||R>y)&&(g.lastExpiredTime=y)}function od(g){var y=g._reactInternalFiber;if(y===void 0)throw typeof g.render=="function"?Error(t(188)):Error(t(268,Object.keys(g)));return g=Xe(y),g===null?null:g.stateNode}function ha(g,y){g=g.memoizedState,g!==null&&g.dehydrated!==null&&g.retryTime{"use strict";Object.defineProperty(tc,"__esModule",{value:!0});var jI=0;tc.__interactionsRef=null;tc.__subscriberRef=null;tc.unstable_clear=function(i){return i()};tc.unstable_getCurrent=function(){return null};tc.unstable_getThreadID=function(){return++jI};tc.unstable_trace=function(i,o,a){return a()};tc.unstable_wrap=function(i){return i};tc.unstable_subscribe=function(){};tc.unstable_unsubscribe=function(){}});var dT=Ke(mu=>{"use strict";process.env.NODE_ENV!=="production"&&function(){"use strict";Object.defineProperty(mu,"__esModule",{value:!0});var i=!0,o=0,a=0,c=0;mu.__interactionsRef=null,mu.__subscriberRef=null,i&&(mu.__interactionsRef={current:new Set},mu.__subscriberRef={current:null});function _(ue){if(!i)return ue();var _e=mu.__interactionsRef.current;mu.__interactionsRef.current=new Set;try{return ue()}finally{mu.__interactionsRef.current=_e}}function t(){return i?mu.__interactionsRef.current:null}function M(){return++c}function N(ue,_e,ce){var me=arguments.length>3&&arguments[3]!==void 0?arguments[3]:o;if(!i)return ce();var re={__count:1,id:a++,name:ue,timestamp:_e},we=mu.__interactionsRef.current,Ie=new Set(we);Ie.add(re),mu.__interactionsRef.current=Ie;var je=mu.__subscriberRef.current,ct;try{je!==null&&je.onInteractionTraced(re)}finally{try{je!==null&&je.onWorkStarted(Ie,me)}finally{try{ct=ce()}finally{mu.__interactionsRef.current=we;try{je!==null&&je.onWorkStopped(Ie,me)}finally{re.__count--,je!==null&&re.__count===0&&je.onInteractionScheduledWorkCompleted(re)}}}}return ct}function O(ue){var _e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:o;if(!i)return ue;var ce=mu.__interactionsRef.current,me=mu.__subscriberRef.current;me!==null&&me.onWorkScheduled(ce,_e),ce.forEach(function(Ie){Ie.__count++});var re=!1;function we(){var Ie=mu.__interactionsRef.current;mu.__interactionsRef.current=ce,me=mu.__subscriberRef.current;try{var je;try{me!==null&&me.onWorkStarted(ce,_e)}finally{try{je=ue.apply(void 0,arguments)}finally{mu.__interactionsRef.current=Ie,me!==null&&me.onWorkStopped(ce,_e)}}return je}finally{re||(re=!0,ce.forEach(function(ct){ct.__count--,me!==null&&ct.__count===0&&me.onInteractionScheduledWorkCompleted(ct)}))}}return we.cancel=function(){me=mu.__subscriberRef.current;try{me!==null&&me.onWorkCanceled(ce,_e)}finally{ce.forEach(function(je){je.__count--,me&&je.__count===0&&me.onInteractionScheduledWorkCompleted(je)})}},we}var T=null;i&&(T=new Set);function B(ue){i&&(T.add(ue),T.size===1&&(mu.__subscriberRef.current={onInteractionScheduledWorkCompleted:ne,onInteractionTraced:q,onWorkCanceled:ve,onWorkScheduled:m,onWorkStarted:pe,onWorkStopped:ge}))}function H(ue){i&&(T.delete(ue),T.size===0&&(mu.__subscriberRef.current=null))}function q(ue){var _e=!1,ce=null;if(T.forEach(function(me){try{me.onInteractionTraced(ue)}catch(re){_e||(_e=!0,ce=re)}}),_e)throw ce}function ne(ue){var _e=!1,ce=null;if(T.forEach(function(me){try{me.onInteractionScheduledWorkCompleted(ue)}catch(re){_e||(_e=!0,ce=re)}}),_e)throw ce}function m(ue,_e){var ce=!1,me=null;if(T.forEach(function(re){try{re.onWorkScheduled(ue,_e)}catch(we){ce||(ce=!0,me=we)}}),ce)throw me}function pe(ue,_e){var ce=!1,me=null;if(T.forEach(function(re){try{re.onWorkStarted(ue,_e)}catch(we){ce||(ce=!0,me=we)}}),ce)throw me}function ge(ue,_e){var ce=!1,me=null;if(T.forEach(function(re){try{re.onWorkStopped(ue,_e)}catch(we){ce||(ce=!0,me=we)}}),ce)throw me}function ve(ue,_e){var ce=!1,me=null;if(T.forEach(function(re){try{re.onWorkCanceled(ue,_e)}catch(we){ce||(ce=!0,me=we)}}),ce)throw me}mu.unstable_clear=_,mu.unstable_getCurrent=t,mu.unstable_getThreadID=M,mu.unstable_trace=N,mu.unstable_wrap=O,mu.unstable_subscribe=B,mu.unstable_unsubscribe=H}()});var pT=Ke((jW,PD)=>{"use strict";process.env.NODE_ENV==="production"?PD.exports=cT():PD.exports=dT()});var hT=Ke((zW,Qy)=>{"use strict";process.env.NODE_ENV!=="production"&&(Qy.exports=function i(o){"use strict";var a=Iy(),c=Mi(),_=hD(),t=Q_(),M=pT(),N=0,O=1,T=2,B=3,H=4,q=5,ne=6,m=7,pe=8,ge=9,ve=10,ue=11,_e=12,ce=13,me=14,re=15,we=16,Ie=17,je=18,ct=19,pt=20,Xe=21,tt=function(){};tt=function(f,d){for(var E=arguments.length,C=new Array(E>2?E-2:0),A=2;A8)throw new Error("warningWithoutStack() currently supports at most 8 arguments.");if(!f){if(typeof console!="undefined"){var j=C.map(function(se){return""+se});j.unshift("Warning: "+d),Function.prototype.apply.call(console.error,console,j)}try{var V=0,te="Warning: "+d.replace(/%s/g,function(){return C[V++]});throw new Error(te)}catch(se){}}};var He=tt;function kt(f){return f._reactInternalFiber}function zt(f,d){f._reactInternalFiber=d}var nt=c.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;nt.hasOwnProperty("ReactCurrentDispatcher")||(nt.ReactCurrentDispatcher={current:null}),nt.hasOwnProperty("ReactCurrentBatchConfig")||(nt.ReactCurrentBatchConfig={suspense:null});var X=typeof Symbol=="function"&&Symbol.for,fe=X?Symbol.for("react.element"):60103,xe=X?Symbol.for("react.portal"):60106,le=X?Symbol.for("react.fragment"):60107,qe=X?Symbol.for("react.strict_mode"):60108,dt=X?Symbol.for("react.profiler"):60114,Rt=X?Symbol.for("react.provider"):60109,nn=X?Symbol.for("react.context"):60110,an=X?Symbol.for("react.concurrent_mode"):60111,Mn=X?Symbol.for("react.forward_ref"):60112,lr=X?Symbol.for("react.suspense"):60113,ln=X?Symbol.for("react.suspense_list"):60120,Gt=X?Symbol.for("react.memo"):60115,Er=X?Symbol.for("react.lazy"):60116,w=X?Symbol.for("react.fundamental"):60117,jt=X?Symbol.for("react.responder"):60118,Xn=X?Symbol.for("react.scope"):60119,vr=typeof Symbol=="function"&&Symbol.iterator,jr="@@iterator";function fr(f){if(f===null||typeof f!="object")return null;var d=vr&&f[vr]||f[jr];return typeof d=="function"?d:null}var zr=He;zr=function(f,d){if(!f){for(var E=nt.ReactDebugCurrentFrame,C=E.getStackAddendum(),A=arguments.length,j=new Array(A>2?A-2:0),V=2;V import('./MyComponent'))`,C),f._status=A0,f._result=A}},function(C){f._status===po&&(f._status=J0,f._result=C)})}}function $0(f,d,E){var C=d.displayName||d.name||"";return f.displayName||(C!==""?E+"("+C+")":E)}function Wt(f){if(f==null)return null;if(typeof f.tag=="number"&&He(!1,"Received an unexpected object in getComponentName(). This is likely a bug in React. Please file an issue."),typeof f=="function")return f.displayName||f.name||null;if(typeof f=="string")return f;switch(f){case le:return"Fragment";case xe:return"Portal";case dt:return"Profiler";case qe:return"StrictMode";case lr:return"Suspense";case ln:return"SuspenseList"}if(typeof f=="object")switch(f.$$typeof){case nn:return"Context.Consumer";case Rt:return"Context.Provider";case Mn:return $0(f,f.render,"ForwardRef");case Gt:return Wt(f.type);case Er:{var d=f,E=Ps(d);if(E)return Wt(E);break}}return null}var xi=0,su=1,mi=2,Dr=4,el=6,Ko=8,Uu=16,Xo=32,Xr=64,O0=128,M0=256,Po=512,au=1024,ki=1028,Is=932,Xl=2047,Io=2048,ho=4096,Hr=!0,Ri=!0,Qo=!0,yi=!0,en=!0,bn=!0,Ai=!1,gi=!1,Vt=!1,Au=!1,eu=!1,Jo=!0,Yi=!1,Ql=!1,k0=!1,ai=!1,f0=!1,Jl=nt.ReactCurrentOwner;function L0(f){var d=f,E=f;if(f.alternate)for(;d.return;)d=d.return;else{var C=d;do d=C,(d.effectTag&(mi|au))!==xi&&(E=d.return),C=d.return;while(C)}return d.tag===B?E:null}function bs(f){return L0(f)===f}function $n(f){{var d=Jl.current;if(d!==null&&d.tag===O){var E=d,C=E.stateNode;C._warnedAboutRefsInRender||He(!1,"%s is accessing isMounted inside its render() function. render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead.",Wt(E.type)||"A component"),C._warnedAboutRefsInRender=!0}}var A=kt(f);return A?L0(A)===A:!1}function tl(f){if(L0(f)!==f)throw Error("Unable to find node on an unmounted component.")}function c0(f){var d=f.alternate;if(!d){var E=L0(f);if(E===null)throw Error("Unable to find node on an unmounted component.");return E!==f?null:f}for(var C=f,A=d;;){var j=C.return;if(j===null)break;var V=j.alternate;if(V===null){var te=j.return;if(te!==null){C=A=te;continue}break}if(j.child===V.child){for(var se=j.child;se;){if(se===C)return tl(j),f;if(se===A)return tl(j),d;se=se.sibling}throw Error("Unable to find node on an unmounted component.")}if(C.return!==A.return)C=j,A=V;else{for(var Ue=!1,Qe=j.child;Qe;){if(Qe===C){Ue=!0,C=j,A=V;break}if(Qe===A){Ue=!0,A=j,C=V;break}Qe=Qe.sibling}if(!Ue){for(Qe=V.child;Qe;){if(Qe===C){Ue=!0,C=V,A=j;break}if(Qe===A){Ue=!0,A=V,C=j;break}Qe=Qe.sibling}if(!Ue)throw Error("Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.")}}if(C.alternate!==A)throw Error("Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue.")}if(C.tag!==B)throw Error("Unable to find node on an unmounted component.");return C.stateNode.current===C?f:d}function bo(f){var d=c0(f);if(!d)return null;for(var E=d;;){if(E.tag===q||E.tag===ne)return E;if(E.child){E.child.return=E,E=E.child;continue}if(E===d)return null;for(;!E.sibling;){if(!E.return||E.return===d)return null;E=E.return}E.sibling.return=E.return,E=E.sibling}return null}function Sl(f){var d=c0(f);if(!d)return null;for(var E=d;;){if(E.tag===q||E.tag===ne||Vt&&E.tag===pt)return E;if(E.child&&E.tag!==H){E.child.return=E,E=E.child;continue}if(E===d)return null;for(;!E.sibling;){if(!E.return||E.return===d)return null;E=E.return}E.sibling.return=E.return,E=E.sibling}return null}var N0=o.getPublicInstance,wt=o.getRootHostContext,bt=o.getChildHostContext,Hn=o.prepareForCommit,qr=o.resetAfterCommit,Ki=o.createInstance,Qr=o.appendInitialChild,Ou=o.finalizeInitialChildren,vo=o.prepareUpdate,Li=o.shouldSetTextContent,mo=o.shouldDeprioritizeSubtree,vs=o.createTextInstance,Tt=o.setTimeout,d0=o.clearTimeout,nl=o.noTimeout,Zl=o.now,ju=o.isPrimaryRenderer,ms=o.warnsIfNotActing,Bo=o.supportsMutation,Q=o.supportsPersistence,Se=o.supportsHydration,Ne=o.mountResponderInstance,Le=o.unmountResponderInstance,ht=o.getFundamentalComponentInstance,Yn=o.mountFundamentalComponent,Cn=o.shouldUpdateFundamentalComponent,cr=o.getInstanceFromNode,Si=o.appendChild,Mu=o.appendChildToContainer,zu=o.commitTextUpdate,Hu=o.commitMount,Su=o.commitUpdate,Ti=o.insertBefore,F0=o.insertInContainerBefore,ku=o.removeChild,p0=o.removeChildFromContainer,qu=o.resetTextContent,Ia=o.hideInstance,yo=o.hideTextInstance,ua=o.unhideInstance,Zo=o.unhideTextInstance,oa=o.updateFundamentalComponent,ba=o.unmountFundamentalComponent,ys=o.cloneInstance,To=o.createContainerChildSet,Qn=o.appendChildToContainerChildSet,fc=o.finalizeContainerChildren,fi=o.replaceContainerChildren,$r=o.cloneHiddenInstance,$l=o.cloneHiddenTextInstance,la=o.cloneInstance,hf=o.canHydrateInstance,Bs=o.canHydrateTextInstance,Ba=o.canHydrateSuspenseInstance,Us=o.isSuspenseInstancePending,go=o.isSuspenseInstanceFallback,js=o.registerSuspenseInstanceRetry,ji=o.getNextHydratableSibling,U=o.getFirstHydratableChild,z=o.hydrateInstance,G=o.hydrateTextInstance,$=o.hydrateSuspenseInstance,Ce=o.getNextHydratableInstanceAfterSuspenseInstance,Ee=o.commitHydratedContainer,Ae=o.commitHydratedSuspenseInstance,Z=o.clearSuspenseBoundary,ke=o.clearSuspenseBoundaryFromContainer,Je=o.didNotMatchHydratedContainerTextInstance,mt=o.didNotMatchHydratedTextInstance,oe=o.didNotHydrateContainerInstance,We=o.didNotHydrateInstance,it=o.didNotFindHydratableContainerInstance,Ct=o.didNotFindHydratableContainerTextInstance,Mt=o.didNotFindHydratableContainerSuspenseInstance,It=o.didNotFindHydratableInstance,sn=o.didNotFindHydratableTextInstance,rn=o.didNotFindHydratableSuspenseInstance,Ft=/^(.*)[\\\/]/,Dn=function(f,d,E){var C="";if(d){var A=d.fileName,j=A.replace(Ft,"");if(/^index\./.test(j)){var V=A.match(Ft);if(V){var te=V[1];if(te){var se=te.replace(Ft,"");j=se+"/"+j}}}C=" (at "+j+":"+d.lineNumber+")"}else E&&(C=" (created by "+E+")");return` - in `+(f||"Unknown")+C},dr=nt.ReactDebugCurrentFrame;function er(f){switch(f.tag){case B:case H:case ne:case m:case ve:case ge:return"";default:var d=f._debugOwner,E=f._debugSource,C=Wt(f.type),A=null;return d&&(A=Wt(d.type)),Dn(C,E,A)}}function Cr(f){var d="",E=f;do d+=er(E),E=E.return;while(E);return d}var An=null,Lr=null;function _o(){{if(An===null)return null;var f=An._debugOwner;if(f!==null&&typeof f!="undefined")return Wt(f.type)}return null}function Nr(){return An===null?"":Cr(An)}function ut(){dr.getCurrentStack=null,An=null,Lr=null}function Dt(f){dr.getCurrentStack=Nr,An=f,Lr=null}function et(f){Lr=f}var Pt="\u269B",un="\u26D4",fn=typeof performance!="undefined"&&typeof performance.mark=="function"&&typeof performance.clearMarks=="function"&&typeof performance.measure=="function"&&typeof performance.clearMeasures=="function",Jn=null,wr=null,fu=null,Lu=!1,Co=!1,$o=!1,Nu=0,_i=0,P0=new Set,rl=function(f){return Pt+" "+f},vf=function(f,d){var E=d?un+" ":Pt+" ",C=d?" Warning: "+d:"";return""+E+f+C},Tl=function(f){performance.mark(rl(f))},mf=function(f){performance.clearMarks(rl(f))},I0=function(f,d,E){var C=rl(d),A=vf(f,E);try{performance.measure(A,C)}catch(j){}performance.clearMarks(C),performance.clearMeasures(A)},gs=function(f,d){return f+" (#"+d+")"},zs=function(f,d,E){return E===null?f+" ["+(d?"update":"mount")+"]":f+"."+E},b0=function(f,d){var E=Wt(f.type)||"Unknown",C=f._debugID,A=f.alternate!==null,j=zs(E,A,d);if(Lu&&P0.has(j))return!1;P0.add(j);var V=gs(j,C);return Tl(V),!0},B0=function(f,d){var E=Wt(f.type)||"Unknown",C=f._debugID,A=f.alternate!==null,j=zs(E,A,d),V=gs(j,C);mf(V)},_s=function(f,d,E){var C=Wt(f.type)||"Unknown",A=f._debugID,j=f.alternate!==null,V=zs(C,j,d),te=gs(V,A);I0(V,te,E)},Qu=function(f){switch(f.tag){case B:case q:case ne:case H:case m:case ve:case ge:case pe:return!0;default:return!1}},Tu=function(){wr!==null&&fu!==null&&B0(fu,wr),fu=null,wr=null,$o=!1},Ei=function(){for(var f=Jn;f;)f._debugIsCurrentlyTiming&&_s(f,null,null),f=f.return},xo=function(f){f.return!==null&&xo(f.return),f._debugIsCurrentlyTiming&&b0(f,null)},e0=function(){Jn!==null&&xo(Jn)};function U0(){Hr&&_i++}function sa(){Hr&&(Lu&&(Co=!0),wr!==null&&wr!=="componentWillMount"&&wr!=="componentWillReceiveProps"&&($o=!0))}function es(f){if(Hr){if(!fn||Qu(f)||(Jn=f,!b0(f,null)))return;f._debugIsCurrentlyTiming=!0}}function tu(f){if(Hr){if(!fn||Qu(f))return;f._debugIsCurrentlyTiming=!1,B0(f,null)}}function ei(f){if(Hr){if(!fn||Qu(f)||(Jn=f.return,!f._debugIsCurrentlyTiming))return;f._debugIsCurrentlyTiming=!1,_s(f,null,null)}}function h0(f){if(Hr){if(!fn||Qu(f)||(Jn=f.return,!f._debugIsCurrentlyTiming))return;f._debugIsCurrentlyTiming=!1;var d=f.tag===ce?"Rendering was suspended":"An error was thrown inside this error boundary";_s(f,null,d)}}function Bi(f,d){if(Hr){if(!fn||(Tu(),!b0(f,d)))return;fu=f,wr=d}}function Ci(){if(Hr){if(!fn)return;if(wr!==null&&fu!==null){var f=$o?"Scheduled a cascading update":null;_s(fu,wr,f)}wr=null,fu=null}}function yf(f){if(Hr){if(Jn=f,!fn)return;Nu=0,Tl("(React Tree Reconciliation)"),e0()}}function gf(f,d){if(Hr){if(!fn)return;var E=null;if(f!==null)if(f.tag===B)E="A top-level update interrupted the previous render";else{var C=Wt(f.type)||"Unknown";E="An update to "+C+" interrupted the previous render"}else Nu>1&&(E="There were cascading updates");Nu=0;var A=d?"(React Tree Reconciliation: Completed Root)":"(React Tree Reconciliation: Yielded)";Ei(),I0(A,"(React Tree Reconciliation)",E)}}function t0(){if(Hr){if(!fn)return;Lu=!0,Co=!1,P0.clear(),Tl("(Committing Changes)")}}function n0(){if(Hr){if(!fn)return;var f=null;Co?f="Lifecycle hook scheduled a cascading update":Nu>0&&(f="Caused by a cascading update in earlier commit"),Co=!1,Nu++,Lu=!1,P0.clear(),I0("(Committing Changes)","(Committing Changes)",f)}}function Re(){if(Hr){if(!fn)return;_i=0,Tl("(Committing Snapshot Effects)")}}function rt(){if(Hr){if(!fn)return;var f=_i;_i=0,I0("(Committing Snapshot Effects: "+f+" Total)","(Committing Snapshot Effects)",null)}}function Ye(){if(Hr){if(!fn)return;_i=0,Tl("(Committing Host Effects)")}}function Kt(){if(Hr){if(!fn)return;var f=_i;_i=0,I0("(Committing Host Effects: "+f+" Total)","(Committing Host Effects)",null)}}function Xt(){if(Hr){if(!fn)return;_i=0,Tl("(Calling Lifecycle Methods)")}}function pr(){if(Hr){if(!fn)return;var f=_i;_i=0,I0("(Calling Lifecycle Methods: "+f+" Total)","(Calling Lifecycle Methods)",null)}}var Wr=[],xn;xn=[];var yu=-1;function Ju(f){return{current:f}}function ti(f,d){if(yu<0){He(!1,"Unexpected pop.");return}d!==xn[yu]&&He(!1,"Unexpected Fiber popped."),f.current=Wr[yu],Wr[yu]=null,xn[yu]=null,yu--}function Jr(f,d,E){yu++,Wr[yu]=f.current,xn[yu]=E,f.current=d}var Wu;Wu={};var Rn={};Object.freeze(Rn);var Ro=Ju(Rn),Fu=Ju(!1),li=Rn;function Cl(f,d,E){return ai?Rn:E&&Xi(d)?li:Ro.current}function Hs(f,d,E){if(!ai){var C=f.stateNode;C.__reactInternalMemoizedUnmaskedChildContext=d,C.__reactInternalMemoizedMaskedChildContext=E}}function Vu(f,d){if(ai)return Rn;var E=f.type,C=E.contextTypes;if(!C)return Rn;var A=f.stateNode;if(A&&A.__reactInternalMemoizedUnmaskedChildContext===d)return A.__reactInternalMemoizedMaskedChildContext;var j={};for(var V in C)j[V]=d[V];{var te=Wt(E)||"Unknown";_(C,j,"context",te,Nr)}return A&&Hs(f,d,j),j}function aa(){return ai?!1:Fu.current}function Xi(f){if(ai)return!1;var d=f.childContextTypes;return d!=null}function qs(f){ai||(ti(Fu,f),ti(Ro,f))}function Ao(f){ai||(ti(Fu,f),ti(Ro,f))}function zi(f,d,E){if(!ai){if(Ro.current!==Rn)throw Error("Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.");Jr(Ro,d,f),Jr(Fu,E,f)}}function Oo(f,d,E){if(ai)return E;var C=f.stateNode,A=d.childContextTypes;if(typeof C.getChildContext!="function"){{var j=Wt(d)||"Unknown";Wu[j]||(Wu[j]=!0,He(!1,"%s.childContextTypes is specified but there is no getChildContext() method on the instance. You can either define getChildContext() on %s or remove childContextTypes from it.",j,j))}return E}var V;et("getChildContext"),Bi(f,"getChildContext"),V=C.getChildContext(),Ci(),et(null);for(var te in V)if(!(te in A))throw Error((Wt(d)||"Unknown")+'.getChildContext(): key "'+te+'" is not defined in childContextTypes.');{var se=Wt(d)||"Unknown";_(A,V,"child context",se,Nr)}return a({},E,{},V)}function Hi(f){if(ai)return!1;var d=f.stateNode,E=d&&d.__reactInternalMemoizedMergedChildContext||Rn;return li=Ro.current,Jr(Ro,E,f),Jr(Fu,Fu.current,f),!0}function il(f,d,E){if(!ai){var C=f.stateNode;if(!C)throw Error("Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.");if(E){var A=Oo(f,d,li);C.__reactInternalMemoizedMergedChildContext=A,ti(Fu,f),ti(Ro,f),Jr(Ro,A,f),Jr(Fu,E,f)}else ti(Fu,f),Jr(Fu,E,f)}}function xl(f){if(ai)return Rn;if(!(bs(f)&&f.tag===O))throw Error("Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue.");var d=f;do{switch(d.tag){case B:return d.stateNode.context;case O:{var E=d.type;if(Xi(E))return d.stateNode.__reactInternalMemoizedMergedChildContext;break}}d=d.return}while(d!==null);throw Error("Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue.")}var Uo=1,Mo=2,v0=t.unstable_runWithPriority,Pu=t.unstable_scheduleCallback,Zu=t.unstable_cancelCallback,ts=t.unstable_shouldYield,Es=t.unstable_requestPaint,fa=t.unstable_now,_f=t.unstable_getCurrentPriorityLevel,$u=t.unstable_ImmediatePriority,Ds=t.unstable_UserBlockingPriority,Rr=t.unstable_NormalPriority,r0=t.unstable_LowPriority,nu=t.unstable_IdlePriority;if(bn&&!(M.__interactionsRef!=null&&M.__interactionsRef.current!=null))throw Error("It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling");var cu={},Ni=99,ni=98,Kn=97,eo=96,Eo=95,Do=90,Fn=ts,ae=Es!==void 0?Es:function(){},ie=null,Fe=null,Oe=!1,st=fa(),yt=st<1e4?fa:function(){return fa()-st};function Jt(){switch(_f()){case $u:return Ni;case Ds:return ni;case Rr:return Kn;case r0:return eo;case nu:return Eo;default:throw Error("Unknown priority level.")}}function On(f){switch(f){case Ni:return $u;case ni:return Ds;case Kn:return Rr;case eo:return r0;case Eo:return nu;default:throw Error("Unknown priority level.")}}function Sn(f,d){var E=On(f);return v0(E,d)}function _n(f,d,E){var C=On(f);return Pu(C,d,E)}function Tn(f){return ie===null?(ie=[f],Fe=Pu($u,Fi)):ie.push(f),cu}function ir(f){f!==cu&&Zu(f)}function Bt(){if(Fe!==null){var f=Fe;Fe=null,Zu(f)}Fi()}function Fi(){if(!Oe&&ie!==null){Oe=!0;var f=0;try{var d=!0,E=ie;Sn(Ni,function(){for(;f1?d-1:0),C=1;C2?E-2:0),A=2;A0&&(za.forEach(function(Nt){f.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),za=[]);var d=new Set;Ha.length>0&&(Ha.forEach(function(Nt){d.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),Ha=[]);var E=new Set;qa.length>0&&(qa.forEach(function(Nt){E.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),qa=[]);var C=new Set;da.length>0&&(da.forEach(function(Nt){C.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),da=[]);var A=new Set;Ss.length>0&&(Ss.forEach(function(Nt){A.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),Ss=[]);var j=new Set;if(Ts.length>0&&(Ts.forEach(function(Nt){j.add(Wt(Nt.type)||"Component"),ns.add(Nt.type)}),Ts=[]),d.size>0){var V=z0(d);He(!1,`Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move code with side effects to componentDidMount, and set initial state in the constructor. - -Please update the following components: %s`,V)}if(C.size>0){var te=z0(C);He(!1,`Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move data fetching code or side effects to componentDidUpdate. -* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state - -Please update the following components: %s`,te)}if(j.size>0){var se=z0(j);He(!1,`Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move data fetching code or side effects to componentDidUpdate. - -Please update the following components: %s`,se)}if(f.size>0){var Ue=z0(f);Ws(!1,`componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move code with side effects to componentDidMount, and set initial state in the constructor. -* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder. - -Please update the following components: %s`,Ue)}if(E.size>0){var Qe=z0(E);Ws(!1,`componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move data fetching code or side effects to componentDidUpdate. -* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state -* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder. - -Please update the following components: %s`,Qe)}if(A.size>0){var vt=z0(A);Ws(!1,`componentWillUpdate has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details. - -* Move data fetching code or side effects to componentDidUpdate. -* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder. - -Please update the following components: %s`,vt)}};var H0=new Map,Df=new Set;Al.recordLegacyContextWarning=function(f,d){var E=ud(f);if(E===null){He(!1,"Expected to find a StrictMode component in a strict mode tree. This error is likely caused by a bug in React. Please file an issue.");return}if(!Df.has(f.type)){var C=H0.get(E);(f.type.contextTypes!=null||f.type.childContextTypes!=null||d!==null&&typeof d.getChildContext=="function")&&(C===void 0&&(C=[],H0.set(E,C)),C.push(f))}},Al.flushLegacyContextWarning=function(){H0.forEach(function(f,d){var E=new Set;f.forEach(function(j){E.add(Wt(j.type)||"Component"),Df.add(j.type)});var C=z0(E),A=Cr(d);He(!1,`Legacy context API has been detected within a strict-mode tree. - -The old API will be supported in all 16.x releases, but applications using it should migrate to the new version. - -Please update the following components: %s - -Learn more about this warning here: https://fb.me/react-legacy-context%s`,C,A)})},Al.discardPendingWarnings=function(){za=[],Ha=[],qa=[],da=[],Ss=[],Ts=[],H0=new Map}}var ol=null,Gu=null,Wa=function(f){ol=f};function ro(f){{if(ol===null)return f;var d=ol(f);return d===void 0?f:d.current}}function zo(f){return ro(f)}function wf(f){{if(ol===null)return f;var d=ol(f);if(d===void 0){if(f!=null&&typeof f.render=="function"){var E=ro(f.render);if(f.render!==E){var C={$$typeof:Mn,render:E};return f.displayName!==void 0&&(C.displayName=f.displayName),C}}return f}return d.current}}function Wc(f,d){{if(ol===null)return!1;var E=f.elementType,C=d.type,A=!1,j=typeof C=="object"&&C!==null?C.$$typeof:null;switch(f.tag){case O:{typeof C=="function"&&(A=!0);break}case N:{(typeof C=="function"||j===Er)&&(A=!0);break}case ue:{(j===Mn||j===Er)&&(A=!0);break}case me:case re:{(j===Gt||j===Er)&&(A=!0);break}default:return!1}if(A){var V=ol(E);if(V!==void 0&&V===ol(C))return!0}return!1}}function pc(f){{if(ol===null||typeof WeakSet!="function")return;Gu===null&&(Gu=new WeakSet),Gu.add(f)}}var Ol=function(f,d){{if(ol===null)return;var E=d.staleFamilies,C=d.updatedFamilies;nf(),Op(function(){pa(f.current,C,E)})}},Cs=function(f,d){{if(f.context!==Rn)return;nf(),pv(function(){o_(d,f,null,null)})}};function pa(f,d,E){{var C=f.alternate,A=f.child,j=f.sibling,V=f.tag,te=f.type,se=null;switch(V){case N:case re:case O:se=te;break;case ue:se=te.render;break;default:break}if(ol===null)throw new Error("Expected resolveFamily to be set during hot reload.");var Ue=!1,Qe=!1;if(se!==null){var vt=ol(se);vt!==void 0&&(E.has(vt)?Qe=!0:d.has(vt)&&(V===O?Qe=!0:Ue=!0))}Gu!==null&&(Gu.has(f)||C!==null&&Gu.has(C))&&(Qe=!0),Qe&&(f._debugNeedsRemount=!0),(Qe||Ue)&&yl(f,Un),A!==null&&!Qe&&pa(A,d,E),j!==null&&pa(j,d,E)}}var od=function(f,d){{var E=new Set,C=new Set(d.map(function(A){return A.current}));return ha(f.current,C,E),E}};function ha(f,d,E){{var C=f.child,A=f.sibling,j=f.tag,V=f.type,te=null;switch(j){case N:case re:case O:te=V;break;case ue:te=V.render;break;default:break}var se=!1;te!==null&&d.has(te)&&(se=!0),se?hc(f,E):C!==null&&ha(C,d,E),A!==null&&ha(A,d,E)}}function hc(f,d){{var E=Vc(f,d);if(E)return;for(var C=f;;){switch(C.tag){case q:d.add(C.stateNode);return;case H:d.add(C.stateNode.containerInfo);return;case B:d.add(C.stateNode.containerInfo);return}if(C.return===null)throw new Error("Expected to reach root first.");C=C.return}}}function Vc(f,d){for(var E=f,C=!1;;){if(E.tag===q)C=!0,d.add(E.stateNode);else if(E.child!==null){E.child.return=E,E=E.child;continue}if(E===f)return C;for(;E.sibling===null;){if(E.return===null||E.return===f)return C;E=E.return}E.sibling.return=E.return,E=E.sibling}return!1}function qi(f,d){if(f&&f.defaultProps){var E=a({},d),C=f.defaultProps;for(var A in C)E[A]===void 0&&(E[A]=C[A]);return E}return d}function g(f){if(Z0(f),f._status!==A0)throw f._result;return f._result}var y=Ju(null),R;R={};var F=null,b=null,J=null,de=!1;function gt(){F=null,b=null,J=null,de=!1}function xt(){de=!0}function Lt(){de=!1}function xr(f,d){var E=f.type._context;ju?(Jr(y,E._currentValue,f),E._currentValue=d,E._currentRenderer===void 0||E._currentRenderer===null||E._currentRenderer===R||He(!1,"Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported."),E._currentRenderer=R):(Jr(y,E._currentValue2,f),E._currentValue2=d,E._currentRenderer2===void 0||E._currentRenderer2===null||E._currentRenderer2===R||He(!1,"Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported."),E._currentRenderer2=R)}function io(f){var d=y.current;ti(y,f);var E=f.type._context;ju?E._currentValue=d:E._currentValue2=d}function du(f,d,E){if(y0(E,d))return 0;var C=typeof f._calculateChangedBits=="function"?f._calculateChangedBits(E,d):Vr;return(C&Vr)!==C&&Qt(!1,"calculateChangedBits: Expected the return value to be a 31-bit integer. Instead received: %s",C),C|0}function Ho(f,d){for(var E=f;E!==null;){var C=E.alternate;if(E.childExpirationTime=d&&sp(),E.firstContext=null)}}function Ve(f,d){if(de&&Qt(!1,"Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."),J!==f){if(!(d===!1||d===0)){var E;typeof d!="number"||d===Vr?(J=f,E=Vr):E=d;var C={context:f,observedBits:E,next:null};if(b===null){if(F===null)throw Error("Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo().");b=C,F.dependencies={expirationTime:at,firstContext:C,responders:null}}else b=b.next=C}}return ju?f._currentValue:f._currentValue2}var ze=0,lt=1,$t=2,Wn=3,si=!1,ur,ci;ur=!1,ci=null;function Qi(f){var d={baseState:f,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null};return d}function Gr(f){var d={baseState:f.baseState,firstUpdate:f.firstUpdate,lastUpdate:f.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null};return d}function Cu(f,d){var E={expirationTime:f,suspenseConfig:d,tag:ze,payload:null,callback:null,next:null,nextEffect:null};return E.priority=Jt(),E}function Va(f,d){f.lastUpdate===null?f.firstUpdate=f.lastUpdate=d:(f.lastUpdate.next=d,f.lastUpdate=d)}function Ga(f,d){var E=f.alternate,C,A;E===null?(C=f.updateQueue,A=null,C===null&&(C=f.updateQueue=Qi(f.memoizedState))):(C=f.updateQueue,A=E.updateQueue,C===null?A===null?(C=f.updateQueue=Qi(f.memoizedState),A=E.updateQueue=Qi(E.memoizedState)):C=f.updateQueue=Gr(A):A===null&&(A=E.updateQueue=Gr(C))),A===null||C===A?Va(C,d):C.lastUpdate===null||A.lastUpdate===null?(Va(C,d),Va(A,d)):(Va(C,d),A.lastUpdate=d),f.tag===O&&(ci===C||A!==null&&ci===A)&&!ur&&(He(!1,"An update (setState, replaceState, or forceUpdate) was scheduled from inside an update function. Update functions should be pure, with zero side-effects. Consider using componentDidUpdate or a callback."),ur=!0)}function ld(f,d){var E=f.updateQueue;E===null?E=f.updateQueue=Qi(f.memoizedState):E=S2(f,E),E.lastCapturedUpdate===null?E.firstCapturedUpdate=E.lastCapturedUpdate=d:(E.lastCapturedUpdate.next=d,E.lastCapturedUpdate=d)}function S2(f,d){var E=f.alternate;return E!==null&&d===E.updateQueue&&(d=f.updateQueue=Gr(d)),d}function T2(f,d,E,C,A,j){switch(E.tag){case lt:{var V=E.payload;if(typeof V=="function"){xt(),Ri&&f.mode&mr&&V.call(j,C,A);var te=V.call(j,C,A);return Lt(),te}return V}case Wn:f.effectTag=f.effectTag&~ho|Xr;case ze:{var se=E.payload,Ue;return typeof se=="function"?(xt(),Ri&&f.mode&mr&&se.call(j,C,A),Ue=se.call(j,C,A),Lt()):Ue=se,Ue==null?C:a({},C,Ue)}case $t:return si=!0,C}return C}function Sf(f,d,E,C,A){si=!1,d=S2(f,d),ci=d;for(var j=d.baseState,V=null,te=at,se=d.firstUpdate,Ue=j;se!==null;){var Qe=se.expirationTime;if(Qe from render. Or maybe you meant to call this function rather than return it."))}function Eh(f){function d(ot,Ot){if(!!f){var $e=ot.lastEffect;$e!==null?($e.nextEffect=Ot,ot.lastEffect=Ot):ot.firstEffect=ot.lastEffect=Ot,Ot.nextEffect=null,Ot.effectTag=Ko}}function E(ot,Ot){if(!f)return null;for(var $e=Ot;$e!==null;)d(ot,$e),$e=$e.sibling;return null}function C(ot,Ot){for(var $e=new Map,Ut=Ot;Ut!==null;)Ut.key!==null?$e.set(Ut.key,Ut):$e.set(Ut.index,Ut),Ut=Ut.sibling;return $e}function A(ot,Ot,$e){var Ut=C0(ot,Ot,$e);return Ut.index=0,Ut.sibling=null,Ut}function j(ot,Ot,$e){if(ot.index=$e,!f)return Ot;var Ut=ot.alternate;if(Ut!==null){var Pn=Ut.index;return PnKr?(xu=hr,hr=null):xu=hr.sibling;var So=Nt(ot,hr,$e[Kr],Ut);if(So===null){hr===null&&(hr=xu);break}f&&hr&&So.alternate===null&&d(ot,hr),hu=j(So,hu,Kr),Ku===null?pi=So:Ku.sibling=So,Ku=So,hr=xu}if(Kr===$e.length)return E(ot,hr),pi;if(hr===null){for(;Kr<$e.length;Kr++){var Vo=vt(ot,$e[Kr],Ut);Vo!==null&&(hu=j(Vo,hu,Kr),Ku===null?pi=Vo:Ku.sibling=Vo,Ku=Vo)}return pi}for(var ks=C(ot,hr);Kr<$e.length;Kr++){var Xu=Yt(ks,ot,Kr,$e[Kr],Ut);Xu!==null&&(f&&Xu.alternate!==null&&ks.delete(Xu.key===null?Kr:Xu.key),hu=j(Xu,hu,Kr),Ku===null?pi=Xu:Ku.sibling=Xu,Ku=Xu)}return f&&ks.forEach(function(gl){return d(ot,gl)}),pi}function kr(ot,Ot,$e,Ut){var Pn=fr($e);if(typeof Pn!="function")throw Error("An object is not an iterable. This error is likely caused by a bug in React. Please file an issue.");{typeof Symbol=="function"&&$e[Symbol.toStringTag]==="Generator"&&(Qc||Qt(!1,"Using Generators as children is unsupported and will likely yield unexpected results because enumerating a generator mutates it. You may convert it to an array with `Array.from()` or the `[...spread]` operator before rendering. Keep in mind you might need to polyfill these features for older browsers."),Qc=!0),$e.entries===Pn&&(pd||Qt(!1,"Using Maps as children is unsupported and will likely yield unexpected results. Convert it to a sequence/iterable of keyed ReactElements instead."),pd=!0);var vn=Pn.call($e);if(vn)for(var Wi=null,pi=vn.next();!pi.done;pi=vn.next()){var Ku=pi.value;Wi=Ht(Ku,Wi)}}var hr=Pn.call($e);if(hr==null)throw Error("An iterable object provided no iterator.");for(var hu=null,Kr=null,xu=Ot,So=0,Vo=0,ks=null,Xu=hr.next();xu!==null&&!Xu.done;Vo++,Xu=hr.next()){xu.index>Vo?(ks=xu,xu=null):ks=xu.sibling;var gl=Nt(ot,xu,Xu.value,Ut);if(gl===null){xu===null&&(xu=ks);break}f&&xu&&gl.alternate===null&&d(ot,xu),So=j(gl,So,Vo),Kr===null?hu=gl:Kr.sibling=gl,Kr=gl,xu=ks}if(Xu.done)return E(ot,xu),hu;if(xu===null){for(;!Xu.done;Vo++,Xu=hr.next()){var uf=vt(ot,Xu.value,Ut);uf!==null&&(So=j(uf,So,Vo),Kr===null?hu=uf:Kr.sibling=uf,Kr=uf)}return hu}for(var V0=C(ot,xu);!Xu.done;Vo++,Xu=hr.next()){var Ls=Yt(V0,ot,Vo,Xu.value,Ut);Ls!==null&&(f&&Ls.alternate!==null&&V0.delete(Ls.key===null?Vo:Ls.key),So=j(Ls,So,Vo),Kr===null?hu=Ls:Kr.sibling=Ls,Kr=Ls)}return f&&V0.forEach(function($d){return d(ot,$d)}),hu}function oi(ot,Ot,$e,Ut){if(Ot!==null&&Ot.tag===ne){E(ot,Ot.sibling);var Pn=A(Ot,$e,Ut);return Pn.return=ot,Pn}E(ot,Ot);var vn=_y($e,ot.mode,Ut);return vn.return=ot,vn}function Oi(ot,Ot,$e,Ut){for(var Pn=$e.key,vn=Ot;vn!==null;){if(vn.key===Pn)if(vn.tag===m?$e.type===le:vn.elementType===$e.type||Wc(vn,$e)){E(ot,vn.sibling);var Wi=A(vn,$e.type===le?$e.props.children:$e.props,Ut);return Wi.ref=mc(ot,vn,$e),Wi.return=ot,Wi._debugSource=$e._source,Wi._debugOwner=$e._owner,Wi}else{E(ot,vn);break}else d(ot,vn);vn=vn.sibling}if($e.type===le){var pi=rf($e.props.children,ot.mode,Ut,$e.key);return pi.return=ot,pi}else{var Ku=gy($e,ot.mode,Ut);return Ku.ref=mc(ot,Ot,$e),Ku.return=ot,Ku}}function Fo(ot,Ot,$e,Ut){for(var Pn=$e.key,vn=Ot;vn!==null;){if(vn.key===Pn)if(vn.tag===H&&vn.stateNode.containerInfo===$e.containerInfo&&vn.stateNode.implementation===$e.implementation){E(ot,vn.sibling);var Wi=A(vn,$e.children||[],Ut);return Wi.return=ot,Wi}else{E(ot,vn);break}else d(ot,vn);vn=vn.sibling}var pi=Ey($e,ot.mode,Ut);return pi.return=ot,pi}function $i(ot,Ot,$e,Ut){var Pn=typeof $e=="object"&&$e!==null&&$e.type===le&&$e.key===null;Pn&&($e=$e.props.children);var vn=typeof $e=="object"&&$e!==null;if(vn)switch($e.$$typeof){case fe:return V(Oi(ot,Ot,$e,Ut));case xe:return V(Fo(ot,Ot,$e,Ut))}if(typeof $e=="string"||typeof $e=="number")return V(oi(ot,Ot,""+$e,Ut));if(Zc($e))return yn(ot,Ot,$e,Ut);if(fr($e))return kr(ot,Ot,$e,Ut);if(vn&&yc(ot,$e),typeof $e=="function"&&hd(),typeof $e=="undefined"&&!Pn)switch(ot.tag){case O:{var Wi=ot.stateNode;if(Wi.render._isMockFunction)break}case N:{var pi=ot.type;throw Error((pi.displayName||pi.name||"Component")+"(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.")}}return E(ot,Ot)}return $i}var Cf=Eh(!0),$c=Eh(!1);function Dh(f,d){if(!(f===null||d.child===f.child))throw Error("Resuming work not yet implemented.");if(d.child!==null){var E=d.child,C=C0(E,E.pendingProps,E.expirationTime);for(d.child=C,C.return=d;E.sibling!==null;)E=E.sibling,C=C.sibling=C0(E,E.pendingProps,E.expirationTime),C.return=d;C.sibling=null}}function am(f,d){for(var E=f.child;E!==null;)kv(E,d),E=E.sibling}var Gs={},ya=Ju(Gs),iu=Ju(Gs),ko=Ju(Gs);function oo(f){if(f===Gs)throw Error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.");return f}function rs(){var f=oo(ko.current);return f}function Ka(f,d){Jr(ko,d,f),Jr(iu,f,f),Jr(ya,Gs,f);var E=wt(d);ti(ya,f),Jr(ya,E,f)}function o0(f){ti(ya,f),ti(iu,f),ti(ko,f)}function fl(){var f=oo(ya.current);return f}function gc(f){var d=oo(ko.current),E=oo(ya.current),C=bt(E,f.type,d);E!==C&&(Jr(iu,f,f),Jr(ya,C,f))}function L2(f){iu.current===f&&(ti(ya,f),ti(iu,f))}var wh=0,xf=1,Rf=1,e1=2,Ll=Ju(wh);function t1(f,d){return(f&d)!=0}function ga(f){return f&xf}function vd(f,d){return f&xf|d}function md(f,d){return f|d}function Fr(f,d){Jr(Ll,d,f)}function Ea(f){ti(Ll,f)}function N2(f,d){var E=f.memoizedState;if(E!==null)return E.dehydrated!==null;var C=f.memoizedProps;return C.fallback===void 0?!1:C.unstable_avoidThisFallback!==!0?!0:!d}function n1(f){for(var d=f;d!==null;){if(d.tag===ce){var E=d.memoizedState;if(E!==null){var C=E.dehydrated;if(C===null||Us(C)||go(C))return d}}else if(d.tag===ct&&d.memoizedProps.revealOrder!==void 0){var A=(d.effectTag&Xr)!==xi;if(A)return d}else if(d.child!==null){d.child.return=d,d=d.child;continue}if(d===f)return null;for(;d.sibling===null;){if(d.return===null||d.return===f)return null;d=d.return}d.sibling.return=d.return,d=d.sibling}return null}var yd={},wi=Array.isArray;function F2(f,d,E,C){return{fiber:C,props:d,responder:f,rootEventTypes:null,state:E}}function fm(f,d,E,C,A){var j=yd,V=f.getInitialState;V!==null&&(j=V(d));var te=F2(f,d,j,E);if(!A)for(var se=E;se!==null;){var Ue=se.tag;if(Ue===q){A=se.stateNode;break}else if(Ue===B){A=se.stateNode.containerInfo;break}se=se.return}Ne(f,te,d,j,A),C.set(f,te)}function gd(f,d,E,C,A){var j,V;if(f&&(j=f.responder,V=f.props),!(j&&j.$$typeof===jt))throw Error("An invalid value was used as an event listener. Expect one or many event listeners created via React.unstable_useResponder().");var te=V;if(E.has(j)){Qt(!1,'Duplicate event responder "%s" found in event listeners. Event listeners passed to elements cannot use the same event responder more than once.',j.displayName);return}E.add(j);var se=C.get(j);se===void 0?fm(j,te,d,C,A):(se.props=te,se.fiber=d)}function hn(f,d,E){var C=new Set,A=d.dependencies;if(f!=null){A===null&&(A=d.dependencies={expirationTime:at,firstContext:null,responders:new Map});var j=A.responders;if(j===null&&(j=new Map),wi(f))for(var V=0,te=f.length;V0){var j=A.dispatch;if(xs!==null){var V=xs.get(A);if(V!==void 0){xs.delete(A);var te=C.memoizedState,se=V;do{var Ue=se.action;te=f(te,Ue),se=se.next}while(se!==null);return y0(te,C.memoizedState)||sp(),C.memoizedState=te,C.baseUpdate===A.last&&(C.baseState=te),A.lastRenderedState=te,[te,j]}}return[C.memoizedState,j]}var Qe=A.last,vt=C.baseUpdate,Nt=C.baseState,Yt;if(vt!==null?(Qe!==null&&(Qe.next=null),Yt=vt.next):Yt=Qe!==null?Qe.next:null,Yt!==null){var Ht=Nt,yn=null,kr=null,oi=vt,Oi=Yt,Fo=!1;do{var $i=Oi.expirationTime;if($iIu&&(Iu=$i,Qd(Iu));else if(gv($i,Oi.suspenseConfig),Oi.eagerReducer===f)Ht=Oi.eagerState;else{var ot=Oi.action;Ht=f(Ht,ot)}oi=Oi,Oi=Oi.next}while(Oi!==null&&Oi!==Yt);Fo||(kr=oi,yn=Ht),y0(Ht,C.memoizedState)||sp(),C.memoizedState=Ht,C.baseUpdate=kr,C.baseState=yn,A.lastRenderedState=Ht}var Ot=A.dispatch;return[C.memoizedState,Ot]}function Pf(f){var d=wc();typeof f=="function"&&(f=f()),d.memoizedState=d.baseState=f;var E=d.queue={last:null,dispatch:null,lastRenderedReducer:P2,lastRenderedState:f},C=E.dispatch=a1.bind(null,dl,E);return[d.memoizedState,C]}function o1(f){return u1(P2,f)}function Ja(f,d,E,C){var A={tag:f,create:d,destroy:E,deps:C,next:null};if(is===null)is=Qa(),is.lastEffect=A.next=A;else{var j=is.lastEffect;if(j===null)is.lastEffect=A.next=A;else{var V=j.next;j.next=A,A.next=V,is.lastEffect=A}}return A}function l1(f){var d=wc(),E={current:f};return Object.seal(E),d.memoizedState=E,E}function I2(f){var d=i1();return d.memoizedState}function wd(f,d,E,C){var A=wc(),j=C===void 0?null:C;kf|=f,A.memoizedState=Ja(d,E,void 0,j)}function Sc(f,d,E,C){var A=i1(),j=C===void 0?null:C,V=void 0;if(jn!==null){var te=jn.memoizedState;if(V=te.destroy,j!==null){var se=te.deps;if(Nf(j,se)){Ja(Of,E,V,j);return}}}kf|=f,A.memoizedState=Ja(d,E,V,j)}function s1(f,d){return typeof jest!="undefined"&&Mv(dl),wd(Dr|Po,sr|r1,f,d)}function Fl(f,d){return typeof jest!="undefined"&&Mv(dl),Sc(Dr|Po,sr|r1,f,d)}function Da(f,d){return wd(Dr,Mf|cl,f,d)}function Ch(f,d){return Sc(Dr,Mf|cl,f,d)}function b2(f,d){if(typeof d=="function"){var E=d,C=f();return E(C),function(){E(null)}}else if(d!=null){var A=d;A.hasOwnProperty("current")||Qt(!1,"Expected useImperativeHandle() first argument to either be a ref callback or React.createRef() object. Instead received: %s.","an object with keys {"+Object.keys(A).join(", ")+"}");var j=f();return A.current=j,function(){A.current=null}}}function B2(f,d,E){typeof d!="function"&&Qt(!1,"Expected useImperativeHandle() second argument to be a function that creates a handle. Instead received: %s.",d!==null?typeof d:"null");var C=E!=null?E.concat([f]):null;return wd(Dr,Mf|cl,b2.bind(null,d,f),C)}function xh(f,d,E){typeof d!="function"&&Qt(!1,"Expected useImperativeHandle() second argument to be a function that creates a handle. Instead received: %s.",d!==null?typeof d:"null");var C=E!=null?E.concat([f]):null;return Sc(Dr,Mf|cl,b2.bind(null,d,f),C)}function Sd(f,d){}var Rh=Sd;function Pl(f,d){var E=wc(),C=d===void 0?null:d;return E.memoizedState=[f,C],f}function os(f,d){var E=i1(),C=d===void 0?null:d,A=E.memoizedState;if(A!==null&&C!==null){var j=A[1];if(Nf(C,j))return A[0]}return E.memoizedState=[f,C],f}function Rs(f,d){var E=wc(),C=d===void 0?null:d,A=f();return E.memoizedState=[A,C],A}function Ys(f,d){var E=i1(),C=d===void 0?null:d,A=E.memoizedState;if(A!==null&&C!==null){var j=A[1];if(Nf(C,j))return A[0]}var V=f();return E.memoizedState=[V,C],V}function U2(f,d){var E=Pf(f),C=E[0],A=E[1];return s1(function(){t.unstable_next(function(){var j=q0.suspense;q0.suspense=d===void 0?null:d;try{A(f)}finally{q0.suspense=j}})},[f,d]),C}function Ah(f,d){var E=o1(f),C=E[0],A=E[1];return Fl(function(){t.unstable_next(function(){var j=q0.suspense;q0.suspense=d===void 0?null:d;try{A(f)}finally{q0.suspense=j}})},[f,d]),C}function j2(f){var d=Pf(!1),E=d[0],C=d[1],A=Pl(function(j){C(!0),t.unstable_next(function(){var V=q0.suspense;q0.suspense=f===void 0?null:f;try{C(!1),j()}finally{q0.suspense=V}})},[f,E]);return[A,E]}function z2(f){var d=o1(!1),E=d[0],C=d[1],A=os(function(j){C(!0),t.unstable_next(function(){var V=q0.suspense;q0.suspense=f===void 0?null:f;try{C(!1),j()}finally{q0.suspense=V}})},[f,E]);return[A,E]}function a1(f,d,E){if(!(Dc=0){var E=c1()-d1;f.actualDuration+=E,d&&(f.selfBaseDuration=E),d1=-1}}var bl=null,$a=null,wa=!1;function V2(){wa&&Qt(!1,"We should not be hydrating here. This is a bug in React. Please file a bug.")}function G2(f){if(!Se)return!1;var d=f.stateNode.containerInfo;return $a=U(d),bl=f,wa=!0,!0}function hm(f,d){return Se?($a=ji(d),X2(f),wa=!0,!0):!1}function Y2(f,d){switch(f.tag){case B:oe(f.stateNode.containerInfo,d);break;case q:We(f.type,f.memoizedProps,f.stateNode,d);break}var E=rE();E.stateNode=d,E.return=f,E.effectTag=Ko,f.lastEffect!==null?(f.lastEffect.nextEffect=E,f.lastEffect=E):f.firstEffect=f.lastEffect=E}function Fh(f,d){switch(d.effectTag=d.effectTag&~au|mi,f.tag){case B:{var E=f.stateNode.containerInfo;switch(d.tag){case q:var C=d.type,A=d.pendingProps;it(E,C,A);break;case ne:var j=d.pendingProps;Ct(E,j);break;case ce:Mt(E);break}break}case q:{var V=f.type,te=f.memoizedProps,se=f.stateNode;switch(d.tag){case q:var Ue=d.type,Qe=d.pendingProps;It(V,te,se,Ue,Qe);break;case ne:var vt=d.pendingProps;sn(V,te,se,vt);break;case ce:rn(V,te,se);break}break}default:return}}function Ph(f,d){switch(f.tag){case q:{var E=f.type,C=f.pendingProps,A=hf(d,E,C);return A!==null?(f.stateNode=A,!0):!1}case ne:{var j=f.pendingProps,V=Bs(d,j);return V!==null?(f.stateNode=V,!0):!1}case ce:{if(Ai){var te=Ba(d);if(te!==null){var se={dehydrated:te,retryTime:Di};f.memoizedState=se;var Ue=iE(te);return Ue.return=f,f.child=Ue,!0}}return!1}default:return!1}}function K2(f){if(!!wa){var d=$a;if(!d){Fh(bl,f),wa=!1,bl=f;return}var E=d;if(!Ph(f,d)){if(d=ji(E),!d||!Ph(f,d)){Fh(bl,f),wa=!1,bl=f;return}Y2(bl,E)}bl=f,$a=U(d)}}function vm(f,d,E){if(!Se)throw Error("Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.");var C=f.stateNode,A=z(C,f.type,f.memoizedProps,d,E,f);return f.updateQueue=A,A!==null}function mm(f){if(!Se)throw Error("Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.");var d=f.stateNode,E=f.memoizedProps,C=G(d,E,f);if(C){var A=bl;if(A!==null)switch(A.tag){case B:{var j=A.stateNode.containerInfo;Je(j,d,E);break}case q:{var V=A.type,te=A.memoizedProps,se=A.stateNode;mt(V,te,se,d,E);break}}}return C}function Ih(f){if(!Se)throw Error("Expected prepareToHydrateHostSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.");var d=f.memoizedState,E=d!==null?d.dehydrated:null;if(!E)throw Error("Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue.");$(E,f)}function ym(f){if(!Se)throw Error("Expected skipPastDehydratedSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.");var d=f.memoizedState,E=d!==null?d.dehydrated:null;if(!E)throw Error("Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue.");return Ce(E)}function X2(f){for(var d=f.return;d!==null&&d.tag!==q&&d.tag!==B&&d.tag!==ce;)d=d.return;bl=d}function h1(f){if(!Se||f!==bl)return!1;if(!wa)return X2(f),wa=!0,!1;var d=f.type;if(f.tag!==q||d!=="head"&&d!=="body"&&!Li(d,f.memoizedProps))for(var E=$a;E;)Y2(f,E),E=ji(E);return X2(f),f.tag===ce?$a=ym(f):$a=bl?ji(f.stateNode):null,!0}function v1(){!Se||(bl=null,$a=null,wa=!1)}var m1=nt.ReactCurrentOwner,Sa=!1,Q2,Ks,Xs,Qs,J2,Ta,y1,Td,Tc,Z2;Q2={},Ks={},Xs={},Qs={},J2={},Ta=!1,y1=!1,Td={},Tc={},Z2={};function w0(f,d,E,C){f===null?d.child=$c(d,null,E,C):d.child=Cf(d,f.child,E,C)}function bh(f,d,E,C){d.child=Cf(d,f.child,null,C),d.child=Cf(d,null,E,C)}function Bh(f,d,E,C,A){if(d.type!==d.elementType){var j=E.propTypes;j&&_(j,C,"prop",Wt(E),Nr)}var V=E.render,te=d.ref,se;return uo(d,A),m1.current=d,et("render"),se=Ff(f,d,V,C,te,A),Ri&&d.mode&mr&&d.memoizedState!==null&&(se=Ff(f,d,V,C,te,A)),et(null),f!==null&&!Sa?(_d(f,d,A),Ca(f,d,A)):(d.effectTag|=su,w0(f,d,se,A),d.child)}function Uh(f,d,E,C,A,j){if(f===null){var V=E.type;if(ao(V)&&E.compare===null&&E.defaultProps===void 0){var te=V;return te=ro(V),d.tag=re,d.type=te,tp(d,V),jh(f,d,te,C,A,j)}{var se=V.propTypes;se&&_(se,C,"prop",Wt(V),Nr)}var Ue=yy(E.type,null,C,null,d.mode,j);return Ue.ref=d.ref,Ue.return=d,d.child=Ue,Ue}{var Qe=E.type,vt=Qe.propTypes;vt&&_(vt,C,"prop",Wt(Qe),Nr)}var Nt=f.child;if(A component appears to have a render method, but doesn't extend React.Component. This is likely to cause errors. Change %s to extend React.Component instead.",se,se),Q2[se]=!0)}d.mode&mr&&Al.recordLegacyContextWarning(d,null),m1.current=d,te=Ff(null,d,E,A,j,C)}if(d.effectTag|=su,typeof te=="object"&&te!==null&&typeof te.render=="function"&&te.$$typeof===void 0){{var Ue=Wt(E)||"Unknown";Ks[Ue]||(He(!1,"The <%s /> component appears to be a function component that returns a class instance. Change %s to a class that extends React.Component instead. If you can't use a class try assigning the prototype on the function as a workaround. `%s.prototype = React.Component.prototype`. Don't use an arrow function since it cannot be called with `new` by React.",Ue,Ue,Ue),Ks[Ue]=!0)}d.tag=O,Ed();var Qe=!1;Xi(E)?(Qe=!0,Hi(d)):Qe=!1,d.memoizedState=te.state!==null&&te.state!==void 0?te.state:null;var vt=E.getDerivedStateFromProps;return typeof vt=="function"&&Tf(d,E,vt,A),al(d,te),vc(d,E,A,C),ep(null,d,E,!0,Qe,C)}else return d.tag=N,ai&&E.contextTypes&&He(!1,"%s uses the legacy contextTypes API which is no longer supported. Use React.createContext() with React.useContext() instead.",Wt(E)||"Unknown"),Ri&&d.mode&mr&&d.memoizedState!==null&&(te=Ff(null,d,E,A,j,C)),w0(null,d,te,C),tp(d,E),d.child}function tp(f,d){if(d&&d.childContextTypes&&He(!1,"%s(...): childContextTypes cannot be defined on a function component.",d.displayName||d.name||"Component"),f.ref!==null){var E="",C=_o();C&&(E+=` - -Check the render method of \``+C+"`.");var A=C||f._debugID||"",j=f._debugSource;j&&(A=j.fileName+":"+j.lineNumber),J2[A]||(J2[A]=!0,Qt(!1,"Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?%s",E))}if(Ql&&d.defaultProps!==void 0){var V=Wt(d)||"Unknown";Z2[V]||(He(!1,"%s: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.",V),Z2[V]=!0)}if(typeof d.getDerivedStateFromProps=="function"){var te=Wt(d)||"Unknown";Qs[te]||(He(!1,"%s: Function components do not support getDerivedStateFromProps.",te),Qs[te]=!0)}if(typeof d.contextType=="object"&&d.contextType!==null){var se=Wt(d)||"Unknown";Xs[se]||(He(!1,"%s: Function components do not support contextType.",se),Xs[se]=!0)}}var xd={dehydrated:null,retryTime:at};function np(f,d,E){return t1(f,e1)&&(d===null||d.memoizedState!==null)}function Vh(f,d,E){var C=d.mode,A=d.pendingProps;s_(d)&&(d.effectTag|=Xr);var j=Ll.current,V=!1,te=(d.effectTag&Xr)!==xi;if(te||np(j,f,d)?(V=!0,d.effectTag&=~Xr):(f===null||f.memoizedState!==null)&&A.fallback!==void 0&&A.unstable_avoidThisFallback!==!0&&(j=md(j,Rf)),j=ga(j),Fr(d,j),"maxDuration"in A&&(y1||(y1=!0,Qt(!1,"maxDuration has been removed from React. Remove the maxDuration prop."))),f===null){if(A.fallback!==void 0&&(K2(d),Ai)){var se=d.memoizedState;if(se!==null){var Ue=se.dehydrated;if(Ue!==null)return Gh(d,Ue,E)}}if(V){var Qe=A.fallback,vt=rf(null,C,at,null);if(vt.return=d,(d.mode&Y)===Ar){var Nt=d.memoizedState,Yt=Nt!==null?d.child.child:d.child;vt.child=Yt;for(var Ht=Yt;Ht!==null;)Ht.return=vt,Ht=Ht.sibling}var yn=rf(Qe,C,E,null);return yn.return=d,vt.sibling=yn,d.memoizedState=xd,d.child=vt,yn}else{var kr=A.children;return d.memoizedState=null,d.child=$c(d,null,kr,E)}}else{var oi=f.memoizedState;if(oi!==null){if(Ai){var Oi=oi.dehydrated;if(Oi!==null)if(te){if(d.memoizedState!==null)return d.child=f.child,d.effectTag|=Xr,null;var Fo=A.fallback,$i=rf(null,C,at,null);if($i.return=d,$i.child=null,(d.mode&Y)===Ar)for(var ot=$i.child=d.child;ot!==null;)ot.return=$i,ot=ot.sibling;else Cf(d,f.child,null,E);if(en&&d.mode&ii){for(var Ot=0,$e=$i.child;$e!==null;)Ot+=$e.treeBaseDuration,$e=$e.sibling;$i.treeBaseDuration=Ot}var Ut=rf(Fo,C,E,null);return Ut.return=d,$i.sibling=Ut,Ut.effectTag|=mi,$i.childExpirationTime=at,d.memoizedState=xd,d.child=$i,Ut}else return Yh(f,d,Oi,oi,E)}var Pn=f.child,vn=Pn.sibling;if(V){var Wi=A.fallback,pi=C0(Pn,Pn.pendingProps,at);if(pi.return=d,(d.mode&Y)===Ar){var Ku=d.memoizedState,hr=Ku!==null?d.child.child:d.child;if(hr!==Pn.child){pi.child=hr;for(var hu=hr;hu!==null;)hu.return=pi,hu=hu.sibling}}if(en&&d.mode&ii){for(var Kr=0,xu=pi.child;xu!==null;)Kr+=xu.treeBaseDuration,xu=xu.sibling;pi.treeBaseDuration=Kr}var So=C0(vn,Wi,vn.expirationTime);return So.return=d,pi.sibling=So,pi.childExpirationTime=at,d.memoizedState=xd,d.child=pi,So}else{var Vo=A.children,ks=Pn.child,Xu=Cf(d,ks,Vo,E);return d.memoizedState=null,d.child=Xu}}else{var gl=f.child;if(V){var uf=A.fallback,V0=rf(null,C,at,null);if(V0.return=d,V0.child=gl,gl!==null&&(gl.return=V0),(d.mode&Y)===Ar){var Ls=d.memoizedState,$d=Ls!==null?d.child.child:d.child;V0.child=$d;for(var Gf=$d;Gf!==null;)Gf.return=V0,Gf=Gf.sibling}if(en&&d.mode&ii){for(var Fc=0,Hl=V0.child;Hl!==null;)Fc+=Hl.treeBaseDuration,Hl=Hl.sibling;V0.treeBaseDuration=Fc}var G0=rf(uf,C,E,null);return G0.return=d,V0.sibling=G0,G0.effectTag|=mi,V0.childExpirationTime=at,d.memoizedState=xd,d.child=V0,G0}else{d.memoizedState=null;var N1=A.children;return d.child=Cf(d,gl,N1,E)}}}}function rp(f,d,E){d.memoizedState=null;var C=d.pendingProps,A=C.children;return w0(f,d,A,E),d.child}function Gh(f,d,E){if((f.mode&Y)===Ar)Qt(!1,"Cannot hydrate Suspense in legacy mode. Switch from ReactDOM.hydrate(element, container) to ReactDOM.createBlockingRoot(container, { hydrate: true }).render(element) or remove the Suspense components from the server rendered components."),f.expirationTime=Un;else if(go(d)){var C=jl(),A=ws(C);bn&&x(A),f.expirationTime=A}else f.expirationTime=Di,bn&&x(Di);return null}function Yh(f,d,E,C,A){if(V2(),(d.mode&Y)===Ar||go(E))return rp(f,d,A);var j=f.childExpirationTime>=A;if(Sa||j){if(A. Use lowercase "%s" instead.',f,f.toLowerCase());break}case"forward":case"backward":{Qt(!1,'"%s" is not a valid value for revealOrder on . React uses the -s suffix in the spelling. Use "%ss" instead.',f,f.toLowerCase());break}default:Qt(!1,'"%s" is not a supported revealOrder on . Did you mean "together", "forwards" or "backwards"?',f);break}else Qt(!1,'%s is not a supported value for revealOrder on . Did you mean "together", "forwards" or "backwards"?',f)}function Kh(f,d){f!==void 0&&!Tc[f]&&(f!=="collapsed"&&f!=="hidden"?(Tc[f]=!0,Qt(!1,'"%s" is not a supported value for tail on . Did you mean "collapsed" or "hidden"?',f)):d!=="forwards"&&d!=="backwards"&&(Tc[f]=!0,Qt(!1,' is only valid if revealOrder is "forwards" or "backwards". Did you mean to specify revealOrder="forwards"?',f)))}function _1(f,d){{var E=Array.isArray(f),C=!E&&typeof fr(f)=="function";if(E||C){var A=E?"array":"iterable";return Qt(!1,"A nested %s was passed to row #%s in . Wrap it in an additional SuspenseList to configure its revealOrder: ... {%s} ... ",A,d,A),!1}}return!0}function Cm(f,d){if((d==="forwards"||d==="backwards")&&f!==void 0&&f!==null&&f!==!1)if(Array.isArray(f)){for(var E=0;E. This is not useful since it needs multiple rows. Did you mean to pass multiple children or an array?',d)}}function up(f,d,E,C,A,j){var V=f.memoizedState;V===null?f.memoizedState={isBackwards:d,rendering:null,last:C,tail:E,tailExpiration:0,tailMode:A,lastEffect:j}:(V.isBackwards=d,V.rendering=null,V.last=C,V.tail=E,V.tailExpiration=0,V.tailMode=A,V.lastEffect=j)}function op(f,d,E){var C=d.pendingProps,A=C.revealOrder,j=C.tail,V=C.children;Tm(A),Kh(j,A),Cm(V,A),w0(f,d,V,E);var te=Ll.current,se=t1(te,e1);if(se)te=vd(te,e1),d.effectTag|=Xr;else{var Ue=f!==null&&(f.effectTag&Xr)!==xi;Ue&&wm(d,d.child,E),te=ga(te)}if(Fr(d,te),(d.mode&Y)===Ar)d.memoizedState=null;else switch(A){case"forwards":{var Qe=Sm(d.child),vt;Qe===null?(vt=d.child,d.child=null):(vt=Qe.sibling,Qe.sibling=null),up(d,!1,vt,Qe,j,d.lastEffect);break}case"backwards":{var Nt=null,Yt=d.child;for(d.child=null;Yt!==null;){var Ht=Yt.alternate;if(Ht!==null&&n1(Ht)===null){d.child=Yt;break}var yn=Yt.sibling;Yt.sibling=Nt,Nt=Yt,Yt=yn}up(d,!0,Nt,null,j,d.lastEffect);break}case"together":{up(d,!1,null,null,void 0,d.lastEffect);break}default:d.memoizedState=null}return d.child}function xm(f,d,E){Ka(d,d.stateNode.containerInfo);var C=d.pendingProps;return f===null?d.child=Cf(d,null,C,E):w0(f,d,C,E),d.child}function Rm(f,d,E){var C=d.type,A=C._context,j=d.pendingProps,V=d.memoizedProps,te=j.value;{var se=d.type.propTypes;se&&_(se,j,"prop","Context.Provider",Nr)}if(xr(d,te),V!==null){var Ue=V.value,Qe=du(A,te,Ue);if(Qe===0){if(V.children===j.children&&!aa())return Ca(f,d,E)}else Ml(d,A,Qe,E)}var vt=j.children;return w0(f,d,vt,E),d.child}var Xh=!1;function Am(f,d,E){var C=d.type;C._context===void 0?C!==C.Consumer&&(Xh||(Xh=!0,Qt(!1,"Rendering directly is not supported and will be removed in a future major release. Did you mean to render instead?"))):C=C._context;var A=d.pendingProps,j=A.children;typeof j!="function"&&He(!1,"A context consumer was rendered with multiple children, or a child that isn't a function. A context consumer expects a single child that is a function. If you did pass a function, make sure there is no trailing or leading whitespace around it."),uo(d,E);var V=Ve(C,A.unstable_observedBits),te;return m1.current=d,et("render"),te=j(V),et(null),d.effectTag|=su,w0(f,d,te,E),d.child}function Om(f,d,E){var C=d.type.impl;if(C.reconcileChildren===!1)return null;var A=d.pendingProps,j=A.children;return w0(f,d,j,E),d.child}function lp(f,d,E){var C=d.pendingProps,A=C.children;return w0(f,d,A,E),d.child}function sp(){Sa=!0}function Ca(f,d,E){tu(d),f!==null&&(d.dependencies=f.dependencies),en&&Nh(d);var C=d.expirationTime;C!==at&&Qd(C);var A=d.childExpirationTime;return A=E;se&&(d.effectTag|=Dr)}break;case ce:{var Ue=d.memoizedState;if(Ue!==null){if(Ai&&Ue.dehydrated!==null){Fr(d,ga(Ll.current)),d.effectTag|=Xr;break}var Qe=d.child,vt=Qe.childExpirationTime;if(vt!==at&&vt>=E)return Vh(f,d,E);Fr(d,ga(Ll.current));var Nt=Ca(f,d,E);return Nt!==null?Nt.sibling:null}else Fr(d,ga(Ll.current));break}case ct:{var Yt=(f.effectTag&Xr)!==xi,Ht=d.childExpirationTime>=E;if(Yt){if(Ht)return op(f,d,E);d.effectTag|=Xr}var yn=d.memoizedState;if(yn!==null&&(yn.rendering=null,yn.tail=null),Fr(d,Ll.current),Ht)break;return null}}return Ca(f,d,E)}else Sa=!1}else Sa=!1;switch(d.expirationTime=at,d.tag){case T:return Dm(f,d,d.type,E);case we:{var kr=d.elementType;return bf(f,d,kr,C,E)}case N:{var oi=d.type,Oi=d.pendingProps,Fo=d.elementType===oi?Oi:qi(oi,Oi);return $2(f,d,oi,Fo,E)}case O:{var $i=d.type,ot=d.pendingProps,Ot=d.elementType===$i?ot:qi($i,ot);return qh(f,d,$i,Ot,E)}case B:return _m(f,d,E);case q:return Em(f,d,E);case ne:return If(f,d);case ce:return Vh(f,d,E);case H:return xm(f,d,E);case ue:{var $e=d.type,Ut=d.pendingProps,Pn=d.elementType===$e?Ut:qi($e,Ut);return Bh(f,d,$e,Pn,E)}case m:return gm(f,d,E);case pe:return zh(f,d,E);case _e:return Hh(f,d,E);case ve:return Rm(f,d,E);case ge:return Am(f,d,E);case me:{var vn=d.type,Wi=d.pendingProps,pi=qi(vn,Wi);if(d.type!==d.elementType){var Ku=vn.propTypes;Ku&&_(Ku,pi,"prop",Wt(vn),Nr)}return pi=qi(vn.type,pi),Uh(f,d,vn,pi,C,E)}case re:return jh(f,d,d.type,d.pendingProps,C,E);case Ie:{var hr=d.type,hu=d.pendingProps,Kr=d.elementType===hr?hu:qi(hr,hu);return Cd(f,d,hr,Kr,E)}case ct:return op(f,d,E);case pt:{if(Vt)return Om(f,d,E);break}case Xe:{if(Au)return lp(f,d,E);break}}throw Error("Unknown unit of work tag ("+d.tag+"). This error is likely caused by a bug in React. Please file an issue.")}function Qh(f,d,E,C){return{currentFiber:f,impl:E,instance:null,prevProps:null,props:d,state:C}}function Rd(f){return f.tag===ce&&f.memoizedState!==null}function D1(f){return f.child.sibling.child}var Jh={};function fp(f,d,E){if(Au){if(f.tag===q){var C=f.type,A=f.memoizedProps,j=f.stateNode,V=N0(j);V!==null&&d(C,A||Jh,V)===!0&&E.push(V)}var te=f.child;Rd(f)&&(te=D1(f)),te!==null&&cp(te,d,E)}}function Zh(f,d){if(Au){if(f.tag===q){var E=f.type,C=f.memoizedProps,A=f.stateNode,j=N0(A);if(j!==null&&d(E,C,j)===!0)return j}var V=f.child;if(Rd(f)&&(V=D1(f)),V!==null)return $h(V,d)}return null}function cp(f,d,E){for(var C=f;C!==null;)fp(C,d,E),C=C.sibling}function $h(f,d){for(var E=f;E!==null;){var C=Zh(E,d);if(C!==null)return C;E=E.sibling}return null}function ev(f,d,E){if(Ad(f,d))E.push(f.stateNode.methods);else{var C=f.child;Rd(f)&&(C=D1(f)),C!==null&&dp(C,d,E)}}function dp(f,d,E){for(var C=f;C!==null;)ev(C,d,E),C=C.sibling}function Ad(f,d){return f.tag===Xe&&f.type===d&&f.stateNode!==null}function Od(f,d){return{getChildren:function(){var E=d.fiber,C=E.child,A=[];return C!==null&&dp(C,f,A),A.length===0?null:A},getChildrenFromRoot:function(){for(var E=d.fiber,C=E;C!==null;){var A=C.return;if(A===null||(C=A,C.tag===Xe&&C.type===f))break}var j=[];return dp(C.child,f,j),j.length===0?null:j},getParent:function(){for(var E=d.fiber.return;E!==null;){if(E.tag===Xe&&E.type===f)return E.stateNode.methods;E=E.return}return null},getProps:function(){var E=d.fiber;return E.memoizedProps},queryAllNodes:function(E){var C=d.fiber,A=C.child,j=[];return A!==null&&cp(A,E,j),j.length===0?null:j},queryFirstNode:function(E){var C=d.fiber,A=C.child;return A!==null?$h(A,E):null},containsNode:function(E){for(var C=cr(E);C!==null;){if(C.tag===Xe&&C.type===f&&C.stateNode===d)return!0;C=C.return}return!1}}}function qo(f){f.effectTag|=Dr}function Md(f){f.effectTag|=O0}var xa,ef,kd,Ld;if(Bo)xa=function(f,d,E,C){for(var A=d.child;A!==null;){if(A.tag===q||A.tag===ne)Qr(f,A.stateNode);else if(Vt&&A.tag===pt)Qr(f,A.stateNode.instance);else if(A.tag!==H){if(A.child!==null){A.child.return=A,A=A.child;continue}}if(A===d)return;for(;A.sibling===null;){if(A.return===null||A.return===d)return;A=A.return}A.sibling.return=A.return,A=A.sibling}},ef=function(f){},kd=function(f,d,E,C,A){var j=f.memoizedProps;if(j!==C){var V=d.stateNode,te=fl(),se=vo(V,E,j,C,A,te);d.updateQueue=se,se&&qo(d)}},Ld=function(f,d,E,C){E!==C&&qo(d)};else if(Q){xa=function(f,d,E,C){for(var A=d.child;A!==null;){e:if(A.tag===q){var j=A.stateNode;if(E&&C){var V=A.memoizedProps,te=A.type;j=$r(j,te,V,A)}Qr(f,j)}else if(A.tag===ne){var se=A.stateNode;if(E&&C){var Ue=A.memoizedProps;se=$l(se,Ue,A)}Qr(f,se)}else if(Vt&&A.tag===pt){var Qe=A.stateNode.instance;if(E&&C){var vt=A.memoizedProps,Nt=A.type;Qe=$r(Qe,Nt,vt,A)}Qr(f,Qe)}else if(A.tag!==H){if(A.tag===ce){if((A.effectTag&Dr)!==xi){var Yt=A.memoizedState!==null;if(Yt){var Ht=A.child;if(Ht!==null){Ht.child!==null&&(Ht.child.return=Ht,xa(f,Ht,!0,Yt));var yn=Ht.sibling;if(yn!==null){yn.return=A,A=yn;continue}}}}if(A.child!==null){A.child.return=A,A=A.child;continue}}else if(A.child!==null){A.child.return=A,A=A.child;continue}}if(A=A,A===d)return;for(;A.sibling===null;){if(A.return===null||A.return===d)return;A=A.return}A.sibling.return=A.return,A=A.sibling}};var pp=function(f,d,E,C){for(var A=d.child;A!==null;){e:if(A.tag===q){var j=A.stateNode;if(E&&C){var V=A.memoizedProps,te=A.type;j=$r(j,te,V,A)}Qn(f,j)}else if(A.tag===ne){var se=A.stateNode;if(E&&C){var Ue=A.memoizedProps;se=$l(se,Ue,A)}Qn(f,se)}else if(Vt&&A.tag===pt){var Qe=A.stateNode.instance;if(E&&C){var vt=A.memoizedProps,Nt=A.type;Qe=$r(Qe,Nt,vt,A)}Qn(f,Qe)}else if(A.tag!==H){if(A.tag===ce){if((A.effectTag&Dr)!==xi){var Yt=A.memoizedState!==null;if(Yt){var Ht=A.child;if(Ht!==null){Ht.child!==null&&(Ht.child.return=Ht,pp(f,Ht,!0,Yt));var yn=Ht.sibling;if(yn!==null){yn.return=A,A=yn;continue}}}}if(A.child!==null){A.child.return=A,A=A.child;continue}}else if(A.child!==null){A.child.return=A,A=A.child;continue}}if(A=A,A===d)return;for(;A.sibling===null;){if(A.return===null||A.return===d)return;A=A.return}A.sibling.return=A.return,A=A.sibling}};ef=function(f){var d=f.stateNode,E=f.firstEffect===null;if(!E){var C=d.containerInfo,A=To(C);pp(A,f,!1,!1),d.pendingChildren=A,qo(f),fc(C,A)}},kd=function(f,d,E,C,A){var j=f.stateNode,V=f.memoizedProps,te=d.firstEffect===null;if(te&&V===C){d.stateNode=j;return}var se=d.stateNode,Ue=fl(),Qe=null;if(V!==C&&(Qe=vo(se,E,V,C,A,Ue)),te&&Qe===null){d.stateNode=j;return}var vt=ys(j,Qe,E,V,C,d,te,se);Ou(vt,E,C,A,Ue)&&qo(d),d.stateNode=vt,te?qo(d):xa(vt,d,!1,!1)},Ld=function(f,d,E,C){if(E!==C){var A=rs(),j=fl();d.stateNode=vs(C,A,j,d),qo(d)}}}else ef=function(f){},kd=function(f,d,E,C,A){},Ld=function(f,d,E,C){};function Nd(f,d){switch(f.tailMode){case"hidden":{for(var E=f.tail,C=null;E!==null;)E.alternate!==null&&(C=E),E=E.sibling;C===null?f.tail=null:C.sibling=null;break}case"collapsed":{for(var A=f.tail,j=null;A!==null;)A.alternate!==null&&(j=A),A=A.sibling;j===null?!d&&f.tail!==null?f.tail.sibling=null:f.tail=null:j.sibling=null;break}}}function tv(f,d,E){var C=d.pendingProps;switch(d.tag){case T:break;case we:break;case re:case N:break;case O:{var A=d.type;Xi(A)&&qs(d);break}case B:{o0(d),Ao(d);var j=d.stateNode;if(j.pendingContext&&(j.context=j.pendingContext,j.pendingContext=null),f===null||f.child===null){var V=h1(d);V&&qo(d)}ef(d);break}case q:{L2(d);var te=rs(),se=d.type;if(f!==null&&d.stateNode!=null){if(kd(f,d,se,C,te),gi){var Ue=f.memoizedProps.listeners,Qe=C.listeners;Ue!==Qe&&qo(d)}f.ref!==d.ref&&Md(d)}else{if(!C){if(d.stateNode===null)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");break}var vt=fl(),Nt=h1(d);if(Nt){if(vm(d,te,vt)&&qo(d),gi){var Yt=C.listeners;Yt!=null&&hn(Yt,d,te)}}else{var Ht=Ki(se,C,te,vt,d);if(xa(Ht,d,!1,!1),d.stateNode=Ht,gi){var yn=C.listeners;yn!=null&&hn(yn,d,te)}Ou(Ht,se,C,te,vt)&&qo(d)}d.ref!==null&&Md(d)}break}case ne:{var kr=C;if(f&&d.stateNode!=null){var oi=f.memoizedProps;Ld(f,d,oi,kr)}else{if(typeof kr!="string"&&d.stateNode===null)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");var Oi=rs(),Fo=fl(),$i=h1(d);$i?mm(d)&&qo(d):d.stateNode=vs(kr,Oi,Fo,d)}break}case ue:break;case ce:{Ea(d);var ot=d.memoizedState;if(Ai&&ot!==null&&ot.dehydrated!==null)if(f===null){var Ot=h1(d);if(!Ot)throw Error("A dehydrated suspense component was completed without a hydrated node. This is probably a bug in React.");return Ih(d),bn&&x(Di),null}else return v1(),(d.effectTag&Xr)===xi&&(d.memoizedState=null),d.effectTag|=Dr,null;if((d.effectTag&Xr)!==xi)return d.expirationTime=E,d;var $e=ot!==null,Ut=!1;if(f===null)d.memoizedProps.fallback!==void 0&&h1(d);else{var Pn=f.memoizedState;if(Ut=Pn!==null,!$e&&Pn!==null){var vn=f.child.sibling;if(vn!==null){var Wi=d.firstEffect;Wi!==null?(d.firstEffect=vn,vn.nextEffect=Wi):(d.firstEffect=d.lastEffect=vn,vn.nextEffect=null),vn.effectTag=Ko}}}if($e&&!Ut&&(d.mode&Y)!==Ar){var pi=f===null&&d.memoizedProps.unstable_avoidThisFallback!==!0;pi||t1(Ll.current,Rf)?_v():Ev()}Q&&$e&&(d.effectTag|=Dr),Bo&&($e||Ut)&&(d.effectTag|=Dr),Yi&&d.updateQueue!==null&&d.memoizedProps.suspenseCallback!=null&&(d.effectTag|=Dr);break}case m:break;case pe:break;case _e:break;case H:o0(d),ef(d);break;case ve:io(d);break;case ge:break;case me:break;case Ie:{var Ku=d.type;Xi(Ku)&&qs(d);break}case ct:{Ea(d);var hr=d.memoizedState;if(hr===null)break;var hu=(d.effectTag&Xr)!==xi,Kr=hr.rendering;if(Kr===null)if(hu)Nd(hr,!1);else{var xu=Dv()&&(f===null||(f.effectTag&Xr)===xi);if(!xu)for(var So=d.child;So!==null;){var Vo=n1(So);if(Vo!==null){hu=!0,d.effectTag|=Xr,Nd(hr,!1);var ks=Vo.updateQueue;return ks!==null&&(d.updateQueue=ks,d.effectTag|=Dr),hr.lastEffect===null&&(d.firstEffect=null),d.lastEffect=hr.lastEffect,am(d,E),Fr(d,vd(Ll.current,e1)),d.child}So=So.sibling}}else{if(!hu){var Xu=n1(Kr);if(Xu!==null){d.effectTag|=Xr,hu=!0;var gl=Xu.updateQueue;if(gl!==null&&(d.updateQueue=gl,d.effectTag|=Dr),Nd(hr,!0),hr.tail===null&&hr.tailMode==="hidden"&&!Kr.alternate){var uf=d.lastEffect=hr.lastEffect;return uf!==null&&(uf.nextEffect=null),null}}else if(yt()>hr.tailExpiration&&E>Di){d.effectTag|=Xr,hu=!0,Nd(hr,!1);var V0=E-1;d.expirationTime=d.childExpirationTime=V0,bn&&x(V0)}}if(hr.isBackwards)Kr.sibling=d.child,d.child=Kr;else{var Ls=hr.last;Ls!==null?Ls.sibling=Kr:d.child=Kr,hr.last=Kr}}if(hr.tail!==null){if(hr.tailExpiration===0){var $d=500;hr.tailExpiration=yt()+$d}var Gf=hr.tail;hr.rendering=Gf,hr.tail=Gf.sibling,hr.lastEffect=d.lastEffect,Gf.sibling=null;var Fc=Ll.current;return hu?Fc=vd(Fc,e1):Fc=ga(Fc),Fr(d,Fc),Gf}break}case pt:{if(Vt){var Hl=d.type.impl,G0=d.stateNode;if(G0===null){var N1=Hl.getInitialState,v_;N1!==void 0&&(v_=N1(C)),G0=d.stateNode=Qh(d,C,Hl,v_||{});var m_=ht(G0);if(G0.instance=m_,Hl.reconcileChildren===!1)return null;xa(m_,d,!1,!1),Yn(G0)}else{var EE=G0.props;if(G0.prevProps=EE,G0.props=C,G0.currentFiber=d,Q){var y_=la(G0);G0.instance=y_,xa(y_,d,!1,!1)}var DE=Cn(G0);DE&&qo(d)}}break}case Xe:{if(Au)if(f===null){var wE=d.type,Ry={fiber:d,methods:null};if(d.stateNode=Ry,Ry.methods=Od(wE,Ry),gi){var g_=C.listeners;if(g_!=null){var SE=rs();hn(g_,d,SE)}}d.ref!==null&&(Md(d),qo(d))}else{if(gi){var TE=f.memoizedProps.listeners,CE=C.listeners;(TE!==CE||d.ref!==null)&&qo(d)}else d.ref!==null&&qo(d);f.ref!==d.ref&&Md(d)}break}default:throw Error("Unknown unit of work tag ("+d.tag+"). This error is likely caused by a bug in React. Please file an issue.")}return null}function Mm(f,d){switch(f.tag){case O:{var E=f.type;Xi(E)&&qs(f);var C=f.effectTag;return C&ho?(f.effectTag=C&~ho|Xr,f):null}case B:{o0(f),Ao(f);var A=f.effectTag;if((A&Xr)!==xi)throw Error("The root failed to unmount after an error. This is likely a bug in React. Please file an issue.");return f.effectTag=A&~ho|Xr,f}case q:return L2(f),null;case ce:{if(Ea(f),Ai){var j=f.memoizedState;if(j!==null&&j.dehydrated!==null){if(f.alternate===null)throw Error("Threw in newly mounted dehydrated component. This is likely a bug in React. Please file an issue.");v1()}}var V=f.effectTag;return V&ho?(f.effectTag=V&~ho|Xr,f):null}case ct:return Ea(f),null;case H:return o0(f),null;case ve:return io(f),null;default:return null}}function nv(f){switch(f.tag){case O:{var d=f.type.childContextTypes;d!=null&&qs(f);break}case B:{o0(f),Ao(f);break}case q:{L2(f);break}case H:o0(f);break;case ce:Ea(f);break;case ct:Ea(f);break;case ve:io(f);break;default:break}}function hp(f,d){return{value:f,source:d,stack:Cr(d)}}var vp=function(f,d,E,C,A,j,V,te,se){var Ue=Array.prototype.slice.call(arguments,3);try{d.apply(E,Ue)}catch(Qe){this.onError(Qe)}};if(typeof window!="undefined"&&typeof window.dispatchEvent=="function"&&typeof document!="undefined"&&typeof document.createEvent=="function"){var mp=document.createElement("react"),km=function(f,d,E,C,A,j,V,te,se){if(typeof document=="undefined")throw Error("The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous.");var Ue=document.createEvent("Event"),Qe=!0,vt=window.event,Nt=Object.getOwnPropertyDescriptor(window,"event"),Yt=Array.prototype.slice.call(arguments,3);function Ht(){mp.removeEventListener(Fo,Ht,!1),typeof window.event!="undefined"&&window.hasOwnProperty("event")&&(window.event=vt),d.apply(E,Yt),Qe=!1}var yn,kr=!1,oi=!1;function Oi($i){if(yn=$i.error,kr=!0,yn===null&&$i.colno===0&&$i.lineno===0&&(oi=!0),$i.defaultPrevented&&yn!=null&&typeof yn=="object")try{yn._suppressLogging=!0}catch(ot){}}var Fo="react-"+(f||"invokeguardedcallback");window.addEventListener("error",Oi),mp.addEventListener(Fo,Ht,!1),Ue.initEvent(Fo,!1,!1),mp.dispatchEvent(Ue),Nt&&Object.defineProperty(window,"event",Nt),Qe&&(kr?oi&&(yn=new Error("A cross-origin error was thrown. React doesn't have access to the actual error object in development. See https://fb.me/react-crossorigin-error for more information.")):yn=new Error(`An error was thrown inside one of your components, but React doesn't know what it was. This is likely due to browser flakiness. React does its best to preserve the "Pause on exceptions" behavior of the DevTools, which requires some DEV-mode only tricks. It's possible that these don't work in your browser. Try triggering the error in production mode, or switching to a modern browser. If you suspect that this is actually an issue with React, please file an issue.`),this.onError(yn)),window.removeEventListener("error",Oi)};vp=km}var Lm=vp,S0=!1,Fd=null,Nm={onError:function(f){S0=!0,Fd=f}};function pl(f,d,E,C,A,j,V,te,se){S0=!1,Fd=null,Lm.apply(Nm,arguments)}function tr(){return S0}function Js(){if(S0){var f=Fd;return S0=!1,Fd=null,f}else throw Error("clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.")}function hl(f){return!0}function lo(f){var d=hl(f);if(d!==!1){var E=f.error;{var C=f.componentName,A=f.componentStack,j=f.errorBoundaryName,V=f.errorBoundaryFound,te=f.willRetry;if(E!=null&&E._suppressLogging){if(V&&te)return;console.error(E)}var se=C?"The above error occurred in the <"+C+"> component:":"The above error occurred in one of your React components:",Ue;V&&j?te?Ue="React will try to recreate this component tree from scratch "+("using the error boundary you provided, "+j+"."):Ue="This error was initially handled by the error boundary "+j+`. -Recreating the tree from scratch failed so React will unmount the tree.`:Ue=`Consider adding an error boundary to your tree to customize error handling behavior. -Visit https://fb.me/react-error-boundaries to learn more about error boundaries.`;var Qe=""+se+A+` - -`+(""+Ue);console.error(Qe)}}}var rv=null;rv=new Set;var Zs=typeof WeakSet=="function"?WeakSet:Set;function yp(f,d){var E=d.source,C=d.stack;C===null&&E!==null&&(C=Cr(E));var A={componentName:E!==null?Wt(E.type):null,componentStack:C!==null?C:"",error:d.value,errorBoundary:null,errorBoundaryName:null,errorBoundaryFound:!1,willRetry:!1};f!==null&&f.tag===O&&(A.errorBoundary=f.stateNode,A.errorBoundaryName=Wt(f.type),A.errorBoundaryFound=!0,A.willRetry=!0);try{lo(A)}catch(j){setTimeout(function(){throw j})}}var Fm=function(f,d){Bi(f,"componentWillUnmount"),d.props=f.memoizedProps,d.state=f.memoizedState,d.componentWillUnmount(),Ci()};function iv(f,d){if(pl(null,Fm,null,f,d),tr()){var E=Js();qf(f,E)}}function gp(f){var d=f.ref;if(d!==null)if(typeof d=="function"){if(pl(null,d,null,null),tr()){var E=Js();qf(f,E)}}else d.current=null}function Pm(f,d){if(pl(null,d,null),tr()){var E=Js();qf(f,E)}}function _p(f,d){switch(d.tag){case N:case ue:case re:{Cc(cm,Of,d);return}case O:{if(d.effectTag&M0&&f!==null){var E=f.memoizedProps,C=f.memoizedState;Bi(d,"getSnapshotBeforeUpdate");var A=d.stateNode;d.type===d.elementType&&!Ta&&(A.props!==d.memoizedProps&&Qt(!1,"Expected %s props to match memoized props before getSnapshotBeforeUpdate. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(d.type)||"instance"),A.state!==d.memoizedState&&Qt(!1,"Expected %s state to match memoized state before getSnapshotBeforeUpdate. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(d.type)||"instance"));var j=A.getSnapshotBeforeUpdate(d.elementType===d.type?E:qi(d.type,E),C);{var V=rv;j===void 0&&!V.has(d.type)&&(V.add(d.type),He(!1,"%s.getSnapshotBeforeUpdate(): A snapshot value (or null) must be returned. You have returned undefined.",Wt(d.type)))}A.__reactInternalSnapshotBeforeUpdate=j,Ci()}return}case B:case q:case ne:case H:case Ie:return;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}function Cc(f,d,E){var C=E.updateQueue,A=C!==null?C.lastEffect:null;if(A!==null){var j=A.next,V=j;do{if((V.tag&f)!==Of){var te=V.destroy;V.destroy=void 0,te!==void 0&&te()}if((V.tag&d)!==Of){var se=V.create;V.destroy=se();{var Ue=V.destroy;if(Ue!==void 0&&typeof Ue!="function"){var Qe=void 0;Ue===null?Qe=" You returned null. If your effect does not require clean up, return undefined (or nothing).":typeof Ue.then=="function"?Qe=` - -It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately: - -useEffect(() => { - async function fetchData() { - // You can await here - const response = await MyAPI.getData(someId); - // ... - } - fetchData(); -}, [someId]); // Or [] if effect doesn't need props or state - -Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching`:Qe=" You returned: "+Ue,He(!1,"An effect function must not return anything besides a function, which is used for clean-up.%s%s",Qe,Cr(E))}}}V=V.next}while(V!==j)}}function Ra(f){if((f.effectTag&Po)!==xi)switch(f.tag){case N:case ue:case re:{Cc(sr,Of,f),Cc(Of,r1,f);break}default:break}}function Ep(f,d,E,C){switch(E.tag){case N:case ue:case re:{Cc(dm,cl,E);break}case O:{var A=E.stateNode;if(E.effectTag&Dr)if(d===null)Bi(E,"componentDidMount"),E.type===E.elementType&&!Ta&&(A.props!==E.memoizedProps&&Qt(!1,"Expected %s props to match memoized props before componentDidMount. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance"),A.state!==E.memoizedState&&Qt(!1,"Expected %s state to match memoized state before componentDidMount. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance")),A.componentDidMount(),Ci();else{var j=E.elementType===E.type?d.memoizedProps:qi(E.type,d.memoizedProps),V=d.memoizedState;Bi(E,"componentDidUpdate"),E.type===E.elementType&&!Ta&&(A.props!==E.memoizedProps&&Qt(!1,"Expected %s props to match memoized props before componentDidUpdate. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance"),A.state!==E.memoizedState&&Qt(!1,"Expected %s state to match memoized state before componentDidUpdate. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance")),A.componentDidUpdate(j,V,A.__reactInternalSnapshotBeforeUpdate),Ci()}var te=E.updateQueue;te!==null&&(E.type===E.elementType&&!Ta&&(A.props!==E.memoizedProps&&Qt(!1,"Expected %s props to match memoized props before processing the update queue. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance"),A.state!==E.memoizedState&&Qt(!1,"Expected %s state to match memoized state before processing the update queue. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.",Wt(E.type)||"instance")),g0(E,te,A,C));return}case B:{var se=E.updateQueue;if(se!==null){var Ue=null;if(E.child!==null)switch(E.child.tag){case q:Ue=N0(E.child.stateNode);break;case O:Ue=E.child.stateNode;break}g0(E,se,Ue,C)}return}case q:{var Qe=E.stateNode;if(d===null&&E.effectTag&Dr){var vt=E.type,Nt=E.memoizedProps;Hu(Qe,vt,Nt,E)}return}case ne:return;case H:return;case _e:{if(en){var Yt=E.memoizedProps.onRender;typeof Yt=="function"&&(bn?Yt(E.memoizedProps.id,d===null?"mount":"update",E.actualDuration,E.treeBaseDuration,E.actualStartTime,Il(),f.memoizedInteractions):Yt(E.memoizedProps.id,d===null?"mount":"update",E.actualDuration,E.treeBaseDuration,E.actualStartTime,Il()))}return}case ce:{Bl(f,E);return}case ct:case Ie:case pt:case Xe:return;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}function Pd(f,d){if(Bo)for(var E=f;;){if(E.tag===q){var C=E.stateNode;d?Ia(C):ua(E.stateNode,E.memoizedProps)}else if(E.tag===ne){var A=E.stateNode;d?yo(A):Zo(A,E.memoizedProps)}else if(E.tag===ce&&E.memoizedState!==null&&E.memoizedState.dehydrated===null){var j=E.child.sibling;j.return=E,E=j;continue}else if(E.child!==null){E.child.return=E,E=E.child;continue}if(E===f)return;for(;E.sibling===null;){if(E.return===null||E.return===f)return;E=E.return}E.sibling.return=E.return,E=E.sibling}}function bu(f){var d=f.ref;if(d!==null){var E=f.stateNode,C;switch(f.tag){case q:C=N0(E);break;default:C=E}Au&&f.tag===Xe&&(C=E.methods),typeof d=="function"?d(C):(d.hasOwnProperty("current")||He(!1,"Unexpected ref object provided for %s. Use either a ref-setter function or React.createRef().%s",Wt(f.type),Cr(f)),d.current=C)}}function Yu(f){var d=f.ref;d!==null&&(typeof d=="function"?d(null):d.current=null)}function Dp(f,d,E){switch(kn(d),d.tag){case N:case ue:case me:case re:{var C=d.updateQueue;if(C!==null){var A=C.lastEffect;if(A!==null){var j=A.next,V=E>Kn?Kn:E;Sn(V,function(){var oi=j;do{var Oi=oi.destroy;Oi!==void 0&&Pm(d,Oi),oi=oi.next}while(oi!==j)})}}break}case O:{gp(d);var te=d.stateNode;typeof te.componentWillUnmount=="function"&&iv(d,te);return}case q:{if(gi){var se=d.dependencies;if(se!==null){var Ue=se.responders;if(Ue!==null){for(var Qe=Array.from(Ue.values()),vt=0,Nt=Qe.length;vt component higher in the tree to provide a loading indicator or placeholder to display.`+Cr(E))}kp(),C=hp(C,E);var Nt=d;do{switch(Nt.tag){case B:{var Yt=C;Nt.effectTag|=ho,Nt.expirationTime=A;var Ht=sv(Nt,Yt,A);ld(Nt,Ht);return}case O:var yn=C,kr=Nt.type,oi=Nt.stateNode;if((Nt.effectTag&Xr)===xi&&(typeof kr.getDerivedStateFromError=="function"||oi!==null&&typeof oi.componentDidCatch=="function"&&!Ip(oi))){Nt.effectTag|=ho,Nt.expirationTime=A;var Oi=av(Nt,yn,A);ld(Nt,Oi);return}break;default:break}Nt=Nt.return}while(Nt!==null)}var Oa=Math.ceil,Mr=nt.ReactCurrentDispatcher,Sp=nt.ReactCurrentOwner,vl=nt.IsSomeRendererActing,gu=0,T1=1,Ui=2,Tp=4,Bd=8,T0=16,Os=32,Bf=0,Ud=1,Cp=2,C1=3,x1=4,xp=5,nr=gu,ml=null,Gn=null,Wo=at,Lo=Bf,jd=null,Ul=Un,R1=Un,Rc=null,Ac=at,zd=!1,Rp=0,No=500,dn=null,Hd=!1,qd=null,Oc=null,Mc=!1,kc=null,A1=Do,Ap=at,tf=null,Hm=50,Lc=0,Wd=null,cv=50,O1=0,Uf=null,jf=null,M1=at;function jl(){return(nr&(T0|Os))!==gu?no(yt()):(M1!==at||(M1=no(yt())),M1)}function Nc(){return no(yt())}function zf(f,d,E){var C=d.mode;if((C&Y)===Ar)return Un;var A=Jt();if((C&ri)===Ar)return A===Ni?Un:to;if((nr&T0)!==gu)return Wo;var j;if(E!==null)j=ca(f,E.timeoutMs|0||Ef);else switch(A){case Ni:j=Un;break;case ni:j=ja(f);break;case Kn:case eo:j=ws(f);break;case Eo:j=ru;break;default:throw Error("Expected a valid priority level")}return ml!==null&&j===Wo&&(j-=1),j}function qm(f,d){sy(),dy(f);var E=Vd(f,d);if(E===null){fy(f);return}Hp(f,d),sa();var C=Jt();if(d===Un?(nr&Bd)!==gu&&(nr&(T0|Os))===gu?(W(E,d),k1(E)):(W0(E),W(E,d),nr===gu&&Bt()):(W0(E),W(E,d)),(nr&Tp)!==gu&&(C===ni||C===Ni))if(tf===null)tf=new Map([[E,d]]);else{var A=tf.get(E);(A===void 0||A>d)&&tf.set(E,d)}}var yl=qm;function Vd(f,d){f.expirationTimeA?C:A}function W0(f){var d=f.lastExpiredTime;if(d!==at){f.callbackExpirationTime=Un,f.callbackPriority=Ni,f.callbackNode=Tn(k1.bind(null,f));return}var E=Gd(f),C=f.callbackNode;if(E===at){C!==null&&(f.callbackNode=null,f.callbackExpirationTime=at,f.callbackPriority=Do);return}var A=jl(),j=rd(A,E);if(C!==null){var V=f.callbackPriority,te=f.callbackExpirationTime;if(te===E&&V>=j)return;ir(C)}f.callbackExpirationTime=E,f.callbackPriority=j;var se;E===Un?se=Tn(k1.bind(null,f)):f0?se=_n(j,Yd.bind(null,f)):se=_n(j,Yd.bind(null,f),{timeout:j0(E)-yt()}),f.callbackNode=se}function Yd(f,d){if(M1=at,d){var E=jl();return Vp(f,E),W0(f),null}var C=Gd(f);if(C!==at){var A=f.callbackNode;if((nr&(T0|Os))!==gu)throw Error("Should not already be working.");if(nf(),(f!==ml||C!==Wo)&&(Hf(f,C),ee(f,C)),Gn!==null){var j=nr;nr|=T0;var V=mv(f),te=Kd(f);yf(Gn);do try{ey();break}catch(Qe){vv(f,Qe)}while(!0);if(gt(),nr=j,yv(V),bn&&Xd(te),Lo===Ud){var se=jd;throw zp(),Hf(f,C),Vf(f,C),W0(f),se}if(Gn!==null)zp();else{Rv();var Ue=f.finishedWork=f.current.alternate;f.finishedExpirationTime=C,Wm(f,Ue,Lo,C)}if(W0(f),f.callbackNode===A)return Yd.bind(null,f)}}return null}function Wm(f,d,E,C){switch(ml=null,E){case Bf:case Ud:throw Error("Root did not complete. This is a bug in React.");case Cp:{Vp(f,C>ru?ru:C);break}case C1:{Vf(f,C);var A=f.lastSuspendedTime;C===A&&(f.nextKnownPendingLevel=Lp(d)),p();var j=Ul===Un;if(j&&!(Jo&&Wf.current)){var V=Rp+No-yt();if(V>10){if(zd){var te=f.lastPingedTime;if(te===at||te>=C){f.lastPingedTime=C,Hf(f,C);break}}var se=Gd(f);if(se!==at&&se!==C)break;if(A!==at&&A!==C){f.lastPingedTime=A;break}f.timeoutHandle=Tt(so.bind(null,f),V);break}}so(f);break}case x1:{Vf(f,C);var Ue=f.lastSuspendedTime;if(C===Ue&&(f.nextKnownPendingLevel=Lp(d)),p(),!(Jo&&Wf.current)){if(zd){var Qe=f.lastPingedTime;if(Qe===at||Qe>=C){f.lastPingedTime=C,Hf(f,C);break}}var vt=Gd(f);if(vt!==at&&vt!==C)break;if(Ue!==at&&Ue!==C){f.lastPingedTime=Ue;break}var Nt;if(R1!==Un)Nt=j0(R1)-yt();else if(Ul===Un)Nt=0;else{var Yt=wv(Ul),Ht=yt(),yn=j0(C)-Ht,kr=Ht-Yt;kr<0&&(kr=0),Nt=Up(kr)-kr,yn10){f.timeoutHandle=Tt(so.bind(null,f),Nt);break}}so(f);break}case xp:{if(!(Jo&&Wf.current)&&Ul!==Un&&Rc!==null){var oi=jp(Ul,C,Rc);if(oi>10){Vf(f,C),f.timeoutHandle=Tt(so.bind(null,f),oi);break}}so(f);break}default:throw Error("Unknown root exit status.")}}function k1(f){var d=f.lastExpiredTime,E=d!==at?d:Un;if(f.finishedExpirationTime===E)so(f);else{if((nr&(T0|Os))!==gu)throw Error("Should not already be working.");if(nf(),(f!==ml||E!==Wo)&&(Hf(f,E),ee(f,E)),Gn!==null){var C=nr;nr|=T0;var A=mv(f),j=Kd(f);yf(Gn);do try{Sv();break}catch(te){vv(f,te)}while(!0);if(gt(),nr=C,yv(A),bn&&Xd(j),Lo===Ud){var V=jd;throw zp(),Hf(f,E),Vf(f,E),W0(f),V}if(Gn!==null)throw Error("Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue.");Rv(),f.finishedWork=f.current.alternate,f.finishedExpirationTime=E,Vm(f,Lo,E),W0(f)}}return null}function Vm(f,d,E){ml=null,(d===C1||d===x1)&&p(),so(f)}function Gm(f,d){Vp(f,d),W0(f),(nr&(T0|Os))===gu&&Bt()}function dv(){if((nr&(T1|T0|Os))!==gu){(nr&T0)!==gu&&Qt(!1,"unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.");return}Km(),nf()}function Ym(f){return Sn(Kn,f)}function pv(f,d,E,C){return Sn(Ni,f.bind(null,d,E,C))}function Km(){if(tf!==null){var f=tf;tf=null,f.forEach(function(d,E){Vp(E,d),W0(E)}),Bt()}}function Xm(f,d){var E=nr;nr|=T1;try{return f(d)}finally{nr=E,nr===gu&&Bt()}}function Qm(f,d){var E=nr;nr|=Ui;try{return f(d)}finally{nr=E,nr===gu&&Bt()}}function hv(f,d,E,C){var A=nr;nr|=Tp;try{return Sn(ni,f.bind(null,d,E,C))}finally{nr=A,nr===gu&&Bt()}}function Jm(f,d){var E=nr;nr&=~T1,nr|=Bd;try{return f(d)}finally{nr=E,nr===gu&&Bt()}}function Op(f,d){if((nr&(T0|Os))!==gu)throw Error("flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.");var E=nr;nr|=T1;try{return Sn(Ni,f.bind(null,d))}finally{nr=E,Bt()}}function Zm(f){var d=nr;nr|=T1;try{Sn(Ni,f)}finally{nr=d,nr===gu&&Bt()}}function Hf(f,d){f.finishedWork=null,f.finishedExpirationTime=at;var E=f.timeoutHandle;if(E!==nl&&(f.timeoutHandle=nl,d0(E)),Gn!==null)for(var C=Gn.return;C!==null;)nv(C),C=C.return;ml=f,Gn=C0(f.current,null,d),Wo=d,Lo=Bf,jd=null,Ul=Un,R1=Un,Rc=null,Ac=at,zd=!1,bn&&(jf=null),Al.discardPendingWarnings(),$s=null}function vv(f,d){do{try{if(gt(),Ed(),ut(),Gn===null||Gn.return===null)return Lo=Ud,jd=d,null;en&&Gn.mode&ii&&p1(Gn,!0),fv(f,Gn.return,Gn,d,Wo),Gn=Tv(Gn)}catch(E){d=E;continue}return}while(!0)}function mv(f){var d=Mr.current;return Mr.current=f1,d===null?f1:d}function yv(f){Mr.current=f}function Kd(f){if(bn){var d=M.__interactionsRef.current;return M.__interactionsRef.current=f.memoizedInteractions,d}return null}function Xd(f){bn&&(M.__interactionsRef.current=f)}function Mp(){Rp=yt()}function gv(f,d){fru&&(Ul=f),d!==null&&fru&&(R1=f,Rc=d)}function Qd(f){f>Ac&&(Ac=f)}function _v(){Lo===Bf&&(Lo=C1)}function Ev(){(Lo===Bf||Lo===C1)&&(Lo=x1),Ac!==at&&ml!==null&&(Vf(ml,Wo),u_(ml,Ac))}function kp(){Lo!==xp&&(Lo=Cp)}function Dv(){return Lo===Bf}function wv(f){var d=j0(f);return d-Ef}function $m(f,d){var E=j0(f);return E-(d.timeoutMs|0||Ef)}function Sv(){for(;Gn!==null;)Gn=Jd(Gn)}function ey(){for(;Gn!==null&&!Fn();)Gn=Jd(Gn)}function Jd(f){var d=f.alternate;es(f),Dt(f);var E;return en&&(f.mode&ii)!==Ar?(W2(f),E=L1(d,f,Wo),p1(f,!0)):E=L1(d,f,Wo),ut(),f.memoizedProps=f.pendingProps,E===null&&(E=Tv(f)),Sp.current=null,E}function Tv(f){Gn=f;do{var d=Gn.alternate,E=Gn.return;if((Gn.effectTag&Io)===xi){Dt(Gn);var C=void 0;if(!en||(Gn.mode&ii)===Ar?C=tv(d,Gn,Wo):(W2(Gn),C=tv(d,Gn,Wo),p1(Gn,!1)),ei(Gn),ut(),ty(Gn),C!==null)return C;if(E!==null&&(E.effectTag&Io)===xi){E.firstEffect===null&&(E.firstEffect=Gn.firstEffect),Gn.lastEffect!==null&&(E.lastEffect!==null&&(E.lastEffect.nextEffect=Gn.firstEffect),E.lastEffect=Gn.lastEffect);var A=Gn.effectTag;A>su&&(E.lastEffect!==null?E.lastEffect.nextEffect=Gn:E.firstEffect=Gn,E.lastEffect=Gn)}}else{var j=Mm(Gn,Wo);if(en&&(Gn.mode&ii)!==Ar){p1(Gn,!1);for(var V=Gn.actualDuration,te=Gn.child;te!==null;)V+=te.actualDuration,te=te.sibling;Gn.actualDuration=V}if(j!==null)return h0(Gn),j.effectTag&=Xl,j;ei(Gn),E!==null&&(E.firstEffect=E.lastEffect=null,E.effectTag|=Io)}var se=Gn.sibling;if(se!==null)return se;Gn=E}while(Gn!==null);return Lo===Bf&&(Lo=xp),null}function Lp(f){var d=f.expirationTime,E=f.childExpirationTime;return d>E?d:E}function ty(f){if(!(Wo!==Di&&f.childExpirationTime===Di)){var d=at;if(en&&(f.mode&ii)!==Ar){for(var E=f.actualDuration,C=f.selfBaseDuration,A=f.alternate===null||f.child!==f.alternate.child,j=f.child;j!==null;){var V=j.expirationTime,te=j.childExpirationTime;V>d&&(d=V),te>d&&(d=te),A&&(E+=j.actualDuration),C+=j.treeBaseDuration,j=j.sibling}f.actualDuration=E,f.treeBaseDuration=C}else for(var se=f.child;se!==null;){var Ue=se.expirationTime,Qe=se.childExpirationTime;Ue>d&&(d=Ue),Qe>d&&(d=Qe),se=se.sibling}f.childExpirationTime=d}}function so(f){var d=Jt();return Sn(Ni,Np.bind(null,f,d)),null}function Np(f,d){do nf();while(kc!==null);if(ay(),(nr&(T0|Os))!==gu)throw Error("Should not already be working.");var E=f.finishedWork,C=f.finishedExpirationTime;if(E===null)return null;if(f.finishedWork=null,f.finishedExpirationTime=at,E===f.current)throw Error("Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue.");f.callbackNode=null,f.callbackExpirationTime=at,f.callbackPriority=Do,f.nextKnownPendingLevel=at,t0();var A=Lp(E);lE(f,C,A),f===ml&&(ml=null,Gn=null,Wo=at);var j;if(E.effectTag>su?E.lastEffect!==null?(E.lastEffect.nextEffect=E,j=E.firstEffect):j=E:j=E.firstEffect,j!==null){var V=nr;nr|=Os;var te=Kd(f);Sp.current=null,Re(),Hn(f.containerInfo),dn=j;do if(pl(null,ny,null),tr()){if(dn===null)throw Error("Should be working on an effect.");var se=Js();qf(dn,se),dn=dn.nextEffect}while(dn!==null);rt(),en&&Lh(),Ye(),dn=j;do if(pl(null,ry,null,f,d),tr()){if(dn===null)throw Error("Should be working on an effect.");var Ue=Js();qf(dn,Ue),dn=dn.nextEffect}while(dn!==null);Kt(),qr(f.containerInfo),f.current=E,Xt(),dn=j;do if(pl(null,Fp,null,f,C),tr()){if(dn===null)throw Error("Should be working on an effect.");var Qe=Js();qf(dn,Qe),dn=dn.nextEffect}while(dn!==null);pr(),dn=null,ae(),bn&&Xd(te),nr=V}else f.current=E,Re(),rt(),en&&Lh(),Ye(),Kt(),Xt(),pr();n0();var vt=Mc;if(Mc)Mc=!1,kc=f,Ap=C,A1=d;else for(dn=j;dn!==null;){var Nt=dn.nextEffect;dn.nextEffect=null,dn=Nt}var Yt=f.firstPendingTime;if(Yt!==at){if(bn){if(jf!==null){var Ht=jf;jf=null;for(var yn=0;ynKn?Kn:A1;return A1=Do,Sn(f,Pp)}}function Pp(){if(kc===null)return!1;var f=kc,d=Ap;if(kc=null,Ap=at,(nr&(T0|Os))!==gu)throw Error("Cannot flush passive effects while already rendering.");var E=nr;nr|=Os;for(var C=Kd(f),A=f.current.firstEffect;A!==null;){{if(Dt(A),pl(null,Ra,null,A),tr()){if(A===null)throw Error("Should be working on an effect.");var j=Js();qf(A,j)}ut()}var V=A.nextEffect;A.nextEffect=null,A=V}return bn&&(Xd(C),he(f,d)),nr=E,Bt(),O1=kc===null?0:O1+1,!0}function Ip(f){return Oc!==null&&Oc.has(f)}function bp(f){Oc===null?Oc=new Set([f]):Oc.add(f)}function iy(f){Hd||(Hd=!0,qd=f)}var uy=iy;function Cv(f,d,E){var C=hp(E,d),A=sv(f,C,Un);Ga(f,A);var j=Vd(f,Un);j!==null&&(W0(j),W(j,Un))}function qf(f,d){if(f.tag===B){Cv(f,f,d);return}for(var E=f.return;E!==null;){if(E.tag===B){Cv(E,f,d);return}else if(E.tag===O){var C=E.type,A=E.stateNode;if(typeof C.getDerivedStateFromError=="function"||typeof A.componentDidCatch=="function"&&!Ip(A)){var j=hp(d,f),V=av(E,j,Un);Ga(E,V);var te=Vd(E,Un);te!==null&&(W0(te),W(te,Un));return}}E=E.return}}function Bp(f,d,E){var C=f.pingCache;if(C!==null&&C.delete(d),ml===f&&Wo===E){Lo===x1||Lo===C1&&Ul===Un&&yt()-RpHm)throw Lc=0,Wd=null,Error("Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.");O1>cv&&(O1=0,Qt(!1,"Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render."))}function ay(){Al.flushLegacyContextWarning(),yi&&Al.flushPendingUnsafeLifecycleWarnings()}function Rv(){var f=!0;gf(Uf,f),Uf=null}function zp(){var f=!1;gf(Uf,f),Uf=null}function Hp(f,d){Hr&&ml!==null&&d>Wo&&(Uf=f)}var Zd=null;function fy(f){{var d=f.tag;if(d!==B&&d!==O&&d!==N&&d!==ue&&d!==me&&d!==re)return;var E=Wt(f.type)||"ReactComponent";if(Zd!==null){if(Zd.has(E))return;Zd.add(E)}else Zd=new Set([E]);He(!1,"Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s",d===O?"the componentWillUnmount method":"a useEffect cleanup function",Cr(f))}}var L1;if(Qo){var cy=null;L1=function(f,d,E){var C=r_(cy,d);try{return ap(f,d,E)}catch(j){if(j!==null&&typeof j=="object"&&typeof j.then=="function")throw j;if(gt(),Ed(),nv(d),r_(d,C),en&&d.mode&ii&&W2(d),pl(null,ap,null,f,d,E),tr()){var A=Js();throw A}else throw j}}}else L1=ap;var Av=!1,Ov=!1;function dy(f){if(f.tag===O)switch(Lr){case"getChildContext":if(Ov)return;He(!1,"setState(...): Cannot call setState() inside getChildContext()"),Ov=!0;break;case"render":if(Av)return;He(!1,"Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state."),Av=!0;break}}var Wf={current:!1};function qp(f){ms===!0&&vl.current===!0&&Wf.current!==!0&&He(!1,`It looks like you're using the wrong act() around your test interactions. -Be sure to use the matching version of act() corresponding to your renderer: - -// for react-dom: -import {act} from 'react-dom/test-utils'; -// ... -act(() => ...); - -// for react-test-renderer: -import TestRenderer from 'react-test-renderer'; -const {act} = TestRenderer; -// ... -act(() => ...);%s`,Cr(f))}function Mv(f){ms===!0&&(f.mode&mr)!==Ar&&vl.current===!1&&Wf.current===!1&&He(!1,`An update to %s ran an effect, but was not wrapped in act(...). - -When testing, code that causes React state updates should be wrapped into act(...): - -act(() => { - /* fire events that update state */ -}); -/* assert on the output */ - -This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act%s`,Wt(f.type),Cr(f))}function py(f){ms===!0&&nr===gu&&vl.current===!1&&Wf.current===!1&&He(!1,`An update to %s inside a test was not wrapped in act(...). - -When testing, code that causes React state updates should be wrapped into act(...): - -act(() => { - /* fire events that update state */ -}); -/* assert on the output */ - -This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act%s`,Wt(f.type),Cr(f))}var hy=py,Wp=!1;function vy(f){Wp===!1&&t.unstable_flushAllWithoutAsserting===void 0&&(f.mode&Y||f.mode&ri?(Wp=!0,He(!1,`In Concurrent or Sync modes, the "scheduler" module needs to be mocked to guarantee consistent behaviour across tests and browsers. For example, with jest: -jest.mock('scheduler', () => require('scheduler/unstable_mock')); - -For more info, visit https://fb.me/react-mock-scheduler`)):eu===!0&&(Wp=!0,He(!1,`Starting from React v17, the "scheduler" module will need to be mocked to guarantee consistent behaviour across tests and browsers. For example, with jest: -jest.mock('scheduler', () => require('scheduler/unstable_mock')); - -For more info, visit https://fb.me/react-mock-scheduler`)))}var $s=null;function my(f){{var d=Jt();if((f.mode&ri)!==xi&&(d===ni||d===Ni))for(var E=f;E!==null;){var C=E.alternate;if(C!==null)switch(E.tag){case O:var A=C.updateQueue;if(A!==null)for(var j=A.firstUpdate;j!==null;){var V=j.priority;if(V===ni||V===Ni){$s===null?$s=new Set([Wt(E.type)]):$s.add(Wt(E.type));break}j=j.next}break;case N:case ue:case re:if(E.memoizedState!==null&&E.memoizedState.baseUpdate!==null)for(var te=E.memoizedState.baseUpdate;te!==null;){var se=te.priority;if(se===ni||se===Ni){$s===null?$s=new Set([Wt(E.type)]):$s.add(Wt(E.type));break}if(te.next===E.memoizedState.baseUpdate)break;te=te.next}break;default:break}E=E.return}}}function p(){if($s!==null){var f=[];$s.forEach(function(d){return f.push(d)}),$s=null,f.length>0&&He(!1,`%s triggered a user-blocking update that suspended. - -The fix is to split the update into multiple parts: a user-blocking update to provide immediate feedback, and another update that triggers the bulk of the changes. - -Refer to the documentation for useTransition to learn how to implement this pattern.`,f.sort().join(", "))}}function v(f,d){return d*1e3+f.interactionThreadID}function x(f){!bn||(jf===null?jf=[f]:jf.push(f))}function P(f,d,E){if(!!bn&&E.size>0){var C=f.pendingInteractionMap,A=C.get(d);A!=null?E.forEach(function(te){A.has(te)||te.__count++,A.add(te)}):(C.set(d,new Set(E)),E.forEach(function(te){te.__count++}));var j=M.__subscriberRef.current;if(j!==null){var V=v(f,d);j.onWorkScheduled(E,V)}}}function W(f,d){!bn||P(f,d,M.__interactionsRef.current)}function ee(f,d){if(!!bn){var E=new Set;if(f.pendingInteractionMap.forEach(function(j,V){V>=d&&j.forEach(function(te){return E.add(te)})}),f.memoizedInteractions=E,E.size>0){var C=M.__subscriberRef.current;if(C!==null){var A=v(f,d);try{C.onWorkStarted(E,A)}catch(j){_n(Ni,function(){throw j})}}}}}function he(f,d){if(!!bn){var E=f.firstPendingTime,C;try{if(C=M.__subscriberRef.current,C!==null&&f.memoizedInteractions.size>0){var A=v(f,d);C.onWorkStopped(f.memoizedInteractions,A)}}catch(V){_n(Ni,function(){throw V})}finally{var j=f.pendingInteractionMap;j.forEach(function(V,te){te>E&&(j.delete(te),V.forEach(function(se){if(se.__count--,C!==null&&se.__count===0)try{C.onInteractionScheduledWorkCompleted(se)}catch(Ue){_n(Ni,function(){throw Ue})}}))})}}}var De=null,be=null,Et=!1,St=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__!="undefined";function At(f){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__=="undefined")return!1;var d=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(d.isDisabled)return!0;if(!d.supportsFiber)return He(!1,"The installed version of React DevTools is too old and will not work with the current version of React. Please update React DevTools. https://fb.me/react-devtools"),!0;try{var E=d.inject(f);De=function(C,A){try{var j=(C.current.effectTag&Xr)===Xr;if(en){var V=Nc(),te=rd(V,A);d.onCommitFiberRoot(E,C,te,j)}else d.onCommitFiberRoot(E,C,void 0,j)}catch(se){Et||(Et=!0,He(!1,"React DevTools encountered an error: %s",se))}},be=function(C){try{d.onCommitFiberUnmount(E,C)}catch(A){Et||(Et=!0,He(!1,"React DevTools encountered an error: %s",A))}}}catch(C){He(!1,"React DevTools encountered an error: %s.",C)}return!0}function on(f,d){typeof De=="function"&&De(f,d)}function kn(f){typeof be=="function"&&be(f)}var rr;{rr=!1;try{var br=Object.preventExtensions({}),ar=new Map([[br,null]]),ui=new Set([br]);ar.set(0,0),ui.add(0)}catch(f){rr=!0}}var di=1;function zl(f,d,E,C){this.tag=f,this.key=E,this.elementType=null,this.type=null,this.stateNode=null,this.return=null,this.child=null,this.sibling=null,this.index=0,this.ref=null,this.pendingProps=d,this.memoizedProps=null,this.updateQueue=null,this.memoizedState=null,this.dependencies=null,this.mode=C,this.effectTag=xi,this.nextEffect=null,this.firstEffect=null,this.lastEffect=null,this.expirationTime=at,this.childExpirationTime=at,this.alternate=null,en&&(this.actualDuration=Number.NaN,this.actualStartTime=Number.NaN,this.selfBaseDuration=Number.NaN,this.treeBaseDuration=Number.NaN,this.actualDuration=0,this.actualStartTime=-1,this.selfBaseDuration=0,this.treeBaseDuration=0),Hr&&(this._debugID=di++,this._debugIsCurrentlyTiming=!1),this._debugSource=null,this._debugOwner=null,this._debugNeedsRemount=!1,this._debugHookTypes=null,!rr&&typeof Object.preventExtensions=="function"&&Object.preventExtensions(this)}var Zi=function(f,d,E,C){return new zl(f,d,E,C)};function a0(f){var d=f.prototype;return!!(d&&d.isReactComponent)}function ao(f){return typeof f=="function"&&!a0(f)&&f.defaultProps===void 0}function Ms(f){if(typeof f=="function")return a0(f)?O:N;if(f!=null){var d=f.$$typeof;if(d===Mn)return ue;if(d===Gt)return me}return T}function C0(f,d,E){var C=f.alternate;C===null?(C=Zi(f.tag,d,f.key,f.mode),C.elementType=f.elementType,C.type=f.type,C.stateNode=f.stateNode,C._debugID=f._debugID,C._debugSource=f._debugSource,C._debugOwner=f._debugOwner,C._debugHookTypes=f._debugHookTypes,C.alternate=f,f.alternate=C):(C.pendingProps=d,C.effectTag=xi,C.nextEffect=null,C.firstEffect=null,C.lastEffect=null,en&&(C.actualDuration=0,C.actualStartTime=-1)),C.childExpirationTime=f.childExpirationTime,C.expirationTime=f.expirationTime,C.child=f.child,C.memoizedProps=f.memoizedProps,C.memoizedState=f.memoizedState,C.updateQueue=f.updateQueue;var A=f.dependencies;switch(C.dependencies=A===null?null:{expirationTime:A.expirationTime,firstContext:A.firstContext,responders:A.responders},C.sibling=f.sibling,C.index=f.index,C.ref=f.ref,en&&(C.selfBaseDuration=f.selfBaseDuration,C.treeBaseDuration=f.treeBaseDuration),C._debugNeedsRemount=f._debugNeedsRemount,C.tag){case T:case N:case re:C.type=ro(f.type);break;case O:C.type=zo(f.type);break;case ue:C.type=wf(f.type);break;default:break}return C}function kv(f,d){f.effectTag&=mi,f.nextEffect=null,f.firstEffect=null,f.lastEffect=null;var E=f.alternate;if(E===null)f.childExpirationTime=at,f.expirationTime=d,f.child=null,f.memoizedProps=null,f.memoizedState=null,f.updateQueue=null,f.dependencies=null,en&&(f.selfBaseDuration=0,f.treeBaseDuration=0);else{f.childExpirationTime=E.childExpirationTime,f.expirationTime=E.expirationTime,f.child=E.child,f.memoizedProps=E.memoizedProps,f.memoizedState=E.memoizedState,f.updateQueue=E.updateQueue;var C=E.dependencies;f.dependencies=C===null?null:{expirationTime:C.expirationTime,firstContext:C.firstContext,responders:C.responders},en&&(f.selfBaseDuration=E.selfBaseDuration,f.treeBaseDuration=E.treeBaseDuration)}return f}function Z4(f){var d;return f===Mo?d=ri|Y|mr:f===Uo?d=Y|mr:d=Ar,en&&St&&(d|=ii),Zi(B,null,null,d)}function yy(f,d,E,C,A,j){var V,te=T,se=f;if(typeof f=="function")a0(f)?(te=O,se=zo(se)):se=ro(se);else if(typeof f=="string")te=q;else{e:switch(f){case le:return rf(E.children,A,j,d);case an:te=pe,A|=ri|Y|mr;break;case qe:te=pe,A|=mr;break;case dt:return eE(E,A,j,d);case lr:return tE(E,A,j,d);case ln:return nE(E,A,j,d);default:{if(typeof f=="object"&&f!==null)switch(f.$$typeof){case Rt:te=ve;break e;case nn:te=ge;break e;case Mn:te=ue,se=wf(se);break e;case Gt:te=me;break e;case Er:te=we,se=null;break e;case w:if(Vt)return n_(f,E,A,j,d);break;case Xn:if(Au)return $4(f,E,A,j,d)}var Ue="";{(f===void 0||typeof f=="object"&&f!==null&&Object.keys(f).length===0)&&(Ue+=" You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.");var Qe=C?Wt(C.type):null;Qe&&(Ue+=` - -Check the render method of \``+Qe+"`.")}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+(f==null?f:typeof f)+"."+Ue)}}}return V=Zi(te,E,d,A),V.elementType=f,V.type=se,V.expirationTime=j,V}function gy(f,d,E){var C=null;C=f._owner;var A=f.type,j=f.key,V=f.props,te=yy(A,j,V,C,d,E);return te._debugSource=f._source,te._debugOwner=f._owner,te}function rf(f,d,E,C){var A=Zi(m,f,C,d);return A.expirationTime=E,A}function n_(f,d,E,C,A){var j=Zi(pt,d,A,E);return j.elementType=f,j.type=f,j.expirationTime=C,j}function $4(f,d,E,C,A){var j=Zi(Xe,d,A,E);return j.type=f,j.elementType=f,j.expirationTime=C,j}function eE(f,d,E,C){(typeof f.id!="string"||typeof f.onRender!="function")&&He(!1,'Profiler must specify an "id" string and "onRender" function as props');var A=Zi(_e,f,C,d|ii);return A.elementType=dt,A.type=dt,A.expirationTime=E,A}function tE(f,d,E,C){var A=Zi(ce,f,C,d);return A.type=lr,A.elementType=lr,A.expirationTime=E,A}function nE(f,d,E,C){var A=Zi(ct,f,C,d);return A.type=ln,A.elementType=ln,A.expirationTime=E,A}function _y(f,d,E){var C=Zi(ne,f,null,d);return C.expirationTime=E,C}function rE(){var f=Zi(q,null,null,Ar);return f.elementType="DELETED",f.type="DELETED",f}function iE(f){var d=Zi(je,null,null,Ar);return d.stateNode=f,d}function Ey(f,d,E){var C=f.children!==null?f.children:[],A=Zi(H,C,f.key,d);return A.expirationTime=E,A.stateNode={containerInfo:f.containerInfo,pendingChildren:null,implementation:f.implementation},A}function r_(f,d){return f===null&&(f=Zi(T,null,null,Ar)),f.tag=d.tag,f.key=d.key,f.elementType=d.elementType,f.type=d.type,f.stateNode=d.stateNode,f.return=d.return,f.child=d.child,f.sibling=d.sibling,f.index=d.index,f.ref=d.ref,f.pendingProps=d.pendingProps,f.memoizedProps=d.memoizedProps,f.updateQueue=d.updateQueue,f.memoizedState=d.memoizedState,f.dependencies=d.dependencies,f.mode=d.mode,f.effectTag=d.effectTag,f.nextEffect=d.nextEffect,f.firstEffect=d.firstEffect,f.lastEffect=d.lastEffect,f.expirationTime=d.expirationTime,f.childExpirationTime=d.childExpirationTime,f.alternate=d.alternate,en&&(f.actualDuration=d.actualDuration,f.actualStartTime=d.actualStartTime,f.selfBaseDuration=d.selfBaseDuration,f.treeBaseDuration=d.treeBaseDuration),f._debugID=d._debugID,f._debugSource=d._debugSource,f._debugOwner=d._debugOwner,f._debugIsCurrentlyTiming=d._debugIsCurrentlyTiming,f._debugNeedsRemount=d._debugNeedsRemount,f._debugHookTypes=d._debugHookTypes,f}function uE(f,d,E){this.tag=d,this.current=null,this.containerInfo=f,this.pendingChildren=null,this.pingCache=null,this.finishedExpirationTime=at,this.finishedWork=null,this.timeoutHandle=nl,this.context=null,this.pendingContext=null,this.hydrate=E,this.callbackNode=null,this.callbackPriority=Do,this.firstPendingTime=at,this.firstSuspendedTime=at,this.lastSuspendedTime=at,this.nextKnownPendingLevel=at,this.lastPingedTime=at,this.lastExpiredTime=at,bn&&(this.interactionThreadID=M.unstable_getThreadID(),this.memoizedInteractions=new Set,this.pendingInteractionMap=new Map),Yi&&(this.hydrationCallbacks=null)}function oE(f,d,E,C){var A=new uE(f,d,E);Yi&&(A.hydrationCallbacks=C);var j=Z4(d);return A.current=j,j.stateNode=A,A}function i_(f,d){var E=f.firstSuspendedTime,C=f.lastSuspendedTime;return E!==at&&E>=d&&C<=d}function Vf(f,d){var E=f.firstSuspendedTime,C=f.lastSuspendedTime;Ed||E===at)&&(f.lastSuspendedTime=d),d<=f.lastPingedTime&&(f.lastPingedTime=at),d<=f.lastExpiredTime&&(f.lastExpiredTime=at)}function u_(f,d){var E=f.firstPendingTime;d>E&&(f.firstPendingTime=d);var C=f.firstSuspendedTime;C!==at&&(d>=C?f.firstSuspendedTime=f.lastSuspendedTime=f.nextKnownPendingLevel=at:d>=f.lastSuspendedTime&&(f.lastSuspendedTime=d+1),d>f.nextKnownPendingLevel&&(f.nextKnownPendingLevel=d))}function lE(f,d,E){f.firstPendingTime=E,d<=f.lastSuspendedTime?f.firstSuspendedTime=f.lastSuspendedTime=f.nextKnownPendingLevel=at:d<=f.firstSuspendedTime&&(f.firstSuspendedTime=d-1),d<=f.lastPingedTime&&(f.lastPingedTime=at),d<=f.lastExpiredTime&&(f.lastExpiredTime=at)}function Vp(f,d){var E=f.lastExpiredTime;(E===at||E>d)&&(f.lastExpiredTime=d)}var sE={debugTool:null},Lv=sE,Dy,wy;Dy=!1,wy={};function aE(f){if(!f)return Rn;var d=kt(f),E=xl(d);if(d.tag===O){var C=d.type;if(Xi(C))return Oo(d,C,E)}return E}function Sy(f){var d=kt(f);if(d===void 0)throw typeof f.render=="function"?Error("Unable to find node on an unmounted component."):Error("Argument appears to not be a ReactComponent. Keys: "+Object.keys(f));var E=bo(d);return E===null?null:E.stateNode}function fE(f,d){{var E=kt(f);if(E===void 0)throw typeof f.render=="function"?Error("Unable to find node on an unmounted component."):Error("Argument appears to not be a ReactComponent. Keys: "+Object.keys(f));var C=bo(E);if(C===null)return null;if(C.mode&mr){var A=Wt(E.type)||"Component";wy[A]||(wy[A]=!0,E.mode&mr?He(!1,"%s is deprecated in StrictMode. %s was passed an instance of %s which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://fb.me/react-strict-mode-find-node%s",d,d,A,Cr(C)):He(!1,"%s is deprecated in StrictMode. %s was passed an instance of %s which renders StrictMode children. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://fb.me/react-strict-mode-find-node%s",d,d,A,Cr(C)))}return C.stateNode}return Sy(f)}function cE(f,d,E,C){return oE(f,d,E,C)}function o_(f,d,E,C){var A=d.current,j=jl();typeof jest!="undefined"&&(vy(A),qp(A));var V=_0(),te=zf(j,A,V);Lv.debugTool&&(A.alternate===null?Lv.debugTool.onMountContainer(d):f===null?Lv.debugTool.onUnmountContainer(d):Lv.debugTool.onUpdateContainer(d));var se=aE(E);d.context===null?d.context=se:d.pendingContext=se,Lr==="render"&&An!==null&&!Dy&&(Dy=!0,He(!1,`Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate. - -Check the render method of %s.`,Wt(An.type)||"Unknown"));var Ue=Cu(te,V);return Ue.payload={element:f},C=C===void 0?null:C,C!==null&&(typeof C!="function"&&He(!1,"render(...): Expected the last optional `callback` argument to be a function. Instead received: %s.",C),Ue.callback=C),Ga(A,Ue),yl(A,te),te}function dE(f){var d=f.current;if(!d.child)return null;switch(d.child.tag){case q:return N0(d.child.stateNode);default:return d.child.stateNode}}function pE(f){switch(f.tag){case B:var d=f.stateNode;d.hydrate&&Gm(d,d.firstPendingTime);break;case ce:Op(function(){return yl(f,Un)});var E=ja(jl());Nv(f,E);break}}function l_(f,d){var E=f.memoizedState;E!==null&&E.dehydrated!==null&&E.retryTime=d.length)return C;var A=d[E],j=Array.isArray(f)?f.slice():a({},f);return j[A]=xy(f[A],d,E+1,C),j},p_=function(f,d,E){return xy(f,d,0,E)};a_=function(f,d,E,C){for(var A=f.memoizedState;A!==null&&d>0;)A=A.next,d--;if(A!==null){var j=p_(A.memoizedState,E,C);A.memoizedState=j,A.baseState=j,f.memoizedProps=a({},f.memoizedProps),yl(f,Un)}},f_=function(f,d,E){f.pendingProps=p_(f.memoizedProps,d,E),f.alternate&&(f.alternate.pendingProps=f.pendingProps),yl(f,Un)},c_=function(f){yl(f,Un)},d_=function(f){Cy=f}}function yE(f){var d=f.findFiberByHostInstance,E=nt.ReactCurrentDispatcher;return At(a({},f,{overrideHookState:a_,overrideProps:f_,setSuspenseHandler:d_,scheduleUpdate:c_,currentDispatcherRef:E,findHostInstanceByFiber:function(C){var A=bo(C);return A===null?null:A.stateNode},findFiberByHostInstance:function(C){return d?d(C):null},findHostInstancesForRefresh:od,scheduleRefresh:Ol,scheduleRoot:Cs,setRefreshHandler:Wa,getCurrentFiber:function(){return An}}))}var h_=Object.freeze({createContainer:cE,updateContainer:o_,batchedEventUpdates:Qm,batchedUpdates:Xm,unbatchedUpdates:Jm,deferredUpdates:Ym,syncUpdates:pv,discreteUpdates:hv,flushDiscreteUpdates:dv,flushControlled:Zm,flushSync:Op,flushPassiveEffects:nf,IsThisRendererActing:Wf,getPublicRootInstance:dE,attemptSynchronousHydration:pE,attemptUserBlockingHydration:hE,attemptContinuousHydration:Ty,attemptHydrationAtCurrentPriority:vE,findHostInstance:Sy,findHostInstanceWithWarning:fE,findHostInstanceWithNoPortals:mE,shouldSuspend:s_,injectIntoDevTools:yE}),gE=h_.default||h_;Qy.exports=gE;var _E=Qy.exports;return Qy.exports=i,_E})});var vT=Ke((HW,ID)=>{"use strict";process.env.NODE_ENV==="production"?ID.exports=fT():ID.exports=hT()});var yT=Ke((qW,mT)=>{"use strict";var zI={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};mT.exports=zI});var DT=Ke((WW,gT)=>{"use strict";var HI=Object.assign||function(i){for(var o=1;o"}}]),i}(),_T=function(){J_(i,null,[{key:"fromJS",value:function(a){var c=a.width,_=a.height;return new i(c,_)}}]);function i(o,a){BD(this,i),this.width=o,this.height=a}return J_(i,[{key:"fromJS",value:function(a){a(this.width,this.height)}},{key:"toString",value:function(){return""}}]),i}(),ET=function(){function i(o,a){BD(this,i),this.unit=o,this.value=a}return J_(i,[{key:"fromJS",value:function(a){a(this.unit,this.value)}},{key:"toString",value:function(){switch(this.unit){case nc.UNIT_POINT:return String(this.value);case nc.UNIT_PERCENT:return this.value+"%";case nc.UNIT_AUTO:return"auto";default:return this.value+"?"}}},{key:"valueOf",value:function(){return this.value}}]),i}();gT.exports=function(i,o){function a(M,N,O){var T=M[N];M[N]=function(){for(var B=arguments.length,H=Array(B),q=0;q1?H-1:0),ne=1;ne1&&arguments[1]!==void 0?arguments[1]:NaN,O=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,T=arguments.length>3&&arguments[3]!==void 0?arguments[3]:nc.DIRECTION_LTR;return M.call(this,N,O,T)}),HI({Config:o.Config,Node:o.Node,Layout:i("Layout",qI),Size:i("Size",_T),Value:i("Value",ET),getInstanceCount:function(){return o.getInstanceCount.apply(o,arguments)}},nc)}});var wT=Ke((exports,module)=>{(function(i,o){typeof define=="function"&&define.amd?define([],function(){return o}):typeof module=="object"&&module.exports?module.exports=o:(i.nbind=i.nbind||{}).init=o})(exports,function(Module,cb){typeof Module=="function"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(i,o){return function(){i&&i.apply(this,arguments);try{Module.ccall("nbind_init")}catch(a){o(a);return}o(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module!="undefined"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT==="WEB")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT==="WORKER")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT==="NODE")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT==="SHELL")ENVIRONMENT_IS_SHELL=!0;else throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ENVIRONMENT_IS_WEB=typeof window=="object",ENVIRONMENT_IS_WORKER=typeof importScripts=="function",ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof require=="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(o,a){nodeFS||(nodeFS={}("")),nodePath||(nodePath={}("")),o=nodePath.normalize(o);var c=nodeFS.readFileSync(o);return a?c:c.toString()},Module.readBinary=function(o){var a=Module.read(o,!0);return a.buffer||(a=new Uint8Array(a)),assert(a.buffer),a},Module.load=function(o){globalEval(read(o))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\/g,"/"):Module.thisProgram="unknown-program"),Module.arguments=process.argv.slice(2),typeof module!="undefined"&&(module.exports=Module),Module.inspect=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr!="undefined"&&(Module.printErr=printErr),typeof read!="undefined"?Module.read=read:Module.read=function(){throw"no read() available"},Module.readBinary=function(o){if(typeof readbuffer=="function")return new Uint8Array(readbuffer(o));var a=read(o,"binary");return assert(typeof a=="object"),a},typeof scriptArgs!="undefined"?Module.arguments=scriptArgs:typeof arguments!="undefined"&&(Module.arguments=arguments),typeof quit=="function"&&(Module.quit=function(i,o){quit(i)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(o){var a=new XMLHttpRequest;return a.open("GET",o,!1),a.send(null),a.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(o){var a=new XMLHttpRequest;return a.open("GET",o,!1),a.responseType="arraybuffer",a.send(null),new Uint8Array(a.response)}),Module.readAsync=function(o,a,c){var _=new XMLHttpRequest;_.open("GET",o,!0),_.responseType="arraybuffer",_.onload=function(){_.status==200||_.status==0&&_.response?a(_.response):c()},_.onerror=c,_.send(null)},typeof arguments!="undefined"&&(Module.arguments=arguments),typeof console!="undefined")Module.print||(Module.print=function(o){console.log(o)}),Module.printErr||(Module.printErr=function(o){console.warn(o)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump!="undefined"?function(i){dump(i)}:function(i){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle=="undefined"&&(Module.setWindowTitle=function(i){document.title=i})}else throw"Unknown runtime environment. Where are we?";function globalEval(i){eval.call(null,i)}!Module.load&&Module.read&&(Module.load=function(o){globalEval(Module.read(o))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram="./this.program"),Module.quit||(Module.quit=function(i,o){throw o}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(i){return tempRet0=i,i},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(i){STACKTOP=i},getNativeTypeSize:function(i){switch(i){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(i[i.length-1]==="*")return Runtime.QUANTUM_SIZE;if(i[0]==="i"){var o=parseInt(i.substr(1));return assert(o%8==0),o/8}else return 0}}},getNativeFieldSize:function(i){return Math.max(Runtime.getNativeTypeSize(i),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(i,o){return o==="double"||o==="i64"?i&7&&(assert((i&7)==4),i+=4):assert((i&3)==0),i},getAlignSize:function(i,o,a){return!a&&(i=="i64"||i=="double")?8:i?Math.min(o||(i?Runtime.getNativeFieldSize(i):0),Runtime.QUANTUM_SIZE):Math.min(o,8)},dynCall:function(i,o,a){return a&&a.length?Module["dynCall_"+i].apply(null,[o].concat(a)):Module["dynCall_"+i].call(null,o)},functionPointers:[],addFunction:function(i){for(var o=0;o>2],a=(o+i+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=a,a>=TOTAL_MEMORY){var c=enlargeMemory();if(!c)return HEAP32[DYNAMICTOP_PTR>>2]=o,0}return o},alignMemory:function(i,o){var a=i=Math.ceil(i/(o||16))*(o||16);return a},makeBigInt:function(i,o,a){var c=a?+(i>>>0)+ +(o>>>0)*4294967296:+(i>>>0)+ +(o|0)*4294967296;return c},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(i,o){i||abort("Assertion failed: "+o)}function getCFunc(ident){var func=Module["_"+ident];if(!func)try{func=eval("_"+ident)}catch(i){}return assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(i){var o=Runtime.stackAlloc(i.length);return writeArrayToMemory(i,o),o},stringToC:function(i){var o=0;if(i!=null&&i!==0){var a=(i.length<<2)+1;o=Runtime.stackAlloc(a),stringToUTF8(i,o,a)}return o}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(o,a,c,_,t){var M=getCFunc(o),N=[],O=0;if(_)for(var T=0;T<_.length;T++){var B=toC[c[T]];B?(O===0&&(O=Runtime.stackSave()),N[T]=B(_[T])):N[T]=_[T]}var H=M.apply(null,N);if(a==="string"&&(H=Pointer_stringify(H)),O!==0){if(t&&t.async){EmterpreterAsync.asyncFinalizers.push(function(){Runtime.stackRestore(O)});return}Runtime.stackRestore(O)}return H};var sourceRegex=/^function\s*[a-zA-Z$_0-9]*\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(i){var o=i.toString().match(sourceRegex).slice(1);return{arguments:o[0],body:o[1],returnValue:o[2]}}var JSsource=null;function ensureJSsource(){if(!JSsource){JSsource={};for(var i in JSfuncs)JSfuncs.hasOwnProperty(i)&&(JSsource[i]=parseJSFunc(JSfuncs[i]))}}cwrap=function(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident),numericArgs=argTypes.every(function(i){return i==="number"}),numericRet=returnType!=="string";if(numericRet&&numericArgs)return cfunc;var argNames=argTypes.map(function(i,o){return"$"+o}),funcstr="(function("+argNames.join(",")+") {",nargs=argTypes.length;if(!numericArgs){ensureJSsource(),funcstr+="var stack = "+JSsource.stackSave.body+";";for(var i=0;i>0]=o;break;case"i8":HEAP8[i>>0]=o;break;case"i16":HEAP16[i>>1]=o;break;case"i32":HEAP32[i>>2]=o;break;case"i64":tempI64=[o>>>0,(tempDouble=o,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[i>>2]=tempI64[0],HEAP32[i+4>>2]=tempI64[1];break;case"float":HEAPF32[i>>2]=o;break;case"double":HEAPF64[i>>3]=o;break;default:abort("invalid type for setValue: "+a)}}Module.setValue=setValue;function getValue(i,o,a){switch(o=o||"i8",o.charAt(o.length-1)==="*"&&(o="i32"),o){case"i1":return HEAP8[i>>0];case"i8":return HEAP8[i>>0];case"i16":return HEAP16[i>>1];case"i32":return HEAP32[i>>2];case"i64":return HEAP32[i>>2];case"float":return HEAPF32[i>>2];case"double":return HEAPF64[i>>3];default:abort("invalid type for setValue: "+o)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(i,o,a,c){var _,t;typeof i=="number"?(_=!0,t=i):(_=!1,t=i.length);var M=typeof o=="string"?o:null,N;if(a==ALLOC_NONE?N=c:N=[typeof _malloc=="function"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][a===void 0?ALLOC_STATIC:a](Math.max(t,M?1:o.length)),_){var c=N,O;for(assert((N&3)==0),O=N+(t&~3);c>2]=0;for(O=N+t;c>0]=0;return N}if(M==="i8")return i.subarray||i.slice?HEAPU8.set(i,N):HEAPU8.set(new Uint8Array(i),N),N;for(var T=0,B,H,q;T>0],a|=c,!(c==0&&!o||(_++,o&&_==o)););o||(o=_);var t="";if(a<128){for(var M=1024,N;o>0;)N=String.fromCharCode.apply(String,HEAPU8.subarray(i,i+Math.min(o,M))),t=t?t+N:N,i+=M,o-=M;return t}return Module.UTF8ToString(i)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(i){for(var o="";;){var a=HEAP8[i++>>0];if(!a)return o;o+=String.fromCharCode(a)}}Module.AsciiToString=AsciiToString;function stringToAscii(i,o){return writeAsciiToMemory(i,o,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):void 0;function UTF8ArrayToString(i,o){for(var a=o;i[a];)++a;if(a-o>16&&i.subarray&&UTF8Decoder)return UTF8Decoder.decode(i.subarray(o,a));for(var c,_,t,M,N,O,T="";;){if(c=i[o++],!c)return T;if(!(c&128)){T+=String.fromCharCode(c);continue}if(_=i[o++]&63,(c&224)==192){T+=String.fromCharCode((c&31)<<6|_);continue}if(t=i[o++]&63,(c&240)==224?c=(c&15)<<12|_<<6|t:(M=i[o++]&63,(c&248)==240?c=(c&7)<<18|_<<12|t<<6|M:(N=i[o++]&63,(c&252)==248?c=(c&3)<<24|_<<18|t<<12|M<<6|N:(O=i[o++]&63,c=(c&1)<<30|_<<24|t<<18|M<<12|N<<6|O))),c<65536)T+=String.fromCharCode(c);else{var B=c-65536;T+=String.fromCharCode(55296|B>>10,56320|B&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(i){return UTF8ArrayToString(HEAPU8,i)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(i,o,a,c){if(!(c>0))return 0;for(var _=a,t=a+c-1,M=0;M=55296&&N<=57343&&(N=65536+((N&1023)<<10)|i.charCodeAt(++M)&1023),N<=127){if(a>=t)break;o[a++]=N}else if(N<=2047){if(a+1>=t)break;o[a++]=192|N>>6,o[a++]=128|N&63}else if(N<=65535){if(a+2>=t)break;o[a++]=224|N>>12,o[a++]=128|N>>6&63,o[a++]=128|N&63}else if(N<=2097151){if(a+3>=t)break;o[a++]=240|N>>18,o[a++]=128|N>>12&63,o[a++]=128|N>>6&63,o[a++]=128|N&63}else if(N<=67108863){if(a+4>=t)break;o[a++]=248|N>>24,o[a++]=128|N>>18&63,o[a++]=128|N>>12&63,o[a++]=128|N>>6&63,o[a++]=128|N&63}else{if(a+5>=t)break;o[a++]=252|N>>30,o[a++]=128|N>>24&63,o[a++]=128|N>>18&63,o[a++]=128|N>>12&63,o[a++]=128|N>>6&63,o[a++]=128|N&63}}return o[a]=0,a-_}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(i,o,a){return stringToUTF8Array(i,HEAPU8,o,a)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(i){for(var o=0,a=0;a=55296&&c<=57343&&(c=65536+((c&1023)<<10)|i.charCodeAt(++a)&1023),c<=127?++o:c<=2047?o+=2:c<=65535?o+=3:c<=2097151?o+=4:c<=67108863?o+=5:o+=6}return o}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):void 0;function demangle(i){var o=Module.___cxa_demangle||Module.__cxa_demangle;if(o){try{var a=i.substr(1),c=lengthBytesUTF8(a)+1,_=_malloc(c);stringToUTF8(a,_,c);var t=_malloc(4),M=o(_,0,0,t);if(getValue(t,"i32")===0&&M)return Pointer_stringify(M)}catch(N){}finally{_&&_free(_),t&&_free(t),M&&_free(M)}return i}return Runtime.warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),i}function demangleAll(i){var o=/__Z[\w\d_]+/g;return i.replace(o,function(a){var c=demangle(a);return a===c?a:a+" ["+c+"]"})}function jsStackTrace(){var i=new Error;if(!i.stack){try{throw new Error(0)}catch(o){i=o}if(!i.stack)return"(no stack trace available)"}return i.stack.toString()}function stackTrace(){var i=jsStackTrace();return Module.extraStackTrace&&(i+=` -`+Module.extraStackTrace()),demangleAll(i)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY0;){var o=i.shift();if(typeof o=="function"){o();continue}var a=o.func;typeof a=="number"?o.arg===void 0?Module.dynCall_v(a):Module.dynCall_vi(a,o.arg):a(o.arg===void 0?null:o.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun=="function"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun=="function"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(i){__ATPRERUN__.unshift(i)}Module.addOnPreRun=addOnPreRun;function addOnInit(i){__ATINIT__.unshift(i)}Module.addOnInit=addOnInit;function addOnPreMain(i){__ATMAIN__.unshift(i)}Module.addOnPreMain=addOnPreMain;function addOnExit(i){__ATEXIT__.unshift(i)}Module.addOnExit=addOnExit;function addOnPostRun(i){__ATPOSTRUN__.unshift(i)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(i,o,a){var c=a>0?a:lengthBytesUTF8(i)+1,_=new Array(c),t=stringToUTF8Array(i,_,0,_.length);return o&&(_.length=t),_}Module.intArrayFromString=intArrayFromString;function intArrayToString(i){for(var o=[],a=0;a255&&(c&=255),o.push(String.fromCharCode(c))}return o.join("")}Module.intArrayToString=intArrayToString;function writeStringToMemory(i,o,a){Runtime.warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var c,_;a&&(_=o+lengthBytesUTF8(i),c=HEAP8[_]),stringToUTF8(i,o,Infinity),a&&(HEAP8[_]=c)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(i,o){HEAP8.set(i,o)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(i,o,a){for(var c=0;c>0]=i.charCodeAt(c);a||(HEAP8[o>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function(o,a){var c=o>>>16,_=o&65535,t=a>>>16,M=a&65535;return _*M+(c*M+_*t<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(i){return froundBuffer[0]=i,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(i){i=i>>>0;for(var o=0;o<32;o++)if(i&1<<31-o)return o;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(i){return i<0?Math.ceil(i):Math.floor(i)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(i){return i}function addRunDependency(i){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(i){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var o=dependenciesFulfilled;dependenciesFulfilled=null,o()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(i,o,a,c,_,t,M,N){return _nbind.callbackSignatureList[i].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(i,o,a,c,_,t,M,N){return ASM_CONSTS[i](o,a,c,_,t,M,N)}function _emscripten_asm_const_iiiii(i,o,a,c,_){return ASM_CONSTS[i](o,a,c,_)}function _emscripten_asm_const_iiidddddd(i,o,a,c,_,t,M,N,O){return ASM_CONSTS[i](o,a,c,_,t,M,N,O)}function _emscripten_asm_const_iiididi(i,o,a,c,_,t,M){return ASM_CONSTS[i](o,a,c,_,t,M)}function _emscripten_asm_const_iiii(i,o,a,c){return ASM_CONSTS[i](o,a,c)}function _emscripten_asm_const_iiiid(i,o,a,c,_){return ASM_CONSTS[i](o,a,c,_)}function _emscripten_asm_const_iiiiii(i,o,a,c,_,t){return ASM_CONSTS[i](o,a,c,_,t)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(i,o){__ATEXIT__.unshift({func:i,arg:o})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr("missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj"),abort(-1)}function __decorate(i,o,a,c){var _=arguments.length,t=_<3?o:c===null?c=Object.getOwnPropertyDescriptor(o,a):c,M;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")t=Reflect.decorate(i,o,a,c);else for(var N=i.length-1;N>=0;N--)(M=i[N])&&(t=(_<3?M(t):_>3?M(o,a,t):M(o,a))||t);return _>3&&t&&Object.defineProperty(o,a,t),t}function _defineHidden(i){return function(o,a){Object.defineProperty(o,a,{configurable:!1,enumerable:!1,value:i,writable:!0})}}var _nbind={};function __nbind_free_external(i){_nbind.externalList[i].dereference(i)}function __nbind_reference_external(i){_nbind.externalList[i].reference()}function _llvm_stackrestore(i){var o=_llvm_stacksave,a=o.LLVM_SAVEDSTACKS[i];o.LLVM_SAVEDSTACKS.splice(i,1),Runtime.stackRestore(a)}function __nbind_register_pool(i,o,a,c){_nbind.Pool.pageSize=i,_nbind.Pool.usedPtr=o/4,_nbind.Pool.rootPtr=a,_nbind.Pool.pagePtr=c/4,HEAP32[o/4]=16909060,HEAP8[o]==1&&(_nbind.bigEndian=!0),HEAP32[o/4]=0,_nbind.makeTypeKindTbl=(t={},t[1024]=_nbind.PrimitiveType,t[64]=_nbind.Int64Type,t[2048]=_nbind.BindClass,t[3072]=_nbind.BindClassPtr,t[4096]=_nbind.SharedClassPtr,t[5120]=_nbind.ArrayType,t[6144]=_nbind.ArrayType,t[7168]=_nbind.CStringType,t[9216]=_nbind.CallbackType,t[10240]=_nbind.BindType,t),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,"cbFunction &":_nbind.CallbackType,"const cbFunction &":_nbind.CallbackType,"const std::string &":_nbind.StringType,"std::string":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var _=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:""});_.proto=Module,_nbind.BindClass.list.push(_);var t}function _emscripten_set_main_loop_timing(i,o){if(Browser.mainLoop.timingMode=i,Browser.mainLoop.timingValue=o,!Browser.mainLoop.func)return 1;if(i==0)Browser.mainLoop.scheduler=function(){var M=Math.max(0,Browser.mainLoop.tickStartTime+o-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,M)},Browser.mainLoop.method="timeout";else if(i==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method="rAF";else if(i==2){if(!window.setImmediate){let t=function(M){M.source===window&&M.data===c&&(M.stopPropagation(),a.shift()())};var _=t,a=[],c="setimmediate";window.addEventListener("message",t,!0),window.setImmediate=function(N){a.push(N),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(N),window.postMessage({target:c})):window.postMessage(c,"*")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method="immediate"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(i,o,a,c,_){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."),Browser.mainLoop.func=i,Browser.mainLoop.arg=c;var t;typeof c!="undefined"?t=function(){Module.dynCall_vi(i,c)}:t=function(){Module.dynCall_v(i)};var M=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var O=Date.now(),T=Browser.mainLoop.queue.shift();if(T.func(T.arg),Browser.mainLoop.remainingBlockers){var B=Browser.mainLoop.remainingBlockers,H=B%1==0?B-1:Math.floor(B);T.counted?Browser.mainLoop.remainingBlockers=H:(H=H+.5,Browser.mainLoop.remainingBlockers=(8*B+H)/9)}if(console.log('main loop blocker "'+T.name+'" took '+(Date.now()-O)+" ms"),Browser.mainLoop.updateStatus(),M1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method==="timeout"&&Module.ctx&&(Module.printErr("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!"),Browser.mainLoop.method=""),Browser.mainLoop.runIter(t),!(M0?_emscripten_set_main_loop_timing(0,1e3/o):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),a)throw"SimulateInfiniteLoop"}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var i=Browser.mainLoop.timingMode,o=Browser.mainLoop.timingValue,a=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(a,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(i,o),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var i=Module.statusMessage||"Please wait...",o=Browser.mainLoop.remainingBlockers,a=Browser.mainLoop.expectedBlockers;o?o=6;){var je=re>>we-6&63;we-=6,me+=_e[je]}return we==2?(me+=_e[(re&3)<<4],me+=ce+ce):we==4&&(me+=_e[(re&15)<<2],me+=ce),me}m.src="data:audio/x-"+M.substr(-3)+";base64,"+ve(t),B(m)},m.src=ne,Browser.safeSetTimeout(function(){B(m)},1e4)}else return H()},Module.preloadPlugins.push(o);function a(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var c=Module.canvas;c&&(c.requestPointerLock=c.requestPointerLock||c.mozRequestPointerLock||c.webkitRequestPointerLock||c.msRequestPointerLock||function(){},c.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},c.exitPointerLock=c.exitPointerLock.bind(document),document.addEventListener("pointerlockchange",a,!1),document.addEventListener("mozpointerlockchange",a,!1),document.addEventListener("webkitpointerlockchange",a,!1),document.addEventListener("mspointerlockchange",a,!1),Module.elementPointerLock&&c.addEventListener("click",function(_){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),_.preventDefault())},!1))},createContext:function(i,o,a,c){if(o&&Module.ctx&&i==Module.canvas)return Module.ctx;var _,t;if(o){var M={antialias:!1,alpha:!1};if(c)for(var N in c)M[N]=c[N];t=GL.createContext(i,M),t&&(_=GL.getContext(t).GLctx)}else _=i.getContext("2d");return _?(a&&(o||assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it"),Module.ctx=_,o&&GL.makeContextCurrent(t),Module.useWebGL=o,Browser.moduleContextCreatedCallbacks.forEach(function(O){O()}),Browser.init()),_):null},destroyContext:function(i,o,a){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(i,o,a){Browser.lockPointer=i,Browser.resizeCanvas=o,Browser.vrDevice=a,typeof Browser.lockPointer=="undefined"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas=="undefined"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice=="undefined"&&(Browser.vrDevice=null);var c=Module.canvas;function _(){Browser.isFullscreen=!1;var M=c.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===M?(c.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},c.exitFullscreen=c.exitFullscreen.bind(document),Browser.lockPointer&&c.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(M.parentNode.insertBefore(c,M),M.parentNode.removeChild(M),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(c)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener("fullscreenchange",_,!1),document.addEventListener("mozfullscreenchange",_,!1),document.addEventListener("webkitfullscreenchange",_,!1),document.addEventListener("MSFullscreenChange",_,!1));var t=document.createElement("div");c.parentNode.insertBefore(t,c),t.appendChild(c),t.requestFullscreen=t.requestFullscreen||t.mozRequestFullScreen||t.msRequestFullscreen||(t.webkitRequestFullscreen?function(){t.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(t.webkitRequestFullScreen?function(){t.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),a?t.requestFullscreen({vrDisplay:a}):t.requestFullscreen()},requestFullScreen:function(i,o,a){return Module.printErr("Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead."),Browser.requestFullScreen=function(c,_,t){return Browser.requestFullscreen(c,_,t)},Browser.requestFullscreen(i,o,a)},nextRAF:0,fakeRequestAnimationFrame:function(i){var o=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=o+1e3/60;else for(;o+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var a=Math.max(Browser.nextRAF-o,0);setTimeout(i,a)},requestAnimationFrame:function(o){typeof window=="undefined"?Browser.fakeRequestAnimationFrame(o):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(o))},safeCallback:function(i){return function(){if(!ABORT)return i.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var i=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],i.forEach(function(o){o()})}},safeRequestAnimationFrame:function(i){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?i():Browser.queuedAsyncCallbacks.push(i))})},safeSetTimeout:function(i,o){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?i():Browser.queuedAsyncCallbacks.push(i))},o)},safeSetInterval:function(i,o){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&i()},o)},getMimetype:function(i){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[i.substr(i.lastIndexOf(".")+1)]},getUserMedia:function(i){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(i)},getMovementX:function(i){return i.movementX||i.mozMovementX||i.webkitMovementX||0},getMovementY:function(i){return i.movementY||i.mozMovementY||i.webkitMovementY||0},getMouseWheelDelta:function(i){var o=0;switch(i.type){case"DOMMouseScroll":o=i.detail;break;case"mousewheel":o=i.wheelDelta;break;case"wheel":o=i.deltaY;break;default:throw"unrecognized mouse wheel event: "+i.type}return o},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(i){if(Browser.pointerLock)i.type!="mousemove"&&"mozMovementX"in i?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(i),Browser.mouseMovementY=Browser.getMovementY(i)),typeof SDL!="undefined"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var o=Module.canvas.getBoundingClientRect(),a=Module.canvas.width,c=Module.canvas.height,_=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset,t=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;if(i.type==="touchstart"||i.type==="touchend"||i.type==="touchmove"){var M=i.touch;if(M===void 0)return;var N=M.pageX-(_+o.left),O=M.pageY-(t+o.top);N=N*(a/o.width),O=O*(c/o.height);var T={x:N,y:O};if(i.type==="touchstart")Browser.lastTouches[M.identifier]=T,Browser.touches[M.identifier]=T;else if(i.type==="touchend"||i.type==="touchmove"){var B=Browser.touches[M.identifier];B||(B=T),Browser.lastTouches[M.identifier]=B,Browser.touches[M.identifier]=T}return}var H=i.pageX-(_+o.left),q=i.pageY-(t+o.top);H=H*(a/o.width),q=q*(c/o.height),Browser.mouseMovementX=H-Browser.mouseX,Browser.mouseMovementY=q-Browser.mouseY,Browser.mouseX=H,Browser.mouseY=q}},asyncLoad:function(i,o,a,c){var _=c?"":getUniqueRunDependency("al "+i);Module.readAsync(i,function(t){assert(t,'Loading data file "'+i+'" failed (no arrayBuffer).'),o(new Uint8Array(t)),_&&removeRunDependency(_)},function(t){if(a)a();else throw'Loading data file "'+i+'" failed.'}),_&&addRunDependency(_)},resizeListeners:[],updateResizeListeners:function(){var i=Module.canvas;Browser.resizeListeners.forEach(function(o){o(i.width,i.height)})},setCanvasSize:function(i,o,a){var c=Module.canvas;Browser.updateCanvasDimensions(c,i,o),a||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var i=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];i=i|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=i}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var i=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];i=i&~8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=i}Browser.updateResizeListeners()},updateCanvasDimensions:function(i,o,a){o&&a?(i.widthNative=o,i.heightNative=a):(o=i.widthNative,a=i.heightNative);var c=o,_=a;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(c/_>2];return o},getStr:function(){var i=Pointer_stringify(SYSCALLS.get());return i},get64:function(){var i=SYSCALLS.get(),o=SYSCALLS.get();return i>=0?assert(o===0):assert(o===-1),i},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(i,o){SYSCALLS.varargs=o;try{var a=SYSCALLS.getStreamFromFD();return FS.close(a),0}catch(c){return(typeof FS=="undefined"||!(c instanceof FS.ErrnoError))&&abort(c),-c.errno}}function ___syscall54(i,o){SYSCALLS.varargs=o;try{return 0}catch(a){return(typeof FS=="undefined"||!(a instanceof FS.ErrnoError))&&abort(a),-a.errno}}function _typeModule(i){var o=[[0,1,"X"],[1,1,"const X"],[128,1,"X *"],[256,1,"X &"],[384,1,"X &&"],[512,1,"std::shared_ptr"],[640,1,"std::unique_ptr"],[5120,1,"std::vector"],[6144,2,"std::array"],[9216,-1,"std::function"]];function a(O,T,B,H,q,ne){if(T==1){var m=H&896;(m==128||m==256||m==384)&&(O="X const")}var pe;return ne?pe=B.replace("X",O).replace("Y",q):pe=O.replace("X",B).replace("Y",q),pe.replace(/([*&]) (?=[*&])/g,"$1")}function c(O,T,B,H,q){throw new Error(O+" type "+B.replace("X",T+"?")+(H?" with flag "+H:"")+" in "+q)}function _(O,T,B,H,q,ne,m,pe){ne===void 0&&(ne="X"),pe===void 0&&(pe=1);var ge=B(O);if(ge)return ge;var ve=H(O),ue=ve.placeholderFlag,_e=o[ue];m&&_e&&(ne=a(m[2],m[0],ne,_e[0],"?",!0));var ce;ue==0&&(ce="Unbound"),ue>=10&&(ce="Corrupt"),pe>20&&(ce="Deeply nested"),ce&&c(ce,O,ne,ue,q||"?");var me=ve.paramList[0],re=_(me,T,B,H,q,ne,_e,pe+1),we,Ie={flags:_e[0],id:O,name:"",paramList:[re]},je=[],ct="?";switch(ve.placeholderFlag){case 1:we=re.spec;break;case 2:if((re.flags&15360)==1024&&re.spec.ptrSize==1){Ie.flags=7168;break}case 3:case 6:case 5:we=re.spec,(re.flags&15360)!=2048;break;case 8:ct=""+ve.paramList[1],Ie.paramList.push(ve.paramList[1]);break;case 9:for(var pt=0,Xe=ve.paramList[1];pt>2]=i),i}function _llvm_stacksave(){var i=_llvm_stacksave;return i.LLVM_SAVEDSTACKS||(i.LLVM_SAVEDSTACKS=[]),i.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),i.LLVM_SAVEDSTACKS.length-1}function ___syscall140(i,o){SYSCALLS.varargs=o;try{var a=SYSCALLS.getStreamFromFD(),c=SYSCALLS.get(),_=SYSCALLS.get(),t=SYSCALLS.get(),M=SYSCALLS.get(),N=_;return FS.llseek(a,N,M),HEAP32[t>>2]=a.position,a.getdents&&N===0&&M===0&&(a.getdents=null),0}catch(O){return(typeof FS=="undefined"||!(O instanceof FS.ErrnoError))&&abort(O),-O.errno}}function ___syscall146(i,o){SYSCALLS.varargs=o;try{var a=SYSCALLS.get(),c=SYSCALLS.get(),_=SYSCALLS.get(),t=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(B,H){var q=___syscall146.buffers[B];assert(q),H===0||H===10?((B===1?Module.print:Module.printErr)(UTF8ArrayToString(q,0)),q.length=0):q.push(H)});for(var M=0;M<_;M++){for(var N=HEAP32[c+M*8>>2],O=HEAP32[c+(M*8+4)>>2],T=0;Ti.pageSize/2||o>i.pageSize-a){var c=_nbind.typeNameTbl.NBind.proto;return c.lalloc(o)}else return HEAPU32[i.usedPtr]=a+o,i.rootPtr+a},i.lreset=function(o,a){var c=HEAPU32[i.pagePtr];if(c){var _=_nbind.typeNameTbl.NBind.proto;_.lreset(o,a)}else HEAPU32[i.usedPtr]=o},i}();_nbind.Pool=Pool;function constructType(i,o){var a=i==10240?_nbind.makeTypeNameTbl[o.name]||_nbind.BindType:_nbind.makeTypeKindTbl[i],c=new a(o);return typeIdTbl[o.id]=c,_nbind.typeNameTbl[o.name]=c,c}_nbind.constructType=constructType;function getType(i){return typeIdTbl[i]}_nbind.getType=getType;function queryType(i){var o=HEAPU8[i],a=_nbind.structureList[o][1];i/=4,a<0&&(++i,a=HEAPU32[i]+1);var c=Array.prototype.slice.call(HEAPU32.subarray(i+1,i+1+a));return o==9&&(c=[c[0],c.slice(1)]),{paramList:c,placeholderFlag:o}}_nbind.queryType=queryType;function getTypes(i,o){return i.map(function(a){return typeof a=="number"?_nbind.getComplexType(a,constructType,getType,queryType,o):_nbind.typeNameTbl[a]})}_nbind.getTypes=getTypes;function readTypeIdList(i,o){return Array.prototype.slice.call(HEAPU32,i/4,i/4+o)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(i){for(var o=i;HEAPU8[o++];);return String.fromCharCode.apply("",HEAPU8.subarray(i,o-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(i){var o={};if(i)for(;;){var a=HEAPU32[i/4];if(!a)break;o[readAsciiString(a)]=!0,i+=4}return o}_nbind.readPolicyList=readPolicyList;function getDynCall(i,o){var a={float32_t:"d",float64_t:"d",int64_t:"d",uint64_t:"d",void:"v"},c=i.map(function(t){return a[t.name]||"i"}).join(""),_=Module["dynCall_"+c];if(!_)throw new Error("dynCall_"+c+" not found for "+o+"("+i.map(function(t){return t.name}).join(", ")+")");return _}_nbind.getDynCall=getDynCall;function addMethod(i,o,a,c){var _=i[o];i.hasOwnProperty(o)&&_?((_.arity||_.arity===0)&&(_=_nbind.makeOverloader(_,_.arity),i[o]=_),_.addMethod(a,c)):(a.arity=c,i[o]=a)}_nbind.addMethod=addMethod;function throwError(i){throw new Error(i)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(i){__extends(o,i);function o(){var a=i!==null&&i.apply(this,arguments)||this;return a.heap=HEAPU32,a.ptrSize=4,a}return o.prototype.needsWireRead=function(a){return!!this.wireRead||!!this.makeWireRead},o.prototype.needsWireWrite=function(a){return!!this.wireWrite||!!this.makeWireWrite},o}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(i){__extends(o,i);function o(a){var c=i.call(this,a)||this,_=a.flags&32?{32:HEAPF32,64:HEAPF64}:a.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return c.heap=_[a.ptrSize*8],c.ptrSize=a.ptrSize,c}return o.prototype.needsWireWrite=function(a){return!!a&&!!a.Strict},o.prototype.makeWireWrite=function(a,c){return c&&c.Strict&&function(_){if(typeof _=="number")return _;throw new Error("Type mismatch")}},o}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(i,o){if(i==null){if(o&&o.Nullable)return 0;throw new Error("Type mismatch")}if(o&&o.Strict){if(typeof i!="string")throw new Error("Type mismatch")}else i=i.toString();var a=Module.lengthBytesUTF8(i)+1,c=_nbind.Pool.lalloc(a);return Module.stringToUTF8Array(i,HEAPU8,c,a),c}_nbind.pushCString=pushCString;function popCString(i){return i===0?null:Module.Pointer_stringify(i)}_nbind.popCString=popCString;var CStringType=function(i){__extends(o,i);function o(){var a=i!==null&&i.apply(this,arguments)||this;return a.wireRead=popCString,a.wireWrite=pushCString,a.readResources=[_nbind.resources.pool],a.writeResources=[_nbind.resources.pool],a}return o.prototype.makeWireWrite=function(a,c){return function(_){return pushCString(_,c)}},o}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(i){__extends(o,i);function o(){var a=i!==null&&i.apply(this,arguments)||this;return a.wireRead=function(c){return!!c},a}return o.prototype.needsWireWrite=function(a){return!!a&&!!a.Strict},o.prototype.makeWireRead=function(a){return"!!("+a+")"},o.prototype.makeWireWrite=function(a,c){return c&&c.Strict&&function(_){if(typeof _=="boolean")return _;throw new Error("Type mismatch")}||a},o}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function i(){}return i.prototype.persist=function(){this.__nbindState|=1},i}();_nbind.Wrapper=Wrapper;function makeBound(i,o){var a=function(c){__extends(_,c);function _(t,M,N,O){var T=c.call(this)||this;if(!(T instanceof _))return new(Function.prototype.bind.apply(_,Array.prototype.concat.apply([null],arguments)));var B=M,H=N,q=O;if(t!==_nbind.ptrMarker){var ne=T.__nbindConstructor.apply(T,arguments);B=4096|512,q=HEAPU32[ne/4],H=HEAPU32[ne/4+1]}var m={configurable:!0,enumerable:!1,value:null,writable:!1},pe={__nbindFlags:B,__nbindPtr:H};q&&(pe.__nbindShared=q,_nbind.mark(T));for(var ge=0,ve=Object.keys(pe);ge>=1;var a=_nbind.valueList[i];return _nbind.valueList[i]=firstFreeValue,firstFreeValue=i,a}else{if(o)return _nbind.popShared(i,o);throw new Error("Invalid value slot "+i)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(i){return typeof i=="number"?i:pushValue(i)*4096+valueBase}function pop64(i){return i=3?M=Buffer.from(t):M=new Buffer(t),M.copy(c)}else getBuffer(c).set(t)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var i=0,o=dirtyList;i>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(i,o,a,c,_,t){try{Module.dynCall_viiiii(i,o,a,c,_,t)}catch(M){if(typeof M!="number"&&M!=="longjmp")throw M;Module.setThrew(1,0)}}function invoke_vif(i,o,a){try{Module.dynCall_vif(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_vid(i,o,a){try{Module.dynCall_vid(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_fiff(i,o,a,c){try{return Module.dynCall_fiff(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_vi(i,o){try{Module.dynCall_vi(i,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_vii(i,o,a){try{Module.dynCall_vii(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_ii(i,o){try{return Module.dynCall_ii(i,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_viddi(i,o,a,c,_){try{Module.dynCall_viddi(i,o,a,c,_)}catch(t){if(typeof t!="number"&&t!=="longjmp")throw t;Module.setThrew(1,0)}}function invoke_vidd(i,o,a,c){try{Module.dynCall_vidd(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_iiii(i,o,a,c){try{return Module.dynCall_iiii(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_diii(i,o,a,c){try{return Module.dynCall_diii(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_di(i,o){try{return Module.dynCall_di(i,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_iid(i,o,a){try{return Module.dynCall_iid(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_iii(i,o,a){try{return Module.dynCall_iii(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_viiddi(i,o,a,c,_,t){try{Module.dynCall_viiddi(i,o,a,c,_,t)}catch(M){if(typeof M!="number"&&M!=="longjmp")throw M;Module.setThrew(1,0)}}function invoke_viiiiii(i,o,a,c,_,t,M){try{Module.dynCall_viiiiii(i,o,a,c,_,t,M)}catch(N){if(typeof N!="number"&&N!=="longjmp")throw N;Module.setThrew(1,0)}}function invoke_dii(i,o,a){try{return Module.dynCall_dii(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_i(i){try{return Module.dynCall_i(i)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_iiiiii(i,o,a,c,_,t){try{return Module.dynCall_iiiiii(i,o,a,c,_,t)}catch(M){if(typeof M!="number"&&M!=="longjmp")throw M;Module.setThrew(1,0)}}function invoke_viiid(i,o,a,c,_){try{Module.dynCall_viiid(i,o,a,c,_)}catch(t){if(typeof t!="number"&&t!=="longjmp")throw t;Module.setThrew(1,0)}}function invoke_viififi(i,o,a,c,_,t,M){try{Module.dynCall_viififi(i,o,a,c,_,t,M)}catch(N){if(typeof N!="number"&&N!=="longjmp")throw N;Module.setThrew(1,0)}}function invoke_viii(i,o,a,c){try{Module.dynCall_viii(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_v(i){try{Module.dynCall_v(i)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_viid(i,o,a,c){try{Module.dynCall_viid(i,o,a,c)}catch(_){if(typeof _!="number"&&_!=="longjmp")throw _;Module.setThrew(1,0)}}function invoke_idd(i,o,a){try{return Module.dynCall_idd(i,o,a)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_viiii(i,o,a,c,_){try{Module.dynCall_viiii(i,o,a,c,_)}catch(t){if(typeof t!="number"&&t!=="longjmp")throw t;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:Infinity},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(i,o,a){var c=new i.Int8Array(a),_=new i.Int16Array(a),t=new i.Int32Array(a),M=new i.Uint8Array(a),N=new i.Uint16Array(a),O=new i.Uint32Array(a),T=new i.Float32Array(a),B=new i.Float64Array(a),H=o.DYNAMICTOP_PTR|0,q=o.tempDoublePtr|0,ne=o.ABORT|0,m=o.STACKTOP|0,pe=o.STACK_MAX|0,ge=o.cttz_i8|0,ve=o.___dso_handle|0,ue=0,_e=0,ce=0,me=0,re=i.NaN,we=i.Infinity,Ie=0,je=0,ct=0,pt=0,Xe=0,tt=0,He=i.Math.floor,kt=i.Math.abs,zt=i.Math.sqrt,nt=i.Math.pow,X=i.Math.cos,fe=i.Math.sin,xe=i.Math.tan,le=i.Math.acos,qe=i.Math.asin,dt=i.Math.atan,Rt=i.Math.atan2,nn=i.Math.exp,an=i.Math.log,Mn=i.Math.ceil,lr=i.Math.imul,ln=i.Math.min,Gt=i.Math.max,Er=i.Math.clz32,w=i.Math.fround,jt=o.abort,Xn=o.assert,vr=o.enlargeMemory,jr=o.getTotalMemory,fr=o.abortOnCannotGrowMemory,zr=o.invoke_viiiii,Qt=o.invoke_vif,wu=o.invoke_vid,po=o.invoke_fiff,A0=o.invoke_vi,J0=o.invoke_vii,Ps=o.invoke_ii,Z0=o.invoke_viddi,$0=o.invoke_vidd,Wt=o.invoke_iiii,xi=o.invoke_diii,su=o.invoke_di,mi=o.invoke_iid,Dr=o.invoke_iii,el=o.invoke_viiddi,Ko=o.invoke_viiiiii,Uu=o.invoke_dii,Xo=o.invoke_i,Xr=o.invoke_iiiiii,O0=o.invoke_viiid,M0=o.invoke_viififi,Po=o.invoke_viii,au=o.invoke_v,ki=o.invoke_viid,Is=o.invoke_idd,Xl=o.invoke_viiii,Io=o._emscripten_asm_const_iiiii,ho=o._emscripten_asm_const_iiidddddd,Hr=o._emscripten_asm_const_iiiid,Ri=o.__nbind_reference_external,Qo=o._emscripten_asm_const_iiiiiiii,yi=o._removeAccessorPrefix,en=o._typeModule,bn=o.__nbind_register_pool,Ai=o.__decorate,gi=o._llvm_stackrestore,Vt=o.___cxa_atexit,Au=o.__extends,eu=o.__nbind_get_value_object,Jo=o.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,Yi=o._emscripten_set_main_loop_timing,Ql=o.__nbind_register_primitive,k0=o.__nbind_register_type,ai=o._emscripten_memcpy_big,f0=o.__nbind_register_function,Jl=o.___setErrNo,L0=o.__nbind_register_class,bs=o.__nbind_finish,$n=o._abort,tl=o._nbind_value,c0=o._llvm_stacksave,bo=o.___syscall54,Sl=o._defineHidden,N0=o._emscripten_set_main_loop,wt=o._emscripten_get_now,bt=o.__nbind_register_callback_signature,Hn=o._emscripten_asm_const_iiiiii,qr=o.__nbind_free_external,Ki=o._emscripten_asm_const_iiii,Qr=o._emscripten_asm_const_iiididi,Ou=o.___syscall6,vo=o._atexit,Li=o.___syscall140,mo=o.___syscall146,vs=w(0);let Tt=w(0);function d0(e){e=e|0;var n=0;return n=m,m=m+e|0,m=m+15&-16,n|0}function nl(){return m|0}function Zl(e){e=e|0,m=e}function ju(e,n){e=e|0,n=n|0,m=e,pe=n}function ms(e,n){e=e|0,n=n|0,ue||(ue=e,_e=n)}function Bo(e){e=e|0,tt=e}function Q(){return tt|0}function Se(){var e=0,n=0;gr(8104,8,400)|0,gr(8504,408,540)|0,e=9044,n=e+44|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));c[9088]=0,c[9089]=1,t[2273]=0,t[2274]=948,t[2275]=948,Vt(17,8104,ve|0)|0}function Ne(e){e=e|0,fc(e+948|0)}function Le(e){return e=w(e),((mr(e)|0)&2147483647)>>>0>2139095040|0}function ht(e,n,r){e=e|0,n=n|0,r=r|0;e:do if(t[e+(n<<3)+4>>2]|0)e=e+(n<<3)|0;else{if((n|2|0)==3?t[e+60>>2]|0:0){e=e+56|0;break}switch(n|0){case 0:case 2:case 4:case 5:{if(t[e+52>>2]|0){e=e+48|0;break e}break}default:}if(t[e+68>>2]|0){e=e+64|0;break}else{e=(n|1|0)==5?948:r;break}}while(0);return e|0}function Yn(e){e=e|0;var n=0;return n=T_(1e3)|0,Cn(e,(n|0)!=0,2456),t[2276]=(t[2276]|0)+1,gr(n|0,8104,1e3)|0,c[e+2>>0]|0&&(t[n+4>>2]=2,t[n+12>>2]=4),t[n+976>>2]=e,n|0}function Cn(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;l=m,m=m+16|0,u=l,n||(t[u>>2]=r,Cl(e,5,3197,u)),m=l}function cr(){return Yn(956)|0}function Si(e){e=e|0;var n=0;return n=pn(1e3)|0,Mu(n,e),Cn(t[e+976>>2]|0,1,2456),t[2276]=(t[2276]|0)+1,t[n+944>>2]=0,n|0}function Mu(e,n){e=e|0,n=n|0;var r=0;gr(e|0,n|0,948)|0,aa(e+948|0,n+948|0),r=e+960|0,e=n+960|0,n=r+40|0;do t[r>>2]=t[e>>2],r=r+4|0,e=e+4|0;while((r|0)<(n|0))}function zu(e){e=e|0;var n=0,r=0,u=0,l=0;if(n=e+944|0,r=t[n>>2]|0,r|0&&(Hu(r+948|0,e)|0,t[n>>2]=0),r=Su(e)|0,r|0){n=0;do t[(Ti(e,n)|0)+944>>2]=0,n=n+1|0;while((n|0)!=(r|0))}r=e+948|0,u=t[r>>2]|0,l=e+952|0,n=t[l>>2]|0,(n|0)!=(u|0)&&(t[l>>2]=n+(~((n+-4-u|0)>>>2)<<2)),F0(r),C_(e),t[2276]=(t[2276]|0)+-1}function Hu(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0;u=t[e>>2]|0,D=e+4|0,r=t[D>>2]|0,s=r;e:do if((u|0)==(r|0))l=u,h=4;else for(e=u;;){if((t[e>>2]|0)==(n|0)){l=e,h=4;break e}if(e=e+4|0,(e|0)==(r|0)){e=0;break}}while(0);return(h|0)==4&&((l|0)!=(r|0)?(u=l+4|0,e=s-u|0,n=e>>2,n&&(ky(l|0,u|0,e|0)|0,r=t[D>>2]|0),e=l+(n<<2)|0,(r|0)==(e|0)||(t[D>>2]=r+(~((r+-4-e|0)>>>2)<<2)),e=1):e=0),e|0}function Su(e){return e=e|0,(t[e+952>>2]|0)-(t[e+948>>2]|0)>>2|0}function Ti(e,n){e=e|0,n=n|0;var r=0;return r=t[e+948>>2]|0,(t[e+952>>2]|0)-r>>2>>>0>n>>>0?e=t[r+(n<<2)>>2]|0:e=0,e|0}function F0(e){e=e|0;var n=0,r=0,u=0,l=0;u=m,m=m+32|0,n=u,l=t[e>>2]|0,r=(t[e+4>>2]|0)-l|0,((t[e+8>>2]|0)-l|0)>>>0>r>>>0&&(l=r>>2,Y(n,l,l,e+8|0),ri(e,n),ii(n)),m=u}function ku(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0;L=Su(e)|0;do if(L|0){if((t[(Ti(e,0)|0)+944>>2]|0)==(e|0)){if(!(Hu(e+948|0,n)|0))break;gr(n+400|0,8504,540)|0,t[n+944>>2]=0,Qn(e);break}h=t[(t[e+976>>2]|0)+12>>2]|0,D=e+948|0,S=(h|0)==0,r=0,s=0;do u=t[(t[D>>2]|0)+(s<<2)>>2]|0,(u|0)==(n|0)?Qn(e):(l=Si(u)|0,t[(t[D>>2]|0)+(r<<2)>>2]=l,t[l+944>>2]=e,S||nD[h&15](u,l,e,r),r=r+1|0),s=s+1|0;while((s|0)!=(L|0));if(r>>>0>>0){S=e+948|0,D=e+952|0,h=r,r=t[D>>2]|0;do s=(t[S>>2]|0)+(h<<2)|0,u=s+4|0,l=r-u|0,n=l>>2,n&&(ky(s|0,u|0,l|0)|0,r=t[D>>2]|0),l=r,u=s+(n<<2)|0,(l|0)!=(u|0)&&(r=l+(~((l+-4-u|0)>>>2)<<2)|0,t[D>>2]=r),h=h+1|0;while((h|0)!=(L|0))}}while(0)}function p0(e){e=e|0;var n=0,r=0,u=0,l=0;qu(e,(Su(e)|0)==0,2491),qu(e,(t[e+944>>2]|0)==0,2545),n=e+948|0,r=t[n>>2]|0,u=e+952|0,l=t[u>>2]|0,(l|0)!=(r|0)&&(t[u>>2]=l+(~((l+-4-r|0)>>>2)<<2)),F0(n),n=e+976|0,r=t[n>>2]|0,gr(e|0,8104,1e3)|0,c[r+2>>0]|0&&(t[e+4>>2]=2,t[e+12>>2]=4),t[n>>2]=r}function qu(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;l=m,m=m+16|0,u=l,n||(t[u>>2]=r,pr(e,5,3197,u)),m=l}function Ia(){return t[2276]|0}function yo(){var e=0;return e=T_(20)|0,ua((e|0)!=0,2592),t[2277]=(t[2277]|0)+1,t[e>>2]=t[239],t[e+4>>2]=t[240],t[e+8>>2]=t[241],t[e+12>>2]=t[242],t[e+16>>2]=t[243],e|0}function ua(e,n){e=e|0,n=n|0;var r=0,u=0;u=m,m=m+16|0,r=u,e||(t[r>>2]=n,pr(0,5,3197,r)),m=u}function Zo(e){e=e|0,C_(e),t[2277]=(t[2277]|0)+-1}function oa(e,n){e=e|0,n=n|0;var r=0;n?(qu(e,(Su(e)|0)==0,2629),r=1):(r=0,n=0),t[e+964>>2]=n,t[e+988>>2]=r}function ba(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,s=u+8|0,l=u+4|0,h=u,t[l>>2]=n,qu(e,(t[n+944>>2]|0)==0,2709),qu(e,(t[e+964>>2]|0)==0,2763),ys(e),n=e+948|0,t[h>>2]=(t[n>>2]|0)+(r<<2),t[s>>2]=t[h>>2],To(n,s,l)|0,t[(t[l>>2]|0)+944>>2]=e,Qn(e),m=u}function ys(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0;if(r=Su(e)|0,r|0?(t[(Ti(e,0)|0)+944>>2]|0)!=(e|0):0){u=t[(t[e+976>>2]|0)+12>>2]|0,l=e+948|0,s=(u|0)==0,n=0;do h=t[(t[l>>2]|0)+(n<<2)>>2]|0,D=Si(h)|0,t[(t[l>>2]|0)+(n<<2)>>2]=D,t[D+944>>2]=e,s||nD[u&15](h,D,e,n),n=n+1|0;while((n|0)!=(r|0))}}function To(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0;Ze=m,m=m+64|0,I=Ze+52|0,D=Ze+48|0,K=Ze+28|0,Be=Ze+24|0,Te=Ze+20|0,ye=Ze,u=t[e>>2]|0,s=u,n=u+((t[n>>2]|0)-s>>2<<2)|0,u=e+4|0,l=t[u>>2]|0,h=e+8|0;do if(l>>>0<(t[h>>2]|0)>>>0){if((n|0)==(l|0)){t[n>>2]=t[r>>2],t[u>>2]=(t[u>>2]|0)+4;break}Vr(e,n,l,n+4|0),n>>>0<=r>>>0&&(r=(t[u>>2]|0)>>>0>r>>>0?r+4|0:r),t[n>>2]=t[r>>2]}else{u=(l-s>>2)+1|0,l=Ao(e)|0,l>>>0>>0&&hi(e),k=t[e>>2]|0,L=(t[h>>2]|0)-k|0,s=L>>1,Y(ye,L>>2>>>0>>1>>>0?s>>>0>>0?u:s:l,n-k>>2,e+8|0),k=ye+8|0,u=t[k>>2]|0,s=ye+12|0,L=t[s>>2]|0,h=L,S=u;do if((u|0)==(L|0)){if(L=ye+4|0,u=t[L>>2]|0,Ge=t[ye>>2]|0,l=Ge,u>>>0<=Ge>>>0){u=h-l>>1,u=(u|0)==0?1:u,Y(K,u,u>>>2,t[ye+16>>2]|0),t[Be>>2]=t[L>>2],t[Te>>2]=t[k>>2],t[D>>2]=t[Be>>2],t[I>>2]=t[Te>>2],Di(K,D,I),u=t[ye>>2]|0,t[ye>>2]=t[K>>2],t[K>>2]=u,u=K+4|0,Ge=t[L>>2]|0,t[L>>2]=t[u>>2],t[u>>2]=Ge,u=K+8|0,Ge=t[k>>2]|0,t[k>>2]=t[u>>2],t[u>>2]=Ge,u=K+12|0,Ge=t[s>>2]|0,t[s>>2]=t[u>>2],t[u>>2]=Ge,ii(K),u=t[k>>2]|0;break}s=u,h=((s-l>>2)+1|0)/-2|0,D=u+(h<<2)|0,l=S-s|0,s=l>>2,s&&(ky(D|0,u|0,l|0)|0,u=t[L>>2]|0),Ge=D+(s<<2)|0,t[k>>2]=Ge,t[L>>2]=u+(h<<2),u=Ge}while(0);t[u>>2]=t[r>>2],t[k>>2]=(t[k>>2]|0)+4,n=at(e,ye,n)|0,ii(ye)}while(0);return m=Ze,n|0}function Qn(e){e=e|0;var n=0;do{if(n=e+984|0,c[n>>0]|0)break;c[n>>0]=1,T[e+504>>2]=w(re),e=t[e+944>>2]|0}while((e|0)!=0)}function fc(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-4-u|0)>>>2)<<2)),_t(r))}function fi(e){return e=e|0,t[e+944>>2]|0}function $r(e){e=e|0,qu(e,(t[e+964>>2]|0)!=0,2832),Qn(e)}function $l(e){return e=e|0,(c[e+984>>0]|0)!=0|0}function la(e,n){e=e|0,n=n|0,LF(e,n,400)|0&&(gr(e|0,n|0,400)|0,Qn(e))}function hf(e){e=e|0;var n=Tt;return n=w(T[e+44>>2]),e=Le(n)|0,w(e?w(0):n)}function Bs(e){e=e|0;var n=Tt;return n=w(T[e+48>>2]),Le(n)|0&&(n=c[(t[e+976>>2]|0)+2>>0]|0?w(1):w(0)),w(n)}function Ba(e,n){e=e|0,n=n|0,t[e+980>>2]=n}function Us(e){return e=e|0,t[e+980>>2]|0}function go(e,n){e=e|0,n=n|0;var r=0;r=e+4|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function js(e){return e=e|0,t[e+4>>2]|0}function ji(e,n){e=e|0,n=n|0;var r=0;r=e+8|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function U(e){return e=e|0,t[e+8>>2]|0}function z(e,n){e=e|0,n=n|0;var r=0;r=e+12|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function G(e){return e=e|0,t[e+12>>2]|0}function $(e,n){e=e|0,n=n|0;var r=0;r=e+16|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function Ce(e){return e=e|0,t[e+16>>2]|0}function Ee(e,n){e=e|0,n=n|0;var r=0;r=e+20|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function Ae(e){return e=e|0,t[e+20>>2]|0}function Z(e,n){e=e|0,n=n|0;var r=0;r=e+24|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function ke(e){return e=e|0,t[e+24>>2]|0}function Je(e,n){e=e|0,n=n|0;var r=0;r=e+28|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function mt(e){return e=e|0,t[e+28>>2]|0}function oe(e,n){e=e|0,n=n|0;var r=0;r=e+32|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function We(e){return e=e|0,t[e+32>>2]|0}function it(e,n){e=e|0,n=n|0;var r=0;r=e+36|0,(t[r>>2]|0)!=(n|0)&&(t[r>>2]=n,Qn(e))}function Ct(e){return e=e|0,t[e+36>>2]|0}function Mt(e,n){e=e|0,n=w(n);var r=0;r=e+40|0,w(T[r>>2])!=n&&(T[r>>2]=n,Qn(e))}function It(e,n){e=e|0,n=w(n);var r=0;r=e+44|0,w(T[r>>2])!=n&&(T[r>>2]=n,Qn(e))}function sn(e,n){e=e|0,n=w(n);var r=0;r=e+48|0,w(T[r>>2])!=n&&(T[r>>2]=n,Qn(e))}function rn(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+52|0,l=e+56|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function Ft(e,n){e=e|0,n=w(n);var r=0,u=0;u=e+52|0,r=e+56|0,(w(T[u>>2])==n?(t[r>>2]|0)==2:0)||(T[u>>2]=n,u=Le(n)|0,t[r>>2]=u?3:2,Qn(e))}function Dn(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+52|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function dr(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=(s^1)&1,l=e+132+(n<<3)|0,n=e+132+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function er(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=s?0:2,l=e+132+(n<<3)|0,n=e+132+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function Cr(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=n+132+(r<<3)|0,n=t[u+4>>2]|0,r=e,t[r>>2]=t[u>>2],t[r+4>>2]=n}function An(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=(s^1)&1,l=e+60+(n<<3)|0,n=e+60+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function Lr(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=s?0:2,l=e+60+(n<<3)|0,n=e+60+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function _o(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=n+60+(r<<3)|0,n=t[u+4>>2]|0,r=e,t[r>>2]=t[u>>2],t[r+4>>2]=n}function Nr(e,n){e=e|0,n=n|0;var r=0;r=e+60+(n<<3)+4|0,(t[r>>2]|0)!=3&&(T[e+60+(n<<3)>>2]=w(re),t[r>>2]=3,Qn(e))}function ut(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=(s^1)&1,l=e+204+(n<<3)|0,n=e+204+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function Dt(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=s?0:2,l=e+204+(n<<3)|0,n=e+204+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function et(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=n+204+(r<<3)|0,n=t[u+4>>2]|0,r=e,t[r>>2]=t[u>>2],t[r+4>>2]=n}function Pt(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0,s=0;s=Le(r)|0,u=(s^1)&1,l=e+276+(n<<3)|0,n=e+276+(n<<3)+4|0,(s|w(T[l>>2])==r?(t[n>>2]|0)==(u|0):0)||(T[l>>2]=r,t[n>>2]=u,Qn(e))}function un(e,n){return e=e|0,n=n|0,w(T[e+276+(n<<3)>>2])}function fn(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+348|0,l=e+352|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function Jn(e,n){e=e|0,n=w(n);var r=0,u=0;u=e+348|0,r=e+352|0,(w(T[u>>2])==n?(t[r>>2]|0)==2:0)||(T[u>>2]=n,u=Le(n)|0,t[r>>2]=u?3:2,Qn(e))}function wr(e){e=e|0;var n=0;n=e+352|0,(t[n>>2]|0)!=3&&(T[e+348>>2]=w(re),t[n>>2]=3,Qn(e))}function fu(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+348|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function Lu(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+356|0,l=e+360|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function Co(e,n){e=e|0,n=w(n);var r=0,u=0;u=e+356|0,r=e+360|0,(w(T[u>>2])==n?(t[r>>2]|0)==2:0)||(T[u>>2]=n,u=Le(n)|0,t[r>>2]=u?3:2,Qn(e))}function $o(e){e=e|0;var n=0;n=e+360|0,(t[n>>2]|0)!=3&&(T[e+356>>2]=w(re),t[n>>2]=3,Qn(e))}function Nu(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+356|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function _i(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+364|0,l=e+368|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function P0(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=s?0:2,u=e+364|0,l=e+368|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function rl(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+364|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function vf(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+372|0,l=e+376|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function Tl(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=s?0:2,u=e+372|0,l=e+376|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function mf(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+372|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function I0(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+380|0,l=e+384|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function gs(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=s?0:2,u=e+380|0,l=e+384|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function zs(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+380|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function b0(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=(s^1)&1,u=e+388|0,l=e+392|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function B0(e,n){e=e|0,n=w(n);var r=0,u=0,l=0,s=0;s=Le(n)|0,r=s?0:2,u=e+388|0,l=e+392|0,(s|w(T[u>>2])==n?(t[l>>2]|0)==(r|0):0)||(T[u>>2]=n,t[l>>2]=r,Qn(e))}function _s(e,n){e=e|0,n=n|0;var r=0,u=0;u=n+388|0,r=t[u+4>>2]|0,n=e,t[n>>2]=t[u>>2],t[n+4>>2]=r}function Qu(e,n){e=e|0,n=w(n);var r=0;r=e+396|0,w(T[r>>2])!=n&&(T[r>>2]=n,Qn(e))}function Tu(e){return e=e|0,w(T[e+396>>2])}function Ei(e){return e=e|0,w(T[e+400>>2])}function xo(e){return e=e|0,w(T[e+404>>2])}function e0(e){return e=e|0,w(T[e+408>>2])}function U0(e){return e=e|0,w(T[e+412>>2])}function sa(e){return e=e|0,w(T[e+416>>2])}function es(e){return e=e|0,w(T[e+420>>2])}function tu(e,n){switch(e=e|0,n=n|0,qu(e,(n|0)<6,2918),n|0){case 0:{n=(t[e+496>>2]|0)==2?5:4;break}case 2:{n=(t[e+496>>2]|0)==2?4:5;break}default:}return w(T[e+424+(n<<2)>>2])}function ei(e,n){switch(e=e|0,n=n|0,qu(e,(n|0)<6,2918),n|0){case 0:{n=(t[e+496>>2]|0)==2?5:4;break}case 2:{n=(t[e+496>>2]|0)==2?4:5;break}default:}return w(T[e+448+(n<<2)>>2])}function h0(e,n){switch(e=e|0,n=n|0,qu(e,(n|0)<6,2918),n|0){case 0:{n=(t[e+496>>2]|0)==2?5:4;break}case 2:{n=(t[e+496>>2]|0)==2?4:5;break}default:}return w(T[e+472+(n<<2)>>2])}function Bi(e,n){e=e|0,n=n|0;var r=0,u=Tt;return r=t[e+4>>2]|0,(r|0)==(t[n+4>>2]|0)?r?(u=w(T[e>>2]),e=w(kt(w(u-w(T[n>>2]))))>2]=0,t[u+4>>2]=0,t[u+8>>2]=0,Jo(u|0,e|0,n|0,0),pr(e,3,(c[u+11>>0]|0)<0?t[u>>2]|0:u,r),tP(u),m=r}function t0(e,n,r,u){e=w(e),n=w(n),r=r|0,u=u|0;var l=Tt;e=w(e*n),l=w(QE(e,w(1)));do if(Ci(l,w(0))|0)e=w(e-l);else{if(e=w(e-l),Ci(l,w(1))|0){e=w(e+w(1));break}if(r){e=w(e+w(1));break}u||(l>w(.5)?l=w(1):(u=Ci(l,w(.5))|0,l=w(u?1:0)),e=w(e+l))}while(0);return w(e/n)}function n0(e,n,r,u,l,s,h,D,S,L,k,I,K){e=e|0,n=w(n),r=r|0,u=w(u),l=l|0,s=w(s),h=h|0,D=w(D),S=w(S),L=w(L),k=w(k),I=w(I),K=K|0;var Be=0,Te=Tt,ye=Tt,Ze=Tt,Ge=Tt,ft=Tt,Me=Tt;return S>2]),Te!=w(0)):0)?(Ze=w(t0(n,Te,0,0)),Ge=w(t0(u,Te,0,0)),ye=w(t0(s,Te,0,0)),Te=w(t0(D,Te,0,0))):(ye=s,Ze=n,Te=D,Ge=u),(l|0)==(e|0)?Be=Ci(ye,Ze)|0:Be=0,(h|0)==(r|0)?K=Ci(Te,Ge)|0:K=0,((Be?0:(ft=w(n-k),!(Re(e,ft,S)|0)))?!(rt(e,ft,l,S)|0):0)?Be=Ye(e,ft,l,s,S)|0:Be=1,((K?0:(Me=w(u-I),!(Re(r,Me,L)|0)))?!(rt(r,Me,h,L)|0):0)?K=Ye(r,Me,h,D,L)|0:K=1,K=Be&K),K|0}function Re(e,n,r){return e=e|0,n=w(n),r=w(r),(e|0)==1?e=Ci(n,r)|0:e=0,e|0}function rt(e,n,r,u){return e=e|0,n=w(n),r=r|0,u=w(u),(e|0)==2&(r|0)==0?n>=u?e=1:e=Ci(n,u)|0:e=0,e|0}function Ye(e,n,r,u,l){return e=e|0,n=w(n),r=r|0,u=w(u),l=w(l),(e|0)==2&(r|0)==2&u>n?l<=n?e=1:e=Ci(n,l)|0:e=0,e|0}function Kt(e,n,r,u,l,s,h,D,S,L,k){e=e|0,n=w(n),r=w(r),u=u|0,l=l|0,s=s|0,h=w(h),D=w(D),S=S|0,L=L|0,k=k|0;var I=0,K=0,Be=0,Te=0,ye=Tt,Ze=Tt,Ge=0,ft=0,Me=0,Pe=0,Zt=0,Br=0,In=0,gn=0,_r=0,Pr=0,Ln=0,uu=Tt,ls=Tt,ss=Tt,as=0,ta=0;Ln=m,m=m+160|0,gn=Ln+152|0,In=Ln+120|0,Br=Ln+104|0,Me=Ln+72|0,Te=Ln+56|0,Zt=Ln+8|0,ft=Ln,Pe=(t[2279]|0)+1|0,t[2279]=Pe,_r=e+984|0,((c[_r>>0]|0)!=0?(t[e+512>>2]|0)!=(t[2278]|0):0)?Ge=4:(t[e+516>>2]|0)==(u|0)?Pr=0:Ge=4,(Ge|0)==4&&(t[e+520>>2]=0,t[e+924>>2]=-1,t[e+928>>2]=-1,T[e+932>>2]=w(-1),T[e+936>>2]=w(-1),Pr=1);e:do if(t[e+964>>2]|0)if(ye=w(Xt(e,2,h)),Ze=w(Xt(e,0,h)),I=e+916|0,ss=w(T[I>>2]),ls=w(T[e+920>>2]),uu=w(T[e+932>>2]),n0(l,n,s,r,t[e+924>>2]|0,ss,t[e+928>>2]|0,ls,uu,w(T[e+936>>2]),ye,Ze,k)|0)Ge=22;else if(Be=t[e+520>>2]|0,!Be)Ge=21;else for(K=0;;){if(I=e+524+(K*24|0)|0,uu=w(T[I>>2]),ls=w(T[e+524+(K*24|0)+4>>2]),ss=w(T[e+524+(K*24|0)+16>>2]),n0(l,n,s,r,t[e+524+(K*24|0)+8>>2]|0,uu,t[e+524+(K*24|0)+12>>2]|0,ls,ss,w(T[e+524+(K*24|0)+20>>2]),ye,Ze,k)|0){Ge=22;break e}if(K=K+1|0,K>>>0>=Be>>>0){Ge=21;break}}else{if(S){if(I=e+916|0,!(Ci(w(T[I>>2]),n)|0)){Ge=21;break}if(!(Ci(w(T[e+920>>2]),r)|0)){Ge=21;break}if((t[e+924>>2]|0)!=(l|0)){Ge=21;break}I=(t[e+928>>2]|0)==(s|0)?I:0,Ge=22;break}if(Be=t[e+520>>2]|0,!Be)Ge=21;else for(K=0;;){if(I=e+524+(K*24|0)|0,((Ci(w(T[I>>2]),n)|0?Ci(w(T[e+524+(K*24|0)+4>>2]),r)|0:0)?(t[e+524+(K*24|0)+8>>2]|0)==(l|0):0)?(t[e+524+(K*24|0)+12>>2]|0)==(s|0):0){Ge=22;break e}if(K=K+1|0,K>>>0>=Be>>>0){Ge=21;break}}}while(0);do if((Ge|0)==21)c[11697]|0?(I=0,Ge=28):(I=0,Ge=31);else if((Ge|0)==22){if(K=(c[11697]|0)!=0,!((I|0)!=0&(Pr^1)))if(K){Ge=28;break}else{Ge=31;break}Te=I+16|0,t[e+908>>2]=t[Te>>2],Be=I+20|0,t[e+912>>2]=t[Be>>2],(c[11698]|0)==0|K^1||(t[ft>>2]=Wr(Pe)|0,t[ft+4>>2]=Pe,pr(e,4,2972,ft),K=t[e+972>>2]|0,K|0&&P1[K&127](e),l=xn(l,S)|0,s=xn(s,S)|0,ta=+w(T[Te>>2]),as=+w(T[Be>>2]),t[Zt>>2]=l,t[Zt+4>>2]=s,B[Zt+8>>3]=+n,B[Zt+16>>3]=+r,B[Zt+24>>3]=ta,B[Zt+32>>3]=as,t[Zt+40>>2]=L,pr(e,4,2989,Zt))}while(0);return(Ge|0)==28&&(K=Wr(Pe)|0,t[Te>>2]=K,t[Te+4>>2]=Pe,t[Te+8>>2]=Pr?3047:11699,pr(e,4,3038,Te),K=t[e+972>>2]|0,K|0&&P1[K&127](e),Zt=xn(l,S)|0,Ge=xn(s,S)|0,t[Me>>2]=Zt,t[Me+4>>2]=Ge,B[Me+8>>3]=+n,B[Me+16>>3]=+r,t[Me+24>>2]=L,pr(e,4,3049,Me),Ge=31),(Ge|0)==31&&(yu(e,n,r,u,l,s,h,D,S,k),c[11697]|0&&(K=t[2279]|0,Zt=Wr(K)|0,t[Br>>2]=Zt,t[Br+4>>2]=K,t[Br+8>>2]=Pr?3047:11699,pr(e,4,3083,Br),K=t[e+972>>2]|0,K|0&&P1[K&127](e),Zt=xn(l,S)|0,Br=xn(s,S)|0,as=+w(T[e+908>>2]),ta=+w(T[e+912>>2]),t[In>>2]=Zt,t[In+4>>2]=Br,B[In+8>>3]=as,B[In+16>>3]=ta,t[In+24>>2]=L,pr(e,4,3092,In)),t[e+516>>2]=u,I||(K=e+520|0,I=t[K>>2]|0,(I|0)==16&&(c[11697]|0&&pr(e,4,3124,gn),t[K>>2]=0,I=0),S?I=e+916|0:(t[K>>2]=I+1,I=e+524+(I*24|0)|0),T[I>>2]=n,T[I+4>>2]=r,t[I+8>>2]=l,t[I+12>>2]=s,t[I+16>>2]=t[e+908>>2],t[I+20>>2]=t[e+912>>2],I=0)),S&&(t[e+416>>2]=t[e+908>>2],t[e+420>>2]=t[e+912>>2],c[e+985>>0]=1,c[_r>>0]=0),t[2279]=(t[2279]|0)+-1,t[e+512>>2]=t[2278],m=Ln,Pr|(I|0)==0|0}function Xt(e,n,r){e=e|0,n=n|0,r=w(r);var u=Tt;return u=w(zi(e,n,r)),w(u+w(Oo(e,n,r)))}function pr(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=m,m=m+16|0,l=s,t[l>>2]=u,e?u=t[e+976>>2]|0:u=0,Hs(u,e,n,r,l),m=s}function Wr(e){return e=e|0,(e>>>0>60?3201:3201+(60-e)|0)|0}function xn(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;return l=m,m=m+32|0,r=l+12|0,u=l,t[r>>2]=t[254],t[r+4>>2]=t[255],t[r+8>>2]=t[256],t[u>>2]=t[257],t[u+4>>2]=t[258],t[u+8>>2]=t[259],(e|0)>2?e=11699:e=t[(n?u:r)+(e<<2)>>2]|0,m=l,e|0}function yu(e,n,r,u,l,s,h,D,S,L){e=e|0,n=w(n),r=w(r),u=u|0,l=l|0,s=s|0,h=w(h),D=w(D),S=S|0,L=L|0;var k=0,I=0,K=0,Be=0,Te=Tt,ye=Tt,Ze=Tt,Ge=Tt,ft=Tt,Me=Tt,Pe=Tt,Zt=0,Br=0,In=0,gn=Tt,_r=Tt,Pr=0,Ln=Tt,uu=0,ls=0,ss=0,as=0,ta=0,r2=0,i2=0,of=0,u2=0,Pc=0,Ic=0,o2=0,l2=0,s2=0,vi=0,lf=0,a2=0,Kf=0,f2=Tt,c2=Tt,bc=Tt,Bc=Tt,Xf=Tt,ql=0,Fa=0,Ns=0,sf=0,b1=0,B1=Tt,Uc=Tt,U1=Tt,j1=Tt,Wl=Tt,El=Tt,af=0,vu=Tt,z1=Tt,fs=Tt,Qf=Tt,cs=Tt,Jf=Tt,H1=0,q1=0,Zf=Tt,Vl=Tt,ff=0,W1=0,V1=0,G1=0,Sr=Tt,Bu=0,Dl=0,ds=0,Gl=0,Or=0,Bn=0,cf=0,mn=Tt,Y1=0,fo=0;cf=m,m=m+16|0,ql=cf+12|0,Fa=cf+8|0,Ns=cf+4|0,sf=cf,qu(e,(l|0)==0|(Le(n)|0)^1,3326),qu(e,(s|0)==0|(Le(r)|0)^1,3406),Dl=xl(e,u)|0,t[e+496>>2]=Dl,Or=Uo(2,Dl)|0,Bn=Uo(0,Dl)|0,T[e+440>>2]=w(zi(e,Or,h)),T[e+444>>2]=w(Oo(e,Or,h)),T[e+428>>2]=w(zi(e,Bn,h)),T[e+436>>2]=w(Oo(e,Bn,h)),T[e+464>>2]=w(Mo(e,Or)),T[e+468>>2]=w(v0(e,Or)),T[e+452>>2]=w(Mo(e,Bn)),T[e+460>>2]=w(v0(e,Bn)),T[e+488>>2]=w(Pu(e,Or,h)),T[e+492>>2]=w(Zu(e,Or,h)),T[e+476>>2]=w(Pu(e,Bn,h)),T[e+484>>2]=w(Zu(e,Bn,h));do if(t[e+964>>2]|0)ts(e,n,r,l,s,h,D);else{if(ds=e+948|0,Gl=(t[e+952>>2]|0)-(t[ds>>2]|0)>>2,!Gl){Es(e,n,r,l,s,h,D);break}if(S?0:fa(e,n,r,l,s,h,D)|0)break;ys(e),lf=e+508|0,c[lf>>0]=0,Or=Uo(t[e+4>>2]|0,Dl)|0,Bn=_f(Or,Dl)|0,Bu=Hi(Or)|0,a2=t[e+8>>2]|0,W1=e+28|0,Kf=(t[W1>>2]|0)!=0,cs=Bu?h:D,Zf=Bu?D:h,f2=w($u(e,Or,h)),c2=w(Ds(e,Or,h)),Te=w($u(e,Bn,h)),Jf=w(Rr(e,Or,h)),Vl=w(Rr(e,Bn,h)),In=Bu?l:s,ff=Bu?s:l,Sr=Bu?Jf:Vl,ft=Bu?Vl:Jf,Qf=w(Xt(e,2,h)),Ge=w(Xt(e,0,h)),ye=w(w(Rn(e+364|0,h))-Sr),Ze=w(w(Rn(e+380|0,h))-Sr),Me=w(w(Rn(e+372|0,D))-ft),Pe=w(w(Rn(e+388|0,D))-ft),bc=Bu?ye:Me,Bc=Bu?Ze:Pe,Qf=w(n-Qf),n=w(Qf-Sr),Le(n)|0?Sr=n:Sr=w(Ru(w(Qp(n,Ze)),ye)),z1=w(r-Ge),n=w(z1-ft),Le(n)|0?fs=n:fs=w(Ru(w(Qp(n,Pe)),Me)),ye=Bu?Sr:fs,vu=Bu?fs:Sr;e:do if((In|0)==1)for(u=0,I=0;;){if(k=Ti(e,I)|0,!u)(w(nu(k))>w(0)?w(cu(k))>w(0):0)?u=k:u=0;else if(r0(k)|0){Be=0;break e}if(I=I+1|0,I>>>0>=Gl>>>0){Be=u;break}}else Be=0;while(0);Zt=Be+500|0,Br=Be+504|0,u=0,k=0,n=w(0),K=0;do{if(I=t[(t[ds>>2]|0)+(K<<2)>>2]|0,(t[I+36>>2]|0)==1)Ni(I),c[I+985>>0]=1,c[I+984>>0]=0;else{Jr(I),S&&Ro(I,xl(I,Dl)|0,ye,vu,Sr);do if((t[I+24>>2]|0)!=1)if((I|0)==(Be|0)){t[Zt>>2]=t[2278],T[Br>>2]=w(0);break}else{ni(e,I,Sr,l,fs,Sr,fs,s,Dl,L);break}else k|0&&(t[k+960>>2]=I),t[I+960>>2]=0,k=I,u=(u|0)==0?I:u;while(0);El=w(T[I+504>>2]),n=w(n+w(El+w(Xt(I,Or,Sr))))}K=K+1|0}while((K|0)!=(Gl|0));for(ss=n>ye,af=Kf&((In|0)==2&ss)?1:In,uu=(ff|0)==1,ta=uu&(S^1),r2=(af|0)==1,i2=(af|0)==2,of=976+(Or<<2)|0,u2=(ff|2|0)==2,s2=uu&(Kf^1),Pc=1040+(Bn<<2)|0,Ic=1040+(Or<<2)|0,o2=976+(Bn<<2)|0,l2=(ff|0)!=1,ss=Kf&((In|0)!=0&ss),ls=e+976|0,uu=uu^1,n=ye,Pr=0,as=0,El=w(0),Xf=w(0);;){e:do if(Pr>>>0>>0)for(Br=t[ds>>2]|0,K=0,Pe=w(0),Me=w(0),Ze=w(0),ye=w(0),I=0,k=0,Be=Pr;;){if(Zt=t[Br+(Be<<2)>>2]|0,(t[Zt+36>>2]|0)!=1?(t[Zt+940>>2]=as,(t[Zt+24>>2]|0)!=1):0){if(Ge=w(Xt(Zt,Or,Sr)),vi=t[of>>2]|0,r=w(Rn(Zt+380+(vi<<3)|0,cs)),ft=w(T[Zt+504>>2]),r=w(Qp(r,ft)),r=w(Ru(w(Rn(Zt+364+(vi<<3)|0,cs)),r)),Kf&(K|0)!=0&w(Ge+w(Me+r))>n){s=K,Ge=Pe,In=Be;break e}Ge=w(Ge+r),r=w(Me+Ge),Ge=w(Pe+Ge),r0(Zt)|0&&(Ze=w(Ze+w(nu(Zt))),ye=w(ye-w(ft*w(cu(Zt))))),k|0&&(t[k+960>>2]=Zt),t[Zt+960>>2]=0,K=K+1|0,k=Zt,I=(I|0)==0?Zt:I}else Ge=Pe,r=Me;if(Be=Be+1|0,Be>>>0>>0)Pe=Ge,Me=r;else{s=K,In=Be;break}}else s=0,Ge=w(0),Ze=w(0),ye=w(0),I=0,In=Pr;while(0);vi=Ze>w(0)&Zew(0)&yeBc&((Le(Bc)|0)^1))n=Bc,vi=51;else if(c[(t[ls>>2]|0)+3>>0]|0)vi=51;else{if(gn!=w(0)?w(nu(e))!=w(0):0){vi=53;break}n=Ge,vi=53}while(0);if((vi|0)==51&&(vi=0,Le(n)|0?vi=53:(_r=w(n-Ge),Ln=n)),(vi|0)==53&&(vi=0,Ge>2]|0,Be=_rw(0),Me=w(_r/gn),Ze=w(0),Ge=w(0),n=w(0),k=I;do r=w(Rn(k+380+(K<<3)|0,cs)),ye=w(Rn(k+364+(K<<3)|0,cs)),ye=w(Qp(r,w(Ru(ye,w(T[k+504>>2]))))),Be?(r=w(ye*w(cu(k))),(r!=w(-0)?(mn=w(ye-w(ft*r)),B1=w(Kn(k,Or,mn,Ln,Sr)),mn!=B1):0)&&(Ze=w(Ze-w(B1-ye)),n=w(n+r))):((Zt?(Uc=w(nu(k)),Uc!=w(0)):0)?(mn=w(ye+w(Me*Uc)),U1=w(Kn(k,Or,mn,Ln,Sr)),mn!=U1):0)&&(Ze=w(Ze-w(U1-ye)),Ge=w(Ge-Uc)),k=t[k+960>>2]|0;while((k|0)!=0);if(n=w(Pe+n),ye=w(_r+Ze),b1)n=w(0);else{ft=w(gn+Ge),Be=t[of>>2]|0,Zt=yew(0),ft=w(ye/ft),n=w(0);do{mn=w(Rn(I+380+(Be<<3)|0,cs)),Ze=w(Rn(I+364+(Be<<3)|0,cs)),Ze=w(Qp(mn,w(Ru(Ze,w(T[I+504>>2]))))),Zt?(mn=w(Ze*w(cu(I))),ye=w(-mn),mn!=w(-0)?(mn=w(Me*ye),ye=w(Kn(I,Or,w(Ze+(Br?ye:mn)),Ln,Sr))):ye=Ze):(K?(j1=w(nu(I)),j1!=w(0)):0)?ye=w(Kn(I,Or,w(Ze+w(ft*j1)),Ln,Sr)):ye=Ze,n=w(n-w(ye-Ze)),Ge=w(Xt(I,Or,Sr)),r=w(Xt(I,Bn,Sr)),ye=w(ye+Ge),T[Fa>>2]=ye,t[sf>>2]=1,Ze=w(T[I+396>>2]);e:do if(Le(Ze)|0){k=Le(vu)|0;do if(!k){if(ss|(Wu(I,Bn,vu)|0|uu)||(eo(e,I)|0)!=4||(t[(Eo(I,Bn)|0)+4>>2]|0)==3||(t[(Do(I,Bn)|0)+4>>2]|0)==3)break;T[ql>>2]=vu,t[Ns>>2]=1;break e}while(0);if(Wu(I,Bn,vu)|0){k=t[I+992+(t[o2>>2]<<2)>>2]|0,mn=w(r+w(Rn(k,vu))),T[ql>>2]=mn,k=l2&(t[k+4>>2]|0)==2,t[Ns>>2]=((Le(mn)|0|k)^1)&1;break}else{T[ql>>2]=vu,t[Ns>>2]=k?0:2;break}}else mn=w(ye-Ge),gn=w(mn/Ze),mn=w(Ze*mn),t[Ns>>2]=1,T[ql>>2]=w(r+(Bu?gn:mn));while(0);Fn(I,Or,Ln,Sr,sf,Fa),Fn(I,Bn,vu,Sr,Ns,ql);do if(Wu(I,Bn,vu)|0?0:(eo(e,I)|0)==4){if((t[(Eo(I,Bn)|0)+4>>2]|0)==3){k=0;break}k=(t[(Do(I,Bn)|0)+4>>2]|0)!=3}else k=0;while(0);mn=w(T[Fa>>2]),gn=w(T[ql>>2]),Y1=t[sf>>2]|0,fo=t[Ns>>2]|0,Kt(I,Bu?mn:gn,Bu?gn:mn,Dl,Bu?Y1:fo,Bu?fo:Y1,Sr,fs,S&(k^1),3488,L)|0,c[lf>>0]=c[lf>>0]|c[I+508>>0],I=t[I+960>>2]|0}while((I|0)!=0)}}else n=w(0);if(n=w(_r+n),fo=n>0]=fo|M[lf>>0],i2&n>w(0)?(k=t[of>>2]|0,((t[e+364+(k<<3)+4>>2]|0)!=0?(Wl=w(Rn(e+364+(k<<3)|0,cs)),Wl>=w(0)):0)?ye=w(Ru(w(0),w(Wl-w(Ln-n)))):ye=w(0)):ye=n,Zt=Pr>>>0>>0,Zt){Be=t[ds>>2]|0,K=Pr,k=0;do I=t[Be+(K<<2)>>2]|0,t[I+24>>2]|0||(k=((t[(Eo(I,Or)|0)+4>>2]|0)==3&1)+k|0,k=k+((t[(Do(I,Or)|0)+4>>2]|0)==3&1)|0),K=K+1|0;while((K|0)!=(In|0));k?(Ge=w(0),r=w(0)):vi=101}else vi=101;e:do if((vi|0)==101)switch(vi=0,a2|0){case 1:{k=0,Ge=w(ye*w(.5)),r=w(0);break e}case 2:{k=0,Ge=ye,r=w(0);break e}case 3:{if(s>>>0<=1){k=0,Ge=w(0),r=w(0);break e}r=w((s+-1|0)>>>0),k=0,Ge=w(0),r=w(w(Ru(ye,w(0)))/r);break e}case 5:{r=w(ye/w((s+1|0)>>>0)),k=0,Ge=r;break e}case 4:{r=w(ye/w(s>>>0)),k=0,Ge=w(r*w(.5));break e}default:{k=0,Ge=w(0),r=w(0);break e}}while(0);if(n=w(f2+Ge),Zt){Ze=w(ye/w(k|0)),K=t[ds>>2]|0,I=Pr,ye=w(0);do{k=t[K+(I<<2)>>2]|0;e:do if((t[k+36>>2]|0)!=1){switch(t[k+24>>2]|0){case 1:{if(ae(k,Or)|0){if(!S)break e;mn=w(ie(k,Or,Ln)),mn=w(mn+w(Mo(e,Or))),mn=w(mn+w(zi(k,Or,Sr))),T[k+400+(t[Ic>>2]<<2)>>2]=mn;break e}break}case 0:if(fo=(t[(Eo(k,Or)|0)+4>>2]|0)==3,mn=w(Ze+n),n=fo?mn:n,S&&(fo=k+400+(t[Ic>>2]<<2)|0,T[fo>>2]=w(n+w(T[fo>>2]))),fo=(t[(Do(k,Or)|0)+4>>2]|0)==3,mn=w(Ze+n),n=fo?mn:n,ta){mn=w(r+w(Xt(k,Or,Sr))),ye=vu,n=w(n+w(mn+w(T[k+504>>2])));break e}else{n=w(n+w(r+w(Fe(k,Or,Sr)))),ye=w(Ru(ye,w(Fe(k,Bn,Sr))));break e}default:}S&&(mn=w(Ge+w(Mo(e,Or))),fo=k+400+(t[Ic>>2]<<2)|0,T[fo>>2]=w(mn+w(T[fo>>2])))}while(0);I=I+1|0}while((I|0)!=(In|0))}else ye=w(0);if(r=w(c2+n),u2?Ge=w(w(Kn(e,Bn,w(Vl+ye),Zf,h))-Vl):Ge=vu,Ze=w(w(Kn(e,Bn,w(Vl+(s2?vu:ye)),Zf,h))-Vl),Zt&S){I=Pr;do{K=t[(t[ds>>2]|0)+(I<<2)>>2]|0;do if((t[K+36>>2]|0)!=1){if((t[K+24>>2]|0)==1){if(ae(K,Bn)|0){if(mn=w(ie(K,Bn,vu)),mn=w(mn+w(Mo(e,Bn))),mn=w(mn+w(zi(K,Bn,Sr))),k=t[Pc>>2]|0,T[K+400+(k<<2)>>2]=mn,!(Le(mn)|0))break}else k=t[Pc>>2]|0;mn=w(Mo(e,Bn)),T[K+400+(k<<2)>>2]=w(mn+w(zi(K,Bn,Sr)));break}k=eo(e,K)|0;do if((k|0)==4){if((t[(Eo(K,Bn)|0)+4>>2]|0)==3){vi=139;break}if((t[(Do(K,Bn)|0)+4>>2]|0)==3){vi=139;break}if(Wu(K,Bn,vu)|0){n=Te;break}Y1=t[K+908+(t[of>>2]<<2)>>2]|0,t[ql>>2]=Y1,n=w(T[K+396>>2]),fo=Le(n)|0,ye=(t[q>>2]=Y1,w(T[q>>2])),fo?n=Ze:(_r=w(Xt(K,Bn,Sr)),mn=w(ye/n),n=w(n*ye),n=w(_r+(Bu?mn:n))),T[Fa>>2]=n,T[ql>>2]=w(w(Xt(K,Or,Sr))+ye),t[Ns>>2]=1,t[sf>>2]=1,Fn(K,Or,Ln,Sr,Ns,ql),Fn(K,Bn,vu,Sr,sf,Fa),n=w(T[ql>>2]),_r=w(T[Fa>>2]),mn=Bu?n:_r,n=Bu?_r:n,fo=((Le(mn)|0)^1)&1,Kt(K,mn,n,Dl,fo,((Le(n)|0)^1)&1,Sr,fs,1,3493,L)|0,n=Te}else vi=139;while(0);e:do if((vi|0)==139){vi=0,n=w(Ge-w(Fe(K,Bn,Sr)));do if((t[(Eo(K,Bn)|0)+4>>2]|0)==3){if((t[(Do(K,Bn)|0)+4>>2]|0)!=3)break;n=w(Te+w(Ru(w(0),w(n*w(.5)))));break e}while(0);if((t[(Do(K,Bn)|0)+4>>2]|0)==3){n=Te;break}if((t[(Eo(K,Bn)|0)+4>>2]|0)==3){n=w(Te+w(Ru(w(0),n)));break}switch(k|0){case 1:{n=Te;break e}case 2:{n=w(Te+w(n*w(.5)));break e}default:{n=w(Te+n);break e}}}while(0);mn=w(El+n),fo=K+400+(t[Pc>>2]<<2)|0,T[fo>>2]=w(mn+w(T[fo>>2]))}while(0);I=I+1|0}while((I|0)!=(In|0))}if(El=w(El+Ze),Xf=w(Ru(Xf,r)),s=as+1|0,In>>>0>=Gl>>>0)break;n=Ln,Pr=In,as=s}do if(S){if(k=s>>>0>1,k?0:!(Oe(e)|0))break;if(!(Le(vu)|0)){n=w(vu-El);e:do switch(t[e+12>>2]|0){case 3:{Te=w(Te+n),Me=w(0);break}case 2:{Te=w(Te+w(n*w(.5))),Me=w(0);break}case 4:{vu>El?Me=w(n/w(s>>>0)):Me=w(0);break}case 7:if(vu>El){Te=w(Te+w(n/w(s<<1>>>0))),Me=w(n/w(s>>>0)),Me=k?Me:w(0);break e}else{Te=w(Te+w(n*w(.5))),Me=w(0);break e}case 6:{Me=w(n/w(as>>>0)),Me=vu>El&k?Me:w(0);break}default:Me=w(0)}while(0);if(s|0)for(Zt=1040+(Bn<<2)|0,Br=976+(Bn<<2)|0,Be=0,I=0;;){e:do if(I>>>0>>0)for(ye=w(0),Ze=w(0),n=w(0),K=I;;){k=t[(t[ds>>2]|0)+(K<<2)>>2]|0;do if((t[k+36>>2]|0)!=1?(t[k+24>>2]|0)==0:0){if((t[k+940>>2]|0)!=(Be|0))break e;if(st(k,Bn)|0&&(mn=w(T[k+908+(t[Br>>2]<<2)>>2]),n=w(Ru(n,w(mn+w(Xt(k,Bn,Sr)))))),(eo(e,k)|0)!=5)break;Wl=w(yt(k)),Wl=w(Wl+w(zi(k,0,Sr))),mn=w(T[k+912>>2]),mn=w(w(mn+w(Xt(k,0,Sr)))-Wl),Wl=w(Ru(Ze,Wl)),mn=w(Ru(ye,mn)),ye=mn,Ze=Wl,n=w(Ru(n,w(Wl+mn)))}while(0);if(k=K+1|0,k>>>0>>0)K=k;else{K=k;break}}else Ze=w(0),n=w(0),K=I;while(0);if(ft=w(Me+n),r=Te,Te=w(Te+ft),I>>>0>>0){Ge=w(r+Ze),k=I;do{I=t[(t[ds>>2]|0)+(k<<2)>>2]|0;e:do if((t[I+36>>2]|0)!=1?(t[I+24>>2]|0)==0:0)switch(eo(e,I)|0){case 1:{mn=w(r+w(zi(I,Bn,Sr))),T[I+400+(t[Zt>>2]<<2)>>2]=mn;break e}case 3:{mn=w(w(Te-w(Oo(I,Bn,Sr)))-w(T[I+908+(t[Br>>2]<<2)>>2])),T[I+400+(t[Zt>>2]<<2)>>2]=mn;break e}case 2:{mn=w(r+w(w(ft-w(T[I+908+(t[Br>>2]<<2)>>2]))*w(.5))),T[I+400+(t[Zt>>2]<<2)>>2]=mn;break e}case 4:{if(mn=w(r+w(zi(I,Bn,Sr))),T[I+400+(t[Zt>>2]<<2)>>2]=mn,Wu(I,Bn,vu)|0||(Bu?(ye=w(T[I+908>>2]),n=w(ye+w(Xt(I,Or,Sr))),Ze=ft):(Ze=w(T[I+912>>2]),Ze=w(Ze+w(Xt(I,Bn,Sr))),n=ft,ye=w(T[I+908>>2])),Ci(n,ye)|0?Ci(Ze,w(T[I+912>>2]))|0:0))break e;Kt(I,n,Ze,Dl,1,1,Sr,fs,1,3501,L)|0;break e}case 5:{T[I+404>>2]=w(w(Ge-w(yt(I)))+w(ie(I,0,vu)));break e}default:break e}while(0);k=k+1|0}while((k|0)!=(K|0))}if(Be=Be+1|0,(Be|0)==(s|0))break;I=K}}}while(0);if(T[e+908>>2]=w(Kn(e,2,Qf,h,h)),T[e+912>>2]=w(Kn(e,0,z1,D,h)),((af|0)!=0?(H1=t[e+32>>2]|0,q1=(af|0)==2,!(q1&(H1|0)!=2)):0)?q1&(H1|0)==2&&(n=w(Jf+Ln),n=w(Ru(w(Qp(n,w(Jt(e,Or,Xf,cs)))),Jf)),vi=198):(n=w(Kn(e,Or,Xf,cs,h)),vi=198),(vi|0)==198&&(T[e+908+(t[976+(Or<<2)>>2]<<2)>>2]=n),((ff|0)!=0?(V1=t[e+32>>2]|0,G1=(ff|0)==2,!(G1&(V1|0)!=2)):0)?G1&(V1|0)==2&&(n=w(Vl+vu),n=w(Ru(w(Qp(n,w(Jt(e,Bn,w(Vl+El),Zf)))),Vl)),vi=204):(n=w(Kn(e,Bn,w(Vl+El),Zf,h)),vi=204),(vi|0)==204&&(T[e+908+(t[976+(Bn<<2)>>2]<<2)>>2]=n),S){if((t[W1>>2]|0)==2){I=976+(Bn<<2)|0,K=1040+(Bn<<2)|0,k=0;do Be=Ti(e,k)|0,t[Be+24>>2]|0||(Y1=t[I>>2]|0,mn=w(T[e+908+(Y1<<2)>>2]),fo=Be+400+(t[K>>2]<<2)|0,mn=w(mn-w(T[fo>>2])),T[fo>>2]=w(mn-w(T[Be+908+(Y1<<2)>>2]))),k=k+1|0;while((k|0)!=(Gl|0))}if(u|0){k=Bu?af:l;do On(e,u,Sr,k,fs,Dl,L),u=t[u+960>>2]|0;while((u|0)!=0)}if(k=(Or|2|0)==3,I=(Bn|2|0)==3,k|I){u=0;do K=t[(t[ds>>2]|0)+(u<<2)>>2]|0,(t[K+36>>2]|0)!=1&&(k&&Sn(e,K,Or),I&&Sn(e,K,Bn)),u=u+1|0;while((u|0)!=(Gl|0))}}}while(0);m=cf}function Ju(e,n){e=e|0,n=w(n);var r=0;Cn(e,n>=w(0),3147),r=n==w(0),T[e+4>>2]=r?w(0):n}function ti(e,n,r,u){e=e|0,n=w(n),r=w(r),u=u|0;var l=Tt,s=Tt,h=0,D=0,S=0;t[2278]=(t[2278]|0)+1,Jr(e),Wu(e,2,n)|0?(l=w(Rn(t[e+992>>2]|0,n)),S=1,l=w(l+w(Xt(e,2,n)))):(l=w(Rn(e+380|0,n)),l>=w(0)?S=2:(S=((Le(n)|0)^1)&1,l=n)),Wu(e,0,r)|0?(s=w(Rn(t[e+996>>2]|0,r)),D=1,s=w(s+w(Xt(e,0,n)))):(s=w(Rn(e+388|0,r)),s>=w(0)?D=2:(D=((Le(r)|0)^1)&1,s=r)),h=e+976|0,(Kt(e,l,s,u,S,D,n,r,1,3189,t[h>>2]|0)|0?(Ro(e,t[e+496>>2]|0,n,r,n),Fu(e,w(T[(t[h>>2]|0)+4>>2]),w(0),w(0)),c[11696]|0):0)&&yf(e,7)}function Jr(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;D=m,m=m+32|0,h=D+24|0,s=D+16|0,u=D+8|0,l=D,r=0;do n=e+380+(r<<3)|0,((t[e+380+(r<<3)+4>>2]|0)!=0?(S=n,L=t[S+4>>2]|0,k=u,t[k>>2]=t[S>>2],t[k+4>>2]=L,k=e+364+(r<<3)|0,L=t[k+4>>2]|0,S=l,t[S>>2]=t[k>>2],t[S+4>>2]=L,t[s>>2]=t[u>>2],t[s+4>>2]=t[u+4>>2],t[h>>2]=t[l>>2],t[h+4>>2]=t[l+4>>2],Bi(s,h)|0):0)||(n=e+348+(r<<3)|0),t[e+992+(r<<2)>>2]=n,r=r+1|0;while((r|0)!=2);m=D}function Wu(e,n,r){e=e|0,n=n|0,r=w(r);var u=0;switch(e=t[e+992+(t[976+(n<<2)>>2]<<2)>>2]|0,t[e+4>>2]|0){case 0:case 3:{e=0;break}case 1:{w(T[e>>2])>2])>2]|0){case 2:{n=w(w(w(T[e>>2])*n)/w(100));break}case 1:{n=w(T[e>>2]);break}default:n=w(re)}return w(n)}function Ro(e,n,r,u,l){e=e|0,n=n|0,r=w(r),u=w(u),l=w(l);var s=0,h=Tt;n=t[e+944>>2]|0?n:1,s=Uo(t[e+4>>2]|0,n)|0,n=_f(s,n)|0,r=w(Ar(e,s,r)),u=w(Ar(e,n,u)),h=w(r+w(zi(e,s,l))),T[e+400+(t[1040+(s<<2)>>2]<<2)>>2]=h,r=w(r+w(Oo(e,s,l))),T[e+400+(t[1e3+(s<<2)>>2]<<2)>>2]=r,r=w(u+w(zi(e,n,l))),T[e+400+(t[1040+(n<<2)>>2]<<2)>>2]=r,l=w(u+w(Oo(e,n,l))),T[e+400+(t[1e3+(n<<2)>>2]<<2)>>2]=l}function Fu(e,n,r,u){e=e|0,n=w(n),r=w(r),u=w(u);var l=0,s=0,h=Tt,D=Tt,S=0,L=0,k=Tt,I=0,K=Tt,Be=Tt,Te=Tt,ye=Tt;if(n!=w(0)&&(l=e+400|0,ye=w(T[l>>2]),s=e+404|0,Te=w(T[s>>2]),I=e+416|0,Be=w(T[I>>2]),L=e+420|0,h=w(T[L>>2]),K=w(ye+r),k=w(Te+u),u=w(K+Be),D=w(k+h),S=(t[e+988>>2]|0)==1,T[l>>2]=w(t0(ye,n,0,S)),T[s>>2]=w(t0(Te,n,0,S)),r=w(QE(w(Be*n),w(1))),Ci(r,w(0))|0?s=0:s=(Ci(r,w(1))|0)^1,r=w(QE(w(h*n),w(1))),Ci(r,w(0))|0?l=0:l=(Ci(r,w(1))|0)^1,ye=w(t0(u,n,S&s,S&(s^1))),T[I>>2]=w(ye-w(t0(K,n,0,S))),ye=w(t0(D,n,S&l,S&(l^1))),T[L>>2]=w(ye-w(t0(k,n,0,S))),s=(t[e+952>>2]|0)-(t[e+948>>2]|0)>>2,s|0)){l=0;do Fu(Ti(e,l)|0,n,K,k),l=l+1|0;while((l|0)!=(s|0))}}function li(e,n,r,u,l){switch(e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,r|0){case 5:case 0:{e=b8(t[489]|0,u,l)|0;break}default:e=JF(u,l)|0}return e|0}function Cl(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;l=m,m=m+16|0,s=l,t[s>>2]=u,Hs(e,0,n,r,s),m=l}function Hs(e,n,r,u,l){if(e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,e=e|0?e:956,iS[t[e+8>>2]&1](e,n,r,u,l)|0,(r|0)==5)$n();else return}function Vu(e,n,r){e=e|0,n=n|0,r=r|0,c[e+n>>0]=r&1}function aa(e,n){e=e|0,n=n|0;var r=0,u=0;t[e>>2]=0,t[e+4>>2]=0,t[e+8>>2]=0,r=n+4|0,u=(t[r>>2]|0)-(t[n>>2]|0)>>2,u|0&&(Xi(e,u),qs(e,t[n>>2]|0,t[r>>2]|0,u))}function Xi(e,n){e=e|0,n=n|0;var r=0;if((Ao(e)|0)>>>0>>0&&hi(e),n>>>0>1073741823)$n();else{r=pn(n<<2)|0,t[e+4>>2]=r,t[e>>2]=r,t[e+8>>2]=r+(n<<2);return}}function qs(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,u=e+4|0,e=r-n|0,(e|0)>0&&(gr(t[u>>2]|0,n|0,e|0)|0,t[u>>2]=(t[u>>2]|0)+(e>>>2<<2))}function Ao(e){return e=e|0,1073741823}function zi(e,n,r){return e=e|0,n=n|0,r=w(r),(Hi(n)|0?(t[e+96>>2]|0)!=0:0)?e=e+92|0:e=ht(e+60|0,t[1040+(n<<2)>>2]|0,992)|0,w(il(e,r))}function Oo(e,n,r){return e=e|0,n=n|0,r=w(r),(Hi(n)|0?(t[e+104>>2]|0)!=0:0)?e=e+100|0:e=ht(e+60|0,t[1e3+(n<<2)>>2]|0,992)|0,w(il(e,r))}function Hi(e){return e=e|0,(e|1|0)==3|0}function il(e,n){return e=e|0,n=w(n),(t[e+4>>2]|0)==3?n=w(0):n=w(Rn(e,n)),w(n)}function xl(e,n){return e=e|0,n=n|0,e=t[e>>2]|0,((e|0)==0?(n|0)>1?n:1:e)|0}function Uo(e,n){e=e|0,n=n|0;var r=0;e:do if((n|0)==2){switch(e|0){case 2:{e=3;break e}case 3:break;default:{r=4;break e}}e=2}else r=4;while(0);return e|0}function Mo(e,n){e=e|0,n=n|0;var r=Tt;return((Hi(n)|0?(t[e+312>>2]|0)!=0:0)?(r=w(T[e+308>>2]),r>=w(0)):0)||(r=w(Ru(w(T[(ht(e+276|0,t[1040+(n<<2)>>2]|0,992)|0)>>2]),w(0)))),w(r)}function v0(e,n){e=e|0,n=n|0;var r=Tt;return((Hi(n)|0?(t[e+320>>2]|0)!=0:0)?(r=w(T[e+316>>2]),r>=w(0)):0)||(r=w(Ru(w(T[(ht(e+276|0,t[1e3+(n<<2)>>2]|0,992)|0)>>2]),w(0)))),w(r)}function Pu(e,n,r){e=e|0,n=n|0,r=w(r);var u=Tt;return((Hi(n)|0?(t[e+240>>2]|0)!=0:0)?(u=w(Rn(e+236|0,r)),u>=w(0)):0)||(u=w(Ru(w(Rn(ht(e+204|0,t[1040+(n<<2)>>2]|0,992)|0,r)),w(0)))),w(u)}function Zu(e,n,r){e=e|0,n=n|0,r=w(r);var u=Tt;return((Hi(n)|0?(t[e+248>>2]|0)!=0:0)?(u=w(Rn(e+244|0,r)),u>=w(0)):0)||(u=w(Ru(w(Rn(ht(e+204|0,t[1e3+(n<<2)>>2]|0,992)|0,r)),w(0)))),w(u)}function ts(e,n,r,u,l,s,h){e=e|0,n=w(n),r=w(r),u=u|0,l=l|0,s=w(s),h=w(h);var D=Tt,S=Tt,L=Tt,k=Tt,I=Tt,K=Tt,Be=0,Te=0,ye=0;ye=m,m=m+16|0,Be=ye,Te=e+964|0,qu(e,(t[Te>>2]|0)!=0,3519),D=w(Rr(e,2,n)),S=w(Rr(e,0,n)),L=w(Xt(e,2,n)),k=w(Xt(e,0,n)),Le(n)|0?I=n:I=w(Ru(w(0),w(w(n-L)-D))),Le(r)|0?K=r:K=w(Ru(w(0),w(w(r-k)-S))),(u|0)==1&(l|0)==1?(T[e+908>>2]=w(Kn(e,2,w(n-L),s,s)),n=w(Kn(e,0,w(r-k),h,s))):(uS[t[Te>>2]&1](Be,e,I,u,K,l),I=w(D+w(T[Be>>2])),K=w(n-L),T[e+908>>2]=w(Kn(e,2,(u|2|0)==2?I:K,s,s)),K=w(S+w(T[Be+4>>2])),n=w(r-k),n=w(Kn(e,0,(l|2|0)==2?K:n,h,s))),T[e+912>>2]=n,m=ye}function Es(e,n,r,u,l,s,h){e=e|0,n=w(n),r=w(r),u=u|0,l=l|0,s=w(s),h=w(h);var D=Tt,S=Tt,L=Tt,k=Tt;L=w(Rr(e,2,s)),D=w(Rr(e,0,s)),k=w(Xt(e,2,s)),S=w(Xt(e,0,s)),n=w(n-k),T[e+908>>2]=w(Kn(e,2,(u|2|0)==2?L:n,s,s)),r=w(r-S),T[e+912>>2]=w(Kn(e,0,(l|2|0)==2?D:r,h,s))}function fa(e,n,r,u,l,s,h){e=e|0,n=w(n),r=w(r),u=u|0,l=l|0,s=w(s),h=w(h);var D=0,S=Tt,L=Tt;return D=(u|0)==2,((n<=w(0)&D?0:!(r<=w(0)&(l|0)==2))?!((u|0)==1&(l|0)==1):0)?e=0:(S=w(Xt(e,0,s)),L=w(Xt(e,2,s)),D=n>2]=w(Kn(e,2,D?w(0):n,s,s)),n=w(r-S),D=r>2]=w(Kn(e,0,D?w(0):n,h,s)),e=1),e|0}function _f(e,n){return e=e|0,n=n|0,_n(e)|0?e=Uo(2,n)|0:e=0,e|0}function $u(e,n,r){return e=e|0,n=n|0,r=w(r),r=w(Pu(e,n,r)),w(r+w(Mo(e,n)))}function Ds(e,n,r){return e=e|0,n=n|0,r=w(r),r=w(Zu(e,n,r)),w(r+w(v0(e,n)))}function Rr(e,n,r){e=e|0,n=n|0,r=w(r);var u=Tt;return u=w($u(e,n,r)),w(u+w(Ds(e,n,r)))}function r0(e){return e=e|0,t[e+24>>2]|0?e=0:w(nu(e))!=w(0)?e=1:e=w(cu(e))!=w(0),e|0}function nu(e){e=e|0;var n=Tt;if(t[e+944>>2]|0){if(n=w(T[e+44>>2]),Le(n)|0)return n=w(T[e+40>>2]),e=n>w(0)&((Le(n)|0)^1),w(e?n:w(0))}else n=w(0);return w(n)}function cu(e){e=e|0;var n=Tt,r=0,u=Tt;do if(t[e+944>>2]|0){if(n=w(T[e+48>>2]),Le(n)|0){if(r=c[(t[e+976>>2]|0)+2>>0]|0,r<<24>>24==0?(u=w(T[e+40>>2]),u>24?w(1):w(0)}}else n=w(0);while(0);return w(n)}function Ni(e){e=e|0;var n=0,r=0;if(jv(e+400|0,0,540)|0,c[e+985>>0]=1,ys(e),r=Su(e)|0,r|0){n=e+948|0,e=0;do Ni(t[(t[n>>2]|0)+(e<<2)>>2]|0),e=e+1|0;while((e|0)!=(r|0))}}function ni(e,n,r,u,l,s,h,D,S,L){e=e|0,n=n|0,r=w(r),u=u|0,l=w(l),s=w(s),h=w(h),D=D|0,S=S|0,L=L|0;var k=0,I=Tt,K=0,Be=0,Te=Tt,ye=Tt,Ze=0,Ge=Tt,ft=0,Me=Tt,Pe=0,Zt=0,Br=0,In=0,gn=0,_r=0,Pr=0,Ln=0,uu=0,ls=0;uu=m,m=m+16|0,Br=uu+12|0,In=uu+8|0,gn=uu+4|0,_r=uu,Ln=Uo(t[e+4>>2]|0,S)|0,Pe=Hi(Ln)|0,I=w(Rn(Tn(n)|0,Pe?s:h)),Zt=Wu(n,2,s)|0,Pr=Wu(n,0,h)|0;do if(Le(I)|0?0:!(Le(Pe?r:l)|0)){if(k=n+504|0,!(Le(w(T[k>>2]))|0)&&(!(ir(t[n+976>>2]|0,0)|0)||(t[n+500>>2]|0)==(t[2278]|0)))break;T[k>>2]=w(Ru(I,w(Rr(n,Ln,s))))}else K=7;while(0);do if((K|0)==7){if(ft=Pe^1,!(ft|Zt^1)){h=w(Rn(t[n+992>>2]|0,s)),T[n+504>>2]=w(Ru(h,w(Rr(n,2,s))));break}if(!(Pe|Pr^1)){h=w(Rn(t[n+996>>2]|0,h)),T[n+504>>2]=w(Ru(h,w(Rr(n,0,s))));break}T[Br>>2]=w(re),T[In>>2]=w(re),t[gn>>2]=0,t[_r>>2]=0,Ge=w(Xt(n,2,s)),Me=w(Xt(n,0,s)),Zt?(Te=w(Ge+w(Rn(t[n+992>>2]|0,s))),T[Br>>2]=Te,t[gn>>2]=1,Be=1):(Be=0,Te=w(re)),Pr?(I=w(Me+w(Rn(t[n+996>>2]|0,h))),T[In>>2]=I,t[_r>>2]=1,k=1):(k=0,I=w(re)),K=t[e+32>>2]|0,Pe&(K|0)==2?K=2:(Le(Te)|0?!(Le(r)|0):0)&&(T[Br>>2]=r,t[gn>>2]=2,Be=2,Te=r),(((K|0)==2&ft?0:Le(I)|0)?!(Le(l)|0):0)&&(T[In>>2]=l,t[_r>>2]=2,k=2,I=l),ye=w(T[n+396>>2]),Ze=Le(ye)|0;do if(Ze)K=Be;else{if((Be|0)==1&ft){T[In>>2]=w(w(Te-Ge)/ye),t[_r>>2]=1,k=1,K=1;break}Pe&(k|0)==1?(T[Br>>2]=w(ye*w(I-Me)),t[gn>>2]=1,k=1,K=1):K=Be}while(0);ls=Le(r)|0,Be=(eo(e,n)|0)!=4,(Pe|Zt|((u|0)!=1|ls)|(Be|(K|0)==1)?0:(T[Br>>2]=r,t[gn>>2]=1,!Ze))&&(T[In>>2]=w(w(r-Ge)/ye),t[_r>>2]=1,k=1),(Pr|ft|((D|0)!=1|(Le(l)|0))|(Be|(k|0)==1)?0:(T[In>>2]=l,t[_r>>2]=1,!Ze))&&(T[Br>>2]=w(ye*w(l-Me)),t[gn>>2]=1),Fn(n,2,s,s,gn,Br),Fn(n,0,h,s,_r,In),r=w(T[Br>>2]),l=w(T[In>>2]),Kt(n,r,l,S,t[gn>>2]|0,t[_r>>2]|0,s,h,0,3565,L)|0,h=w(T[n+908+(t[976+(Ln<<2)>>2]<<2)>>2]),T[n+504>>2]=w(Ru(h,w(Rr(n,Ln,s))))}while(0);t[n+500>>2]=t[2278],m=uu}function Kn(e,n,r,u,l){return e=e|0,n=n|0,r=w(r),u=w(u),l=w(l),u=w(Jt(e,n,r,u)),w(Ru(u,w(Rr(e,n,l))))}function eo(e,n){return e=e|0,n=n|0,n=n+20|0,n=t[((t[n>>2]|0)==0?e+16|0:n)>>2]|0,((n|0)==5?_n(t[e+4>>2]|0)|0:0)&&(n=1),n|0}function Eo(e,n){return e=e|0,n=n|0,(Hi(n)|0?(t[e+96>>2]|0)!=0:0)?n=4:n=t[1040+(n<<2)>>2]|0,e+60+(n<<3)|0}function Do(e,n){return e=e|0,n=n|0,(Hi(n)|0?(t[e+104>>2]|0)!=0:0)?n=5:n=t[1e3+(n<<2)>>2]|0,e+60+(n<<3)|0}function Fn(e,n,r,u,l,s){switch(e=e|0,n=n|0,r=w(r),u=w(u),l=l|0,s=s|0,r=w(Rn(e+380+(t[976+(n<<2)>>2]<<3)|0,r)),r=w(r+w(Xt(e,n,u))),t[l>>2]|0){case 2:case 1:{l=Le(r)|0,u=w(T[s>>2]),T[s>>2]=l|u>2]=2,T[s>>2]=r);break}default:}}function ae(e,n){return e=e|0,n=n|0,e=e+132|0,(Hi(n)|0?(t[(ht(e,4,948)|0)+4>>2]|0)!=0:0)?e=1:e=(t[(ht(e,t[1040+(n<<2)>>2]|0,948)|0)+4>>2]|0)!=0,e|0}function ie(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0;return e=e+132|0,(Hi(n)|0?(u=ht(e,4,948)|0,(t[u+4>>2]|0)!=0):0)?l=4:(u=ht(e,t[1040+(n<<2)>>2]|0,948)|0,t[u+4>>2]|0?l=4:r=w(0)),(l|0)==4&&(r=w(Rn(u,r))),w(r)}function Fe(e,n,r){e=e|0,n=n|0,r=w(r);var u=Tt;return u=w(T[e+908+(t[976+(n<<2)>>2]<<2)>>2]),u=w(u+w(zi(e,n,r))),w(u+w(Oo(e,n,r)))}function Oe(e){e=e|0;var n=0,r=0,u=0;e:do if(_n(t[e+4>>2]|0)|0)n=0;else if((t[e+16>>2]|0)!=5)if(r=Su(e)|0,!r)n=0;else for(n=0;;){if(u=Ti(e,n)|0,(t[u+24>>2]|0)==0?(t[u+20>>2]|0)==5:0){n=1;break e}if(n=n+1|0,n>>>0>=r>>>0){n=0;break}}else n=1;while(0);return n|0}function st(e,n){e=e|0,n=n|0;var r=Tt;return r=w(T[e+908+(t[976+(n<<2)>>2]<<2)>>2]),r>=w(0)&((Le(r)|0)^1)|0}function yt(e){e=e|0;var n=Tt,r=0,u=0,l=0,s=0,h=0,D=0,S=Tt;if(r=t[e+968>>2]|0,r)S=w(T[e+908>>2]),n=w(T[e+912>>2]),n=w(eS[r&0](e,S,n)),qu(e,(Le(n)|0)^1,3573);else{s=Su(e)|0;do if(s|0){for(r=0,l=0;;){if(u=Ti(e,l)|0,t[u+940>>2]|0){h=8;break}if((t[u+24>>2]|0)!=1)if(D=(eo(e,u)|0)==5,D){r=u;break}else r=(r|0)==0?u:r;if(l=l+1|0,l>>>0>=s>>>0){h=8;break}}if((h|0)==8&&!r)break;return n=w(yt(r)),w(n+w(T[r+404>>2]))}while(0);n=w(T[e+912>>2])}return w(n)}function Jt(e,n,r,u){e=e|0,n=n|0,r=w(r),u=w(u);var l=Tt,s=0;return _n(n)|0?(n=1,s=3):Hi(n)|0?(n=0,s=3):(u=w(re),l=w(re)),(s|0)==3&&(l=w(Rn(e+364+(n<<3)|0,u)),u=w(Rn(e+380+(n<<3)|0,u))),s=u=w(0)&((Le(u)|0)^1)),r=s?u:r,s=l>=w(0)&((Le(l)|0)^1)&r>2]|0,s)|0,Te=_f(Ze,s)|0,ye=Hi(Ze)|0,I=w(Xt(n,2,r)),K=w(Xt(n,0,r)),Wu(n,2,r)|0?D=w(I+w(Rn(t[n+992>>2]|0,r))):(ae(n,2)|0?Bt(n,2)|0:0)?(D=w(T[e+908>>2]),S=w(Mo(e,2)),S=w(D-w(S+w(v0(e,2)))),D=w(ie(n,2,r)),D=w(Kn(n,2,w(S-w(D+w(Fi(n,2,r)))),r,r))):D=w(re),Wu(n,0,l)|0?S=w(K+w(Rn(t[n+996>>2]|0,l))):(ae(n,0)|0?Bt(n,0)|0:0)?(S=w(T[e+912>>2]),ft=w(Mo(e,0)),ft=w(S-w(ft+w(v0(e,0)))),S=w(ie(n,0,l)),S=w(Kn(n,0,w(ft-w(S+w(Fi(n,0,l)))),l,r))):S=w(re),L=Le(D)|0,k=Le(S)|0;do if(L^k?(Be=w(T[n+396>>2]),!(Le(Be)|0)):0)if(L){D=w(I+w(w(S-K)*Be));break}else{ft=w(K+w(w(D-I)/Be)),S=k?ft:S;break}while(0);k=Le(D)|0,L=Le(S)|0,k|L&&(Me=(k^1)&1,u=r>w(0)&((u|0)!=0&k),D=ye?D:u?r:D,Kt(n,D,S,s,ye?Me:u?2:Me,k&(L^1)&1,D,S,0,3623,h)|0,D=w(T[n+908>>2]),D=w(D+w(Xt(n,2,r))),S=w(T[n+912>>2]),S=w(S+w(Xt(n,0,r)))),Kt(n,D,S,s,1,1,D,S,1,3635,h)|0,(Bt(n,Ze)|0?!(ae(n,Ze)|0):0)?(Me=t[976+(Ze<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(ft-w(T[n+908+(Me<<2)>>2])),ft=w(ft-w(v0(e,Ze))),ft=w(ft-w(Oo(n,Ze,r))),ft=w(ft-w(Fi(n,Ze,ye?r:l))),T[n+400+(t[1040+(Ze<<2)>>2]<<2)>>2]=ft):Ge=21;do if((Ge|0)==21){if(ae(n,Ze)|0?0:(t[e+8>>2]|0)==1){Me=t[976+(Ze<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(w(ft-w(T[n+908+(Me<<2)>>2]))*w(.5)),T[n+400+(t[1040+(Ze<<2)>>2]<<2)>>2]=ft;break}(ae(n,Ze)|0?0:(t[e+8>>2]|0)==2)&&(Me=t[976+(Ze<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(ft-w(T[n+908+(Me<<2)>>2])),T[n+400+(t[1040+(Ze<<2)>>2]<<2)>>2]=ft)}while(0);(Bt(n,Te)|0?!(ae(n,Te)|0):0)?(Me=t[976+(Te<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(ft-w(T[n+908+(Me<<2)>>2])),ft=w(ft-w(v0(e,Te))),ft=w(ft-w(Oo(n,Te,r))),ft=w(ft-w(Fi(n,Te,ye?l:r))),T[n+400+(t[1040+(Te<<2)>>2]<<2)>>2]=ft):Ge=30;do if((Ge|0)==30?!(ae(n,Te)|0):0){if((eo(e,n)|0)==2){Me=t[976+(Te<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(w(ft-w(T[n+908+(Me<<2)>>2]))*w(.5)),T[n+400+(t[1040+(Te<<2)>>2]<<2)>>2]=ft;break}Me=(eo(e,n)|0)==3,Me^(t[e+28>>2]|0)==2&&(Me=t[976+(Te<<2)>>2]|0,ft=w(T[e+908+(Me<<2)>>2]),ft=w(ft-w(T[n+908+(Me<<2)>>2])),T[n+400+(t[1040+(Te<<2)>>2]<<2)>>2]=ft)}while(0)}function Sn(e,n,r){e=e|0,n=n|0,r=r|0;var u=Tt,l=0;l=t[976+(r<<2)>>2]|0,u=w(T[n+908+(l<<2)>>2]),u=w(w(T[e+908+(l<<2)>>2])-u),u=w(u-w(T[n+400+(t[1040+(r<<2)>>2]<<2)>>2])),T[n+400+(t[1e3+(r<<2)>>2]<<2)>>2]=u}function _n(e){return e=e|0,(e|1|0)==1|0}function Tn(e){e=e|0;var n=Tt;switch(t[e+56>>2]|0){case 0:case 3:{n=w(T[e+40>>2]),n>w(0)&((Le(n)|0)^1)?e=c[(t[e+976>>2]|0)+2>>0]|0?1056:992:e=1056;break}default:e=e+52|0}return e|0}function ir(e,n){return e=e|0,n=n|0,(c[e+n>>0]|0)!=0|0}function Bt(e,n){return e=e|0,n=n|0,e=e+132|0,(Hi(n)|0?(t[(ht(e,5,948)|0)+4>>2]|0)!=0:0)?e=1:e=(t[(ht(e,t[1e3+(n<<2)>>2]|0,948)|0)+4>>2]|0)!=0,e|0}function Fi(e,n,r){e=e|0,n=n|0,r=w(r);var u=0,l=0;return e=e+132|0,(Hi(n)|0?(u=ht(e,5,948)|0,(t[u+4>>2]|0)!=0):0)?l=4:(u=ht(e,t[1e3+(n<<2)>>2]|0,948)|0,t[u+4>>2]|0?l=4:r=w(0)),(l|0)==4&&(r=w(Rn(u,r))),w(r)}function Ar(e,n,r){return e=e|0,n=n|0,r=w(r),ae(e,n)|0?r=w(ie(e,n,r)):r=w(-w(Fi(e,n,r))),w(r)}function mr(e){return e=w(e),T[q>>2]=e,t[q>>2]|0|0}function Y(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>1073741823)$n();else{l=pn(n<<2)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<2)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<2)}function ri(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>2)<<2)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function ii(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-4-n|0)>>>2)<<2)),e=t[e>>2]|0,e|0&&_t(e)}function Vr(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;if(h=e+4|0,D=t[h>>2]|0,l=D-u|0,s=l>>2,e=n+(s<<2)|0,e>>>0>>0){u=D;do t[u>>2]=t[e>>2],e=e+4|0,u=(t[h>>2]|0)+4|0,t[h>>2]=u;while(e>>>0>>0)}s|0&&ky(D+(0-s<<2)|0,n|0,l|0)|0}function at(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0;return D=n+4|0,S=t[D>>2]|0,l=t[e>>2]|0,h=r,s=h-l|0,u=S+(0-(s>>2)<<2)|0,t[D>>2]=u,(s|0)>0&&gr(u|0,l|0,s|0)|0,l=e+4|0,s=n+8|0,u=(t[l>>2]|0)-h|0,(u|0)>0&&(gr(t[s>>2]|0,r|0,u|0)|0,t[s>>2]=(t[s>>2]|0)+(u>>>2<<2)),h=t[e>>2]|0,t[e>>2]=t[D>>2],t[D>>2]=h,h=t[l>>2]|0,t[l>>2]=t[s>>2],t[s>>2]=h,h=e+8|0,r=n+12|0,e=t[h>>2]|0,t[h>>2]=t[r>>2],t[r>>2]=e,t[n>>2]=t[D>>2],S|0}function Di(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;if(h=t[n>>2]|0,s=t[r>>2]|0,(h|0)!=(s|0)){l=e+8|0,r=((s+-4-h|0)>>>2)+1|0,e=h,u=t[l>>2]|0;do t[u>>2]=t[e>>2],u=(t[l>>2]|0)+4|0,t[l>>2]=u,e=e+4|0;while((e|0)!=(s|0));t[n>>2]=h+(r<<2)}}function ru(){Se()}function wo(){var e=0;return e=pn(4)|0,Un(e),e|0}function Un(e){e=e|0,t[e>>2]=yo()|0}function to(e){e=e|0,e|0&&(i0(e),_t(e))}function i0(e){e=e|0,Zo(t[e>>2]|0)}function m0(e,n,r){e=e|0,n=n|0,r=r|0,Vu(t[e>>2]|0,n,r)}function no(e,n){e=e|0,n=w(n),Ju(t[e>>2]|0,n)}function j0(e,n){return e=e|0,n=n|0,ir(t[e>>2]|0,n)|0}function u0(){var e=0;return e=pn(8)|0,Ua(e,0),e|0}function Ua(e,n){e=e|0,n=n|0,n?n=Yn(t[n>>2]|0)|0:n=cr()|0,t[e>>2]=n,t[e+4>>2]=0,Ba(n,e)}function Ef(e){e=e|0;var n=0;return n=pn(8)|0,Ua(n,e),n|0}function cc(e){e=e|0,e|0&&(ws(e),_t(e))}function ws(e){e=e|0;var n=0;zu(t[e>>2]|0),n=e+4|0,e=t[n>>2]|0,t[n>>2]=0,e|0&&(ca(e),_t(e))}function ca(e){e=e|0,jo(e)}function jo(e){e=e|0,e=t[e>>2]|0,e|0&&qr(e|0)}function dc(e){return e=e|0,Us(e)|0}function ja(e){e=e|0;var n=0,r=0;r=e+4|0,n=t[r>>2]|0,t[r>>2]=0,n|0&&(ca(n),_t(n)),p0(t[e>>2]|0)}function D2(e,n){e=e|0,n=n|0,la(t[e>>2]|0,t[n>>2]|0)}function rd(e,n){e=e|0,n=n|0,Z(t[e>>2]|0,n)}function id(e,n,r){e=e|0,n=n|0,r=+r,dr(t[e>>2]|0,n,w(r))}function y0(e,n,r){e=e|0,n=n|0,r=+r,er(t[e>>2]|0,n,w(r))}function qc(e,n){e=e|0,n=n|0,z(t[e>>2]|0,n)}function Rl(e,n){e=e|0,n=n|0,$(t[e>>2]|0,n)}function ul(e,n){e=e|0,n=n|0,Ee(t[e>>2]|0,n)}function w2(e,n){e=e|0,n=n|0,go(t[e>>2]|0,n)}function Ws(e,n){e=e|0,n=n|0,Je(t[e>>2]|0,n)}function Al(e,n){e=e|0,n=n|0,ji(t[e>>2]|0,n)}function ud(e,n,r){e=e|0,n=n|0,r=+r,An(t[e>>2]|0,n,w(r))}function z0(e,n,r){e=e|0,n=n|0,r=+r,Lr(t[e>>2]|0,n,w(r))}function za(e,n){e=e|0,n=n|0,Nr(t[e>>2]|0,n)}function Ha(e,n){e=e|0,n=n|0,oe(t[e>>2]|0,n)}function qa(e,n){e=e|0,n=n|0,it(t[e>>2]|0,n)}function da(e,n){e=e|0,n=+n,Mt(t[e>>2]|0,w(n))}function Ss(e,n){e=e|0,n=+n,rn(t[e>>2]|0,w(n))}function Ts(e,n){e=e|0,n=+n,Ft(t[e>>2]|0,w(n))}function ns(e,n){e=e|0,n=+n,It(t[e>>2]|0,w(n))}function H0(e,n){e=e|0,n=+n,sn(t[e>>2]|0,w(n))}function Df(e,n){e=e|0,n=+n,fn(t[e>>2]|0,w(n))}function ol(e,n){e=e|0,n=+n,Jn(t[e>>2]|0,w(n))}function Gu(e){e=e|0,wr(t[e>>2]|0)}function Wa(e,n){e=e|0,n=+n,Lu(t[e>>2]|0,w(n))}function ro(e,n){e=e|0,n=+n,Co(t[e>>2]|0,w(n))}function zo(e){e=e|0,$o(t[e>>2]|0)}function wf(e,n){e=e|0,n=+n,_i(t[e>>2]|0,w(n))}function Wc(e,n){e=e|0,n=+n,P0(t[e>>2]|0,w(n))}function pc(e,n){e=e|0,n=+n,vf(t[e>>2]|0,w(n))}function Ol(e,n){e=e|0,n=+n,Tl(t[e>>2]|0,w(n))}function Cs(e,n){e=e|0,n=+n,I0(t[e>>2]|0,w(n))}function pa(e,n){e=e|0,n=+n,gs(t[e>>2]|0,w(n))}function od(e,n){e=e|0,n=+n,b0(t[e>>2]|0,w(n))}function ha(e,n){e=e|0,n=+n,B0(t[e>>2]|0,w(n))}function hc(e,n){e=e|0,n=+n,Qu(t[e>>2]|0,w(n))}function Vc(e,n,r){e=e|0,n=n|0,r=+r,Pt(t[e>>2]|0,n,w(r))}function qi(e,n,r){e=e|0,n=n|0,r=+r,ut(t[e>>2]|0,n,w(r))}function g(e,n,r){e=e|0,n=n|0,r=+r,Dt(t[e>>2]|0,n,w(r))}function y(e){return e=e|0,ke(t[e>>2]|0)|0}function R(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;u=m,m=m+16|0,l=u,Cr(l,t[n>>2]|0,r),F(e,l),m=u}function F(e,n){e=e|0,n=n|0,b(e,t[n+4>>2]|0,+w(T[n>>2]))}function b(e,n,r){e=e|0,n=n|0,r=+r,t[e>>2]=n,B[e+8>>3]=r}function J(e){return e=e|0,G(t[e>>2]|0)|0}function de(e){return e=e|0,Ce(t[e>>2]|0)|0}function gt(e){return e=e|0,Ae(t[e>>2]|0)|0}function xt(e){return e=e|0,js(t[e>>2]|0)|0}function Lt(e){return e=e|0,mt(t[e>>2]|0)|0}function xr(e){return e=e|0,U(t[e>>2]|0)|0}function io(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;u=m,m=m+16|0,l=u,_o(l,t[n>>2]|0,r),F(e,l),m=u}function du(e){return e=e|0,We(t[e>>2]|0)|0}function Ho(e){return e=e|0,Ct(t[e>>2]|0)|0}function Ml(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,Dn(u,t[n>>2]|0),F(e,u),m=r}function uo(e){return e=e|0,+ +w(hf(t[e>>2]|0))}function Ve(e){return e=e|0,+ +w(Bs(t[e>>2]|0))}function ze(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,fu(u,t[n>>2]|0),F(e,u),m=r}function lt(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,Nu(u,t[n>>2]|0),F(e,u),m=r}function $t(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,rl(u,t[n>>2]|0),F(e,u),m=r}function Wn(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,mf(u,t[n>>2]|0),F(e,u),m=r}function si(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,zs(u,t[n>>2]|0),F(e,u),m=r}function ur(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,_s(u,t[n>>2]|0),F(e,u),m=r}function ci(e){return e=e|0,+ +w(Tu(t[e>>2]|0))}function Qi(e,n){return e=e|0,n=n|0,+ +w(un(t[e>>2]|0,n))}function Gr(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;u=m,m=m+16|0,l=u,et(l,t[n>>2]|0,r),F(e,l),m=u}function Cu(e,n,r){e=e|0,n=n|0,r=r|0,ba(t[e>>2]|0,t[n>>2]|0,r)}function Va(e,n){e=e|0,n=n|0,ku(t[e>>2]|0,t[n>>2]|0)}function Ga(e){return e=e|0,Su(t[e>>2]|0)|0}function ld(e){return e=e|0,e=fi(t[e>>2]|0)|0,e?e=dc(e)|0:e=0,e|0}function S2(e,n){return e=e|0,n=n|0,e=Ti(t[e>>2]|0,n)|0,e?e=dc(e)|0:e=0,e|0}function T2(e,n){e=e|0,n=n|0;var r=0,u=0;u=pn(4)|0,Sf(u,n),r=e+4|0,n=t[r>>2]|0,t[r>>2]=u,n|0&&(ca(n),_t(n)),oa(t[e>>2]|0,1)}function Sf(e,n){e=e|0,n=n|0,sl(e,n)}function sd(e,n,r,u,l,s){e=e|0,n=n|0,r=w(r),u=u|0,l=w(l),s=s|0;var h=0,D=0;h=m,m=m+16|0,D=h,hh(D,Us(n)|0,+r,u,+l,s),T[e>>2]=w(+B[D>>3]),T[e+4>>2]=w(+B[D+8>>3]),m=h}function hh(e,n,r,u,l,s){e=e|0,n=n|0,r=+r,u=u|0,l=+l,s=s|0;var h=0,D=0,S=0,L=0,k=0;h=m,m=m+32|0,k=h+8|0,L=h+20|0,S=h,D=h+16|0,B[k>>3]=r,t[L>>2]=u,B[S>>3]=l,t[D>>2]=s,Gc(e,t[n+4>>2]|0,k,L,S,D),m=h}function Gc(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0;h=m,m=m+16|0,D=h,ka(D),n=g0(n)|0,vh(e,n,+B[r>>3],t[u>>2]|0,+B[l>>3],t[s>>2]|0),La(D),m=h}function g0(e){return e=e|0,t[e>>2]|0}function vh(e,n,r,u,l,s){e=e|0,n=n|0,r=+r,u=u|0,l=+l,s=s|0;var h=0;h=_0(mh()|0)|0,r=+kl(r),u=ad(u)|0,l=+kl(l),fd(e,Qr(0,h|0,n|0,+r,u|0,+l,ad(s)|0)|0)}function mh(){var e=0;return c[7608]|0||(Kc(9120),e=7608,t[e>>2]=1,t[e+4>>2]=0),9120}function _0(e){return e=e|0,t[e+8>>2]|0}function kl(e){return e=+e,+ +Ya(e)}function ad(e){return e=e|0,dd(e)|0}function fd(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;l=m,m=m+32|0,r=l,u=n,u&1?(C2(r,0),eu(u|0,r|0)|0,Yc(e,r),Ir(r)):(t[e>>2]=t[n>>2],t[e+4>>2]=t[n+4>>2],t[e+8>>2]=t[n+8>>2],t[e+12>>2]=t[n+12>>2]),m=l}function C2(e,n){e=e|0,n=n|0,cd(e,n),t[e+8>>2]=0,c[e+24>>0]=0}function Yc(e,n){e=e|0,n=n|0,n=n+8|0,t[e>>2]=t[n>>2],t[e+4>>2]=t[n+4>>2],t[e+8>>2]=t[n+8>>2],t[e+12>>2]=t[n+12>>2]}function Ir(e){e=e|0,c[e+24>>0]=0}function cd(e,n){e=e|0,n=n|0,t[e>>2]=n}function dd(e){return e=e|0,e|0}function Ya(e){return e=+e,+e}function Kc(e){e=e|0,ll(e,x2()|0,4)}function x2(){return 1064}function ll(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r,t[e+8>>2]=bt(n|0,r+1|0)|0}function sl(e,n){e=e|0,n=n|0,n=t[n>>2]|0,t[e>>2]=n,Ri(n|0)}function yh(e){e=e|0;var n=0,r=0;r=e+4|0,n=t[r>>2]|0,t[r>>2]=0,n|0&&(ca(n),_t(n)),oa(t[e>>2]|0,0)}function Tf(e){e=e|0,$r(t[e>>2]|0)}function Xc(e){return e=e|0,$l(t[e>>2]|0)|0}function R2(e,n,r,u){e=e|0,n=+n,r=+r,u=u|0,ti(t[e>>2]|0,w(n),w(r),u)}function gh(e){return e=e|0,+ +w(Ei(t[e>>2]|0))}function al(e){return e=e|0,+ +w(e0(t[e>>2]|0))}function va(e){return e=e|0,+ +w(xo(t[e>>2]|0))}function A2(e){return e=e|0,+ +w(U0(t[e>>2]|0))}function O2(e){return e=e|0,+ +w(sa(t[e>>2]|0))}function vc(e){return e=e|0,+ +w(es(t[e>>2]|0))}function _h(e,n){e=e|0,n=n|0,B[e>>3]=+w(Ei(t[n>>2]|0)),B[e+8>>3]=+w(e0(t[n>>2]|0)),B[e+16>>3]=+w(xo(t[n>>2]|0)),B[e+24>>3]=+w(U0(t[n>>2]|0)),B[e+32>>3]=+w(sa(t[n>>2]|0)),B[e+40>>3]=+w(es(t[n>>2]|0))}function M2(e,n){return e=e|0,n=n|0,+ +w(tu(t[e>>2]|0,n))}function pd(e,n){return e=e|0,n=n|0,+ +w(ei(t[e>>2]|0,n))}function Qc(e,n){return e=e|0,n=n|0,+ +w(h0(t[e>>2]|0,n))}function Jc(){return Ia()|0}function Vs(){k2(),ma(),Zc(),mc(),yc(),hd()}function k2(){IO(11713,4938,1)}function ma(){tO(10448)}function Zc(){I7(10408)}function mc(){u7(10324)}function yc(){EE(10096)}function hd(){Eh(9132)}function Eh(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0,ft=0,Me=0,Pe=0,Zt=0,Br=0,In=0,gn=0,_r=0,Pr=0,Ln=0,uu=0,ls=0,ss=0,as=0,ta=0,r2=0,i2=0,of=0,u2=0,Pc=0,Ic=0,o2=0,l2=0,s2=0,vi=0,lf=0,a2=0,Kf=0,f2=0,c2=0,bc=0,Bc=0,Xf=0,ql=0,Fa=0,Ns=0,sf=0,b1=0,B1=0,Uc=0,U1=0,j1=0,Wl=0,El=0,af=0,vu=0,z1=0,fs=0,Qf=0,cs=0,Jf=0,H1=0,q1=0,Zf=0,Vl=0,ff=0,W1=0,V1=0,G1=0,Sr=0,Bu=0,Dl=0,ds=0,Gl=0,Or=0,Bn=0,cf=0;n=m,m=m+672|0,r=n+656|0,cf=n+648|0,Bn=n+640|0,Or=n+632|0,Gl=n+624|0,ds=n+616|0,Dl=n+608|0,Bu=n+600|0,Sr=n+592|0,G1=n+584|0,V1=n+576|0,W1=n+568|0,ff=n+560|0,Vl=n+552|0,Zf=n+544|0,q1=n+536|0,H1=n+528|0,Jf=n+520|0,cs=n+512|0,Qf=n+504|0,fs=n+496|0,z1=n+488|0,vu=n+480|0,af=n+472|0,El=n+464|0,Wl=n+456|0,j1=n+448|0,U1=n+440|0,Uc=n+432|0,B1=n+424|0,b1=n+416|0,sf=n+408|0,Ns=n+400|0,Fa=n+392|0,ql=n+384|0,Xf=n+376|0,Bc=n+368|0,bc=n+360|0,c2=n+352|0,f2=n+344|0,Kf=n+336|0,a2=n+328|0,lf=n+320|0,vi=n+312|0,s2=n+304|0,l2=n+296|0,o2=n+288|0,Ic=n+280|0,Pc=n+272|0,u2=n+264|0,of=n+256|0,i2=n+248|0,r2=n+240|0,ta=n+232|0,as=n+224|0,ss=n+216|0,ls=n+208|0,uu=n+200|0,Ln=n+192|0,Pr=n+184|0,_r=n+176|0,gn=n+168|0,In=n+160|0,Br=n+152|0,Zt=n+144|0,Pe=n+136|0,Me=n+128|0,ft=n+120|0,Ge=n+112|0,Ze=n+104|0,ye=n+96|0,Te=n+88|0,Be=n+80|0,K=n+72|0,I=n+64|0,k=n+56|0,L=n+48|0,S=n+40|0,D=n+32|0,h=n+24|0,s=n+16|0,l=n+8|0,u=n,Cf(e,3646),$c(e,3651,2)|0,Dh(e,3665,2)|0,am(e,3682,18)|0,t[cf>>2]=19,t[cf+4>>2]=0,t[r>>2]=t[cf>>2],t[r+4>>2]=t[cf+4>>2],Gs(e,3690,r)|0,t[Bn>>2]=1,t[Bn+4>>2]=0,t[r>>2]=t[Bn>>2],t[r+4>>2]=t[Bn+4>>2],ya(e,3696,r)|0,t[Or>>2]=2,t[Or+4>>2]=0,t[r>>2]=t[Or>>2],t[r+4>>2]=t[Or+4>>2],iu(e,3706,r)|0,t[Gl>>2]=1,t[Gl+4>>2]=0,t[r>>2]=t[Gl>>2],t[r+4>>2]=t[Gl+4>>2],ko(e,3722,r)|0,t[ds>>2]=2,t[ds+4>>2]=0,t[r>>2]=t[ds>>2],t[r+4>>2]=t[ds+4>>2],ko(e,3734,r)|0,t[Dl>>2]=3,t[Dl+4>>2]=0,t[r>>2]=t[Dl>>2],t[r+4>>2]=t[Dl+4>>2],iu(e,3753,r)|0,t[Bu>>2]=4,t[Bu+4>>2]=0,t[r>>2]=t[Bu>>2],t[r+4>>2]=t[Bu+4>>2],iu(e,3769,r)|0,t[Sr>>2]=5,t[Sr+4>>2]=0,t[r>>2]=t[Sr>>2],t[r+4>>2]=t[Sr+4>>2],iu(e,3783,r)|0,t[G1>>2]=6,t[G1+4>>2]=0,t[r>>2]=t[G1>>2],t[r+4>>2]=t[G1+4>>2],iu(e,3796,r)|0,t[V1>>2]=7,t[V1+4>>2]=0,t[r>>2]=t[V1>>2],t[r+4>>2]=t[V1+4>>2],iu(e,3813,r)|0,t[W1>>2]=8,t[W1+4>>2]=0,t[r>>2]=t[W1>>2],t[r+4>>2]=t[W1+4>>2],iu(e,3825,r)|0,t[ff>>2]=3,t[ff+4>>2]=0,t[r>>2]=t[ff>>2],t[r+4>>2]=t[ff+4>>2],ko(e,3843,r)|0,t[Vl>>2]=4,t[Vl+4>>2]=0,t[r>>2]=t[Vl>>2],t[r+4>>2]=t[Vl+4>>2],ko(e,3853,r)|0,t[Zf>>2]=9,t[Zf+4>>2]=0,t[r>>2]=t[Zf>>2],t[r+4>>2]=t[Zf+4>>2],iu(e,3870,r)|0,t[q1>>2]=10,t[q1+4>>2]=0,t[r>>2]=t[q1>>2],t[r+4>>2]=t[q1+4>>2],iu(e,3884,r)|0,t[H1>>2]=11,t[H1+4>>2]=0,t[r>>2]=t[H1>>2],t[r+4>>2]=t[H1+4>>2],iu(e,3896,r)|0,t[Jf>>2]=1,t[Jf+4>>2]=0,t[r>>2]=t[Jf>>2],t[r+4>>2]=t[Jf+4>>2],oo(e,3907,r)|0,t[cs>>2]=2,t[cs+4>>2]=0,t[r>>2]=t[cs>>2],t[r+4>>2]=t[cs+4>>2],oo(e,3915,r)|0,t[Qf>>2]=3,t[Qf+4>>2]=0,t[r>>2]=t[Qf>>2],t[r+4>>2]=t[Qf+4>>2],oo(e,3928,r)|0,t[fs>>2]=4,t[fs+4>>2]=0,t[r>>2]=t[fs>>2],t[r+4>>2]=t[fs+4>>2],oo(e,3948,r)|0,t[z1>>2]=5,t[z1+4>>2]=0,t[r>>2]=t[z1>>2],t[r+4>>2]=t[z1+4>>2],oo(e,3960,r)|0,t[vu>>2]=6,t[vu+4>>2]=0,t[r>>2]=t[vu>>2],t[r+4>>2]=t[vu+4>>2],oo(e,3974,r)|0,t[af>>2]=7,t[af+4>>2]=0,t[r>>2]=t[af>>2],t[r+4>>2]=t[af+4>>2],oo(e,3983,r)|0,t[El>>2]=20,t[El+4>>2]=0,t[r>>2]=t[El>>2],t[r+4>>2]=t[El+4>>2],Gs(e,3999,r)|0,t[Wl>>2]=8,t[Wl+4>>2]=0,t[r>>2]=t[Wl>>2],t[r+4>>2]=t[Wl+4>>2],oo(e,4012,r)|0,t[j1>>2]=9,t[j1+4>>2]=0,t[r>>2]=t[j1>>2],t[r+4>>2]=t[j1+4>>2],oo(e,4022,r)|0,t[U1>>2]=21,t[U1+4>>2]=0,t[r>>2]=t[U1>>2],t[r+4>>2]=t[U1+4>>2],Gs(e,4039,r)|0,t[Uc>>2]=10,t[Uc+4>>2]=0,t[r>>2]=t[Uc>>2],t[r+4>>2]=t[Uc+4>>2],oo(e,4053,r)|0,t[B1>>2]=11,t[B1+4>>2]=0,t[r>>2]=t[B1>>2],t[r+4>>2]=t[B1+4>>2],oo(e,4065,r)|0,t[b1>>2]=12,t[b1+4>>2]=0,t[r>>2]=t[b1>>2],t[r+4>>2]=t[b1+4>>2],oo(e,4084,r)|0,t[sf>>2]=13,t[sf+4>>2]=0,t[r>>2]=t[sf>>2],t[r+4>>2]=t[sf+4>>2],oo(e,4097,r)|0,t[Ns>>2]=14,t[Ns+4>>2]=0,t[r>>2]=t[Ns>>2],t[r+4>>2]=t[Ns+4>>2],oo(e,4117,r)|0,t[Fa>>2]=15,t[Fa+4>>2]=0,t[r>>2]=t[Fa>>2],t[r+4>>2]=t[Fa+4>>2],oo(e,4129,r)|0,t[ql>>2]=16,t[ql+4>>2]=0,t[r>>2]=t[ql>>2],t[r+4>>2]=t[ql+4>>2],oo(e,4148,r)|0,t[Xf>>2]=17,t[Xf+4>>2]=0,t[r>>2]=t[Xf>>2],t[r+4>>2]=t[Xf+4>>2],oo(e,4161,r)|0,t[Bc>>2]=18,t[Bc+4>>2]=0,t[r>>2]=t[Bc>>2],t[r+4>>2]=t[Bc+4>>2],oo(e,4181,r)|0,t[bc>>2]=5,t[bc+4>>2]=0,t[r>>2]=t[bc>>2],t[r+4>>2]=t[bc+4>>2],ko(e,4196,r)|0,t[c2>>2]=6,t[c2+4>>2]=0,t[r>>2]=t[c2>>2],t[r+4>>2]=t[c2+4>>2],ko(e,4206,r)|0,t[f2>>2]=7,t[f2+4>>2]=0,t[r>>2]=t[f2>>2],t[r+4>>2]=t[f2+4>>2],ko(e,4217,r)|0,t[Kf>>2]=3,t[Kf+4>>2]=0,t[r>>2]=t[Kf>>2],t[r+4>>2]=t[Kf+4>>2],rs(e,4235,r)|0,t[a2>>2]=1,t[a2+4>>2]=0,t[r>>2]=t[a2>>2],t[r+4>>2]=t[a2+4>>2],Ka(e,4251,r)|0,t[lf>>2]=4,t[lf+4>>2]=0,t[r>>2]=t[lf>>2],t[r+4>>2]=t[lf+4>>2],rs(e,4263,r)|0,t[vi>>2]=5,t[vi+4>>2]=0,t[r>>2]=t[vi>>2],t[r+4>>2]=t[vi+4>>2],rs(e,4279,r)|0,t[s2>>2]=6,t[s2+4>>2]=0,t[r>>2]=t[s2>>2],t[r+4>>2]=t[s2+4>>2],rs(e,4293,r)|0,t[l2>>2]=7,t[l2+4>>2]=0,t[r>>2]=t[l2>>2],t[r+4>>2]=t[l2+4>>2],rs(e,4306,r)|0,t[o2>>2]=8,t[o2+4>>2]=0,t[r>>2]=t[o2>>2],t[r+4>>2]=t[o2+4>>2],rs(e,4323,r)|0,t[Ic>>2]=9,t[Ic+4>>2]=0,t[r>>2]=t[Ic>>2],t[r+4>>2]=t[Ic+4>>2],rs(e,4335,r)|0,t[Pc>>2]=2,t[Pc+4>>2]=0,t[r>>2]=t[Pc>>2],t[r+4>>2]=t[Pc+4>>2],Ka(e,4353,r)|0,t[u2>>2]=12,t[u2+4>>2]=0,t[r>>2]=t[u2>>2],t[r+4>>2]=t[u2+4>>2],o0(e,4363,r)|0,t[of>>2]=1,t[of+4>>2]=0,t[r>>2]=t[of>>2],t[r+4>>2]=t[of+4>>2],fl(e,4376,r)|0,t[i2>>2]=2,t[i2+4>>2]=0,t[r>>2]=t[i2>>2],t[r+4>>2]=t[i2+4>>2],fl(e,4388,r)|0,t[r2>>2]=13,t[r2+4>>2]=0,t[r>>2]=t[r2>>2],t[r+4>>2]=t[r2+4>>2],o0(e,4402,r)|0,t[ta>>2]=14,t[ta+4>>2]=0,t[r>>2]=t[ta>>2],t[r+4>>2]=t[ta+4>>2],o0(e,4411,r)|0,t[as>>2]=15,t[as+4>>2]=0,t[r>>2]=t[as>>2],t[r+4>>2]=t[as+4>>2],o0(e,4421,r)|0,t[ss>>2]=16,t[ss+4>>2]=0,t[r>>2]=t[ss>>2],t[r+4>>2]=t[ss+4>>2],o0(e,4433,r)|0,t[ls>>2]=17,t[ls+4>>2]=0,t[r>>2]=t[ls>>2],t[r+4>>2]=t[ls+4>>2],o0(e,4446,r)|0,t[uu>>2]=18,t[uu+4>>2]=0,t[r>>2]=t[uu>>2],t[r+4>>2]=t[uu+4>>2],o0(e,4458,r)|0,t[Ln>>2]=3,t[Ln+4>>2]=0,t[r>>2]=t[Ln>>2],t[r+4>>2]=t[Ln+4>>2],fl(e,4471,r)|0,t[Pr>>2]=1,t[Pr+4>>2]=0,t[r>>2]=t[Pr>>2],t[r+4>>2]=t[Pr+4>>2],gc(e,4486,r)|0,t[_r>>2]=10,t[_r+4>>2]=0,t[r>>2]=t[_r>>2],t[r+4>>2]=t[_r+4>>2],rs(e,4496,r)|0,t[gn>>2]=11,t[gn+4>>2]=0,t[r>>2]=t[gn>>2],t[r+4>>2]=t[gn+4>>2],rs(e,4508,r)|0,t[In>>2]=3,t[In+4>>2]=0,t[r>>2]=t[In>>2],t[r+4>>2]=t[In+4>>2],Ka(e,4519,r)|0,t[Br>>2]=4,t[Br+4>>2]=0,t[r>>2]=t[Br>>2],t[r+4>>2]=t[Br+4>>2],L2(e,4530,r)|0,t[Zt>>2]=19,t[Zt+4>>2]=0,t[r>>2]=t[Zt>>2],t[r+4>>2]=t[Zt+4>>2],wh(e,4542,r)|0,t[Pe>>2]=12,t[Pe+4>>2]=0,t[r>>2]=t[Pe>>2],t[r+4>>2]=t[Pe+4>>2],xf(e,4554,r)|0,t[Me>>2]=13,t[Me+4>>2]=0,t[r>>2]=t[Me>>2],t[r+4>>2]=t[Me+4>>2],Rf(e,4568,r)|0,t[ft>>2]=2,t[ft+4>>2]=0,t[r>>2]=t[ft>>2],t[r+4>>2]=t[ft+4>>2],e1(e,4578,r)|0,t[Ge>>2]=20,t[Ge+4>>2]=0,t[r>>2]=t[Ge>>2],t[r+4>>2]=t[Ge+4>>2],Ll(e,4587,r)|0,t[Ze>>2]=22,t[Ze+4>>2]=0,t[r>>2]=t[Ze>>2],t[r+4>>2]=t[Ze+4>>2],Gs(e,4602,r)|0,t[ye>>2]=23,t[ye+4>>2]=0,t[r>>2]=t[ye>>2],t[r+4>>2]=t[ye+4>>2],Gs(e,4619,r)|0,t[Te>>2]=14,t[Te+4>>2]=0,t[r>>2]=t[Te>>2],t[r+4>>2]=t[Te+4>>2],t1(e,4629,r)|0,t[Be>>2]=1,t[Be+4>>2]=0,t[r>>2]=t[Be>>2],t[r+4>>2]=t[Be+4>>2],ga(e,4637,r)|0,t[K>>2]=4,t[K+4>>2]=0,t[r>>2]=t[K>>2],t[r+4>>2]=t[K+4>>2],fl(e,4653,r)|0,t[I>>2]=5,t[I+4>>2]=0,t[r>>2]=t[I>>2],t[r+4>>2]=t[I+4>>2],fl(e,4669,r)|0,t[k>>2]=6,t[k+4>>2]=0,t[r>>2]=t[k>>2],t[r+4>>2]=t[k+4>>2],fl(e,4686,r)|0,t[L>>2]=7,t[L+4>>2]=0,t[r>>2]=t[L>>2],t[r+4>>2]=t[L+4>>2],fl(e,4701,r)|0,t[S>>2]=8,t[S+4>>2]=0,t[r>>2]=t[S>>2],t[r+4>>2]=t[S+4>>2],fl(e,4719,r)|0,t[D>>2]=9,t[D+4>>2]=0,t[r>>2]=t[D>>2],t[r+4>>2]=t[D+4>>2],fl(e,4736,r)|0,t[h>>2]=21,t[h+4>>2]=0,t[r>>2]=t[h>>2],t[r+4>>2]=t[h+4>>2],vd(e,4754,r)|0,t[s>>2]=2,t[s+4>>2]=0,t[r>>2]=t[s>>2],t[r+4>>2]=t[s+4>>2],gc(e,4772,r)|0,t[l>>2]=3,t[l+4>>2]=0,t[r>>2]=t[l>>2],t[r+4>>2]=t[l+4>>2],gc(e,4790,r)|0,t[u>>2]=4,t[u+4>>2]=0,t[r>>2]=t[u>>2],t[r+4>>2]=t[u+4>>2],gc(e,4808,r)|0,m=n}function Cf(e,n){e=e|0,n=n|0;var r=0;r=uf()|0,t[e>>2]=r,V0(r,n),e2(t[e>>2]|0)}function $c(e,n,r){return e=e|0,n=n|0,r=r|0,Ot(e,Fr(n)|0,r,0),e|0}function Dh(e,n,r){return e=e|0,n=n|0,r=r|0,d(e,Fr(n)|0,r,0),e|0}function am(e,n,r){return e=e|0,n=n|0,r=r|0,hE(e,Fr(n)|0,r,0),e|0}function Gs(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],oE(e,n,l),m=u,e|0}function ya(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],zl(e,n,l),m=u,e|0}function iu(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],p(e,n,l),m=u,e|0}function ko(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Rv(e,n,l),m=u,e|0}function oo(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],ny(e,n,l),m=u,e|0}function rs(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Kd(e,n,l),m=u,e|0}function Ka(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Yd(e,n,l),m=u,e|0}function o0(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Lo(e,n,l),m=u,e|0}function fl(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Sp(e,n,l),m=u,e|0}function gc(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],bm(e,n,l),m=u,e|0}function L2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],lo(e,n,l),m=u,e|0}function wh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Md(e,n,l),m=u,e|0}function xf(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Am(e,n,l),m=u,e|0}function Rf(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],tp(e,n,l),m=u,e|0}function e1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],y1(e,n,l),m=u,e|0}function Ll(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],$a(e,n,l),m=u,e|0}function t1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],j2(e,n,l),m=u,e|0}function ga(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],P2(e,n,l),m=u,e|0}function vd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],md(e,n,l),m=u,e|0}function md(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Ea(e,r,l,1),m=u}function Fr(e){return e=e|0,e|0}function Ea(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=N2()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=n1(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,yd(s,u)|0,u),m=l}function N2(){var e=0,n=0;if(c[7616]|0||(cl(9136),Vt(24,9136,ve|0)|0,n=7616,t[n>>2]=1,t[n+4>>2]=0),!(sr(9136)|0)){e=9136,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));cl(9136)}return 9136}function n1(e){return e=e|0,0}function yd(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=N2()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Af(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Of(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function wi(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0;h=m,m=m+32|0,K=h+24|0,I=h+20|0,S=h+16|0,k=h+12|0,L=h+8|0,D=h+4|0,Be=h,t[I>>2]=n,t[S>>2]=r,t[k>>2]=u,t[L>>2]=l,t[D>>2]=s,s=e+28|0,t[Be>>2]=t[s>>2],t[K>>2]=t[Be>>2],F2(e+24|0,K,I,k,L,S,D)|0,t[s>>2]=t[t[s>>2]>>2],m=h}function F2(e,n,r,u,l,s,h){return e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,h=h|0,e=fm(n)|0,n=pn(24)|0,gd(n+4|0,t[r>>2]|0,t[u>>2]|0,t[l>>2]|0,t[s>>2]|0,t[h>>2]|0),t[n>>2]=t[e>>2],t[e>>2]=n,n|0}function fm(e){return e=e|0,t[e>>2]|0}function gd(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,t[e>>2]=n,t[e+4>>2]=r,t[e+8>>2]=u,t[e+12>>2]=l,t[e+16>>2]=s}function hn(e,n){return e=e|0,n=n|0,n|e|0}function Af(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Of(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=cm(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Mf(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Af(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Sh(e,D),dm(D),m=L;return}}function cm(e){return e=e|0,357913941}function Mf(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Sh(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function dm(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function cl(e){e=e|0,q0(e)}function r1(e){e=e|0,qn(e+24|0)}function sr(e){return e=e|0,t[e>>2]|0}function qn(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function q0(e){e=e|0;var n=0;n=yr()|0,jn(e,2,3,n,Vn()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function yr(){return 9228}function Vn(){return 1140}function dl(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=E0(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=_c(n,u)|0,m=r,n|0}function jn(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,t[e>>2]=n,t[e+4>>2]=r,t[e+8>>2]=u,t[e+12>>2]=l,t[e+16>>2]=s}function E0(e){return e=e|0,(t[(N2()|0)+24>>2]|0)+(e*12|0)|0}function _c(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;return l=m,m=m+48|0,u=l,r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),I1[r&31](u,e),u=l0(u)|0,m=l,u|0}function l0(e){e=e|0;var n=0,r=0,u=0,l=0;return l=m,m=m+32|0,n=l+12|0,r=l,u=Iu(Xa()|0)|0,u?(is(n,u),kf(r,n),Ec(e,r),e=xs(n)|0):e=Dc(e)|0,m=l,e|0}function Xa(){var e=0;return c[7632]|0||(Nf(9184),Vt(25,9184,ve|0)|0,e=7632,t[e>>2]=1,t[e+4>>2]=0),9184}function Iu(e){return e=e|0,t[e+36>>2]|0}function is(e,n){e=e|0,n=n|0,t[e>>2]=n,t[e+4>>2]=e,t[e+8>>2]=0}function kf(e,n){e=e|0,n=n|0,t[e>>2]=t[n>>2],t[e+4>>2]=t[n+4>>2],t[e+8>>2]=0}function Ec(e,n){e=e|0,n=n|0,s0(n,e,e+8|0,e+16|0,e+24|0,e+32|0,e+40|0)|0}function xs(e){return e=e|0,t[(t[e+4>>2]|0)+8>>2]|0}function Dc(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0;S=m,m=m+16|0,r=S+4|0,u=S,l=Ma(8)|0,s=l,h=pn(48)|0,D=h,n=D+48|0;do t[D>>2]=t[e>>2],D=D+4|0,e=e+4|0;while((D|0)<(n|0));return n=s+4|0,t[n>>2]=h,D=pn(8)|0,h=t[n>>2]|0,t[u>>2]=0,t[r>>2]=t[u>>2],Th(D,h,r),t[l>>2]=D,m=S,s|0}function Th(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,r=pn(16)|0,t[r+4>>2]=0,t[r+8>>2]=0,t[r>>2]=1092,t[r+12>>2]=n,t[e+4>>2]=r}function cn(e){e=e|0,Uv(e),_t(e)}function us(e){e=e|0,e=t[e+12>>2]|0,e|0&&_t(e)}function D0(e){e=e|0,_t(e)}function s0(e,n,r,u,l,s,h){return e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,h=h|0,s=Ji(t[e>>2]|0,n,r,u,l,s,h)|0,h=e+4|0,t[(t[h>>2]|0)+8>>2]=s,t[(t[h>>2]|0)+8>>2]|0}function Ji(e,n,r,u,l,s,h){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,h=h|0;var D=0,S=0;return D=m,m=m+16|0,S=D,ka(S),e=g0(e)|0,h=Yr(e,+B[n>>3],+B[r>>3],+B[u>>3],+B[l>>3],+B[s>>3],+B[h>>3])|0,La(S),m=D,h|0}function Yr(e,n,r,u,l,s,h){e=e|0,n=+n,r=+r,u=+u,l=+l,s=+s,h=+h;var D=0;return D=_0(Lf()|0)|0,n=+kl(n),r=+kl(r),u=+kl(u),l=+kl(l),s=+kl(s),ho(0,D|0,e|0,+n,+r,+u,+l,+s,+ +kl(h))|0}function Lf(){var e=0;return c[7624]|0||(pm(9172),e=7624,t[e>>2]=1,t[e+4>>2]=0),9172}function pm(e){e=e|0,ll(e,Nl()|0,6)}function Nl(){return 1112}function Nf(e){e=e|0,Qa(e)}function Ff(e){e=e|0,_d(e+24|0),Ed(e+16|0)}function _d(e){e=e|0,i1(e)}function Ed(e){e=e|0,wc(e)}function wc(e){e=e|0;var n=0,r=0;if(n=t[e>>2]|0,n|0)do r=n,n=t[n>>2]|0,_t(r);while((n|0)!=0);t[e>>2]=0}function i1(e){e=e|0;var n=0,r=0;if(n=t[e>>2]|0,n|0)do r=n,n=t[n>>2]|0,_t(r);while((n|0)!=0);t[e>>2]=0}function Qa(e){e=e|0;var n=0;t[e+16>>2]=0,t[e+20>>2]=0,n=e+24|0,t[n>>2]=0,t[e+28>>2]=n,t[e+36>>2]=0,c[e+40>>0]=0,c[e+41>>0]=0}function P2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Dd(e,r,l,0),m=u}function Dd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=u1()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=Pf(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,o1(s,u)|0,u),m=l}function u1(){var e=0,n=0;if(c[7640]|0||(Fl(9232),Vt(26,9232,ve|0)|0,n=7640,t[n>>2]=1,t[n+4>>2]=0),!(sr(9232)|0)){e=9232,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Fl(9232)}return 9232}function Pf(e){return e=e|0,0}function o1(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=u1()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Ja(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(l1(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Ja(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function l1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=I2(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,wd(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Ja(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Sc(e,D),s1(D),m=L;return}}function I2(e){return e=e|0,357913941}function wd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Sc(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function s1(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Fl(e){e=e|0,b2(e)}function Da(e){e=e|0,Ch(e+24|0)}function Ch(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function b2(e){e=e|0;var n=0;n=yr()|0,jn(e,2,1,n,B2()|0,3),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function B2(){return 1144}function xh(e,n,r,u,l){e=e|0,n=n|0,r=+r,u=+u,l=l|0;var s=0,h=0,D=0,S=0;s=m,m=m+16|0,h=s+8|0,D=s,S=Sd(e)|0,e=t[S+4>>2]|0,t[D>>2]=t[S>>2],t[D+4>>2]=e,t[h>>2]=t[D>>2],t[h+4>>2]=t[D+4>>2],Rh(n,h,r,u,l),m=s}function Sd(e){return e=e|0,(t[(u1()|0)+24>>2]|0)+(e*12|0)|0}function Rh(e,n,r,u,l){e=e|0,n=n|0,r=+r,u=+u,l=l|0;var s=0,h=0,D=0,S=0,L=0;L=m,m=m+16|0,h=L+2|0,D=L+1|0,S=L,s=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(s=t[(t[e>>2]|0)+s>>2]|0),Pl(h,r),r=+os(h,r),Pl(D,u),u=+os(D,u),Rs(S,l),S=Ys(S,l)|0,tS[s&1](e,r,u,S),m=L}function Pl(e,n){e=e|0,n=+n}function os(e,n){return e=e|0,n=+n,+ +Ah(n)}function Rs(e,n){e=e|0,n=n|0}function Ys(e,n){return e=e|0,n=n|0,U2(n)|0}function U2(e){return e=e|0,e|0}function Ah(e){return e=+e,+e}function j2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],z2(e,r,l,1),m=u}function z2(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=a1()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=f1(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Oh(s,u)|0,u),m=l}function a1(){var e=0,n=0;if(c[7648]|0||(c1(9268),Vt(27,9268,ve|0)|0,n=7648,t[n>>2]=1,t[n+4>>2]=0),!(sr(9268)|0)){e=9268,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));c1(9268)}return 9268}function f1(e){return e=e|0,0}function Oh(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=a1()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],H2(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(q2(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function H2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function q2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=As(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Za(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],H2(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Mh(e,D),pu(D),m=L;return}}function As(e){return e=e|0,357913941}function Za(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Mh(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function pu(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function c1(e){e=e|0,Il(e)}function kh(e){e=e|0,d1(e+24|0)}function d1(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function Il(e){e=e|0;var n=0;n=yr()|0,jn(e,2,4,n,Lh()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Lh(){return 1160}function W2(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=Nh(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=p1(n,u)|0,m=r,n|0}function Nh(e){return e=e|0,(t[(a1()|0)+24>>2]|0)+(e*12|0)|0}function p1(e,n){e=e|0,n=n|0;var r=0;return r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),bl(Zp[r&31](e)|0)|0}function bl(e){return e=e|0,e&1|0}function $a(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],wa(e,r,l,0),m=u}function wa(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=V2()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=G2(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,hm(s,u)|0,u),m=l}function V2(){var e=0,n=0;if(c[7656]|0||(Ih(9304),Vt(28,9304,ve|0)|0,n=7656,t[n>>2]=1,t[n+4>>2]=0),!(sr(9304)|0)){e=9304,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Ih(9304)}return 9304}function G2(e){return e=e|0,0}function hm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=V2()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Y2(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Fh(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Y2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Fh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Ph(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,K2(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Y2(s,u,r),t[S>>2]=(t[S>>2]|0)+12,vm(e,D),mm(D),m=L;return}}function Ph(e){return e=e|0,357913941}function K2(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function vm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function mm(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Ih(e){e=e|0,h1(e)}function ym(e){e=e|0,X2(e+24|0)}function X2(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function h1(e){e=e|0;var n=0;n=yr()|0,jn(e,2,5,n,v1()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function v1(){return 1164}function m1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=Sa(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Q2(n,l,r),m=u}function Sa(e){return e=e|0,(t[(V2()|0)+24>>2]|0)+(e*12|0)|0}function Q2(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Ks(l,r),r=Xs(l,r)|0,I1[u&31](e,r),Qs(l),m=s}function Ks(e,n){e=e|0,n=n|0,J2(e,n)}function Xs(e,n){return e=e|0,n=n|0,e|0}function Qs(e){e=e|0,ca(e)}function J2(e,n){e=e|0,n=n|0,Ta(e,n)}function Ta(e,n){e=e|0,n=n|0,t[e>>2]=n}function y1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Td(e,r,l,0),m=u}function Td(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Tc()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=Z2(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,w0(s,u)|0,u),m=l}function Tc(){var e=0,n=0;if(c[7664]|0||(Hh(9340),Vt(29,9340,ve|0)|0,n=7664,t[n>>2]=1,t[n+4>>2]=0),!(sr(9340)|0)){e=9340,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Hh(9340)}return 9340}function Z2(e){return e=e|0,0}function w0(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Tc()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],bh(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Bh(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function bh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Bh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Uh(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,jh(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],bh(s,u,r),t[S>>2]=(t[S>>2]|0)+12,gm(e,D),zh(D),m=L;return}}function Uh(e){return e=e|0,357913941}function jh(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function gm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function zh(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Hh(e){e=e|0,qh(e)}function g1(e){e=e|0,$2(e+24|0)}function $2(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function qh(e){e=e|0;var n=0;n=yr()|0,jn(e,2,4,n,ep()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function ep(){return 1180}function Wh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=_m(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],r=Em(n,l,r)|0,m=u,r|0}function _m(e){return e=e|0,(t[(Tc()|0)+24>>2]|0)+(e*12|0)|0}function Em(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;return s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),If(l,r),l=bf(l,r)|0,l=Cd(tD[u&15](e,l)|0)|0,m=s,l|0}function If(e,n){e=e|0,n=n|0}function bf(e,n){return e=e|0,n=n|0,Dm(n)|0}function Cd(e){return e=e|0,e|0}function Dm(e){return e=e|0,e|0}function tp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],xd(e,r,l,0),m=u}function xd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=np()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=Vh(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,rp(s,u)|0,u),m=l}function np(){var e=0,n=0;if(c[7672]|0||(Kh(9376),Vt(30,9376,ve|0)|0,n=7672,t[n>>2]=1,t[n+4>>2]=0),!(sr(9376)|0)){e=9376,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Kh(9376)}return 9376}function Vh(e){return e=e|0,0}function rp(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=np()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Gh(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Yh(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Gh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Yh(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=ip(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,wm(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Gh(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Sm(e,D),Tm(D),m=L;return}}function ip(e){return e=e|0,357913941}function wm(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Sm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Tm(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Kh(e){e=e|0,up(e)}function _1(e){e=e|0,Cm(e+24|0)}function Cm(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function up(e){e=e|0;var n=0;n=yr()|0,jn(e,2,5,n,op()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function op(){return 1196}function xm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=Rm(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=Xh(n,u)|0,m=r,n|0}function Rm(e){return e=e|0,(t[(np()|0)+24>>2]|0)+(e*12|0)|0}function Xh(e,n){e=e|0,n=n|0;var r=0;return r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),Cd(Zp[r&31](e)|0)|0}function Am(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Om(e,r,l,1),m=u}function Om(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=lp()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=sp(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Ca(s,u)|0,u),m=l}function lp(){var e=0,n=0;if(c[7680]|0||(fp(9412),Vt(31,9412,ve|0)|0,n=7680,t[n>>2]=1,t[n+4>>2]=0),!(sr(9412)|0)){e=9412,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));fp(9412)}return 9412}function sp(e){return e=e|0,0}function Ca(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=lp()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],E1(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(ap(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function E1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function ap(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Qh(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Rd(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],E1(s,u,r),t[S>>2]=(t[S>>2]|0)+12,D1(e,D),Jh(D),m=L;return}}function Qh(e){return e=e|0,357913941}function Rd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function D1(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Jh(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function fp(e){e=e|0,$h(e)}function Zh(e){e=e|0,cp(e+24|0)}function cp(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function $h(e){e=e|0;var n=0;n=yr()|0,jn(e,2,6,n,ev()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function ev(){return 1200}function dp(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=Ad(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=Od(n,u)|0,m=r,n|0}function Ad(e){return e=e|0,(t[(lp()|0)+24>>2]|0)+(e*12|0)|0}function Od(e,n){e=e|0,n=n|0;var r=0;return r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),qo(Zp[r&31](e)|0)|0}function qo(e){return e=e|0,e|0}function Md(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],xa(e,r,l,0),m=u}function xa(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=ef()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=kd(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Ld(s,u)|0,u),m=l}function ef(){var e=0,n=0;if(c[7688]|0||(vp(9448),Vt(32,9448,ve|0)|0,n=7688,t[n>>2]=1,t[n+4>>2]=0),!(sr(9448)|0)){e=9448,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));vp(9448)}return 9448}function kd(e){return e=e|0,0}function Ld(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=ef()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],pp(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Nd(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function pp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Nd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=tv(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Mm(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],pp(s,u,r),t[S>>2]=(t[S>>2]|0)+12,nv(e,D),hp(D),m=L;return}}function tv(e){return e=e|0,357913941}function Mm(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function nv(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function hp(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function vp(e){e=e|0,Lm(e)}function mp(e){e=e|0,km(e+24|0)}function km(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function Lm(e){e=e|0;var n=0;n=yr()|0,jn(e,2,6,n,S0()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function S0(){return 1204}function Fd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=Nm(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],pl(n,l,r),m=u}function Nm(e){return e=e|0,(t[(ef()|0)+24>>2]|0)+(e*12|0)|0}function pl(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),tr(l,r),l=Js(l,r)|0,I1[u&31](e,l),m=s}function tr(e,n){e=e|0,n=n|0}function Js(e,n){return e=e|0,n=n|0,hl(n)|0}function hl(e){return e=e|0,e|0}function lo(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],rv(e,r,l,0),m=u}function rv(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Zs()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=yp(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Fm(s,u)|0,u),m=l}function Zs(){var e=0,n=0;if(c[7696]|0||(Ep(9484),Vt(33,9484,ve|0)|0,n=7696,t[n>>2]=1,t[n+4>>2]=0),!(sr(9484)|0)){e=9484,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Ep(9484)}return 9484}function yp(e){return e=e|0,0}function Fm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Zs()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],iv(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(gp(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function iv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function gp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Pm(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,_p(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],iv(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Cc(e,D),Ra(D),m=L;return}}function Pm(e){return e=e|0,357913941}function _p(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Cc(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Ra(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Ep(e){e=e|0,Yu(e)}function Pd(e){e=e|0,bu(e+24|0)}function bu(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function Yu(e){e=e|0;var n=0;n=yr()|0,jn(e,2,1,n,Dp()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Dp(){return 1212}function wp(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+16|0,s=l+8|0,h=l,D=uv(e)|0,e=t[D+4>>2]|0,t[h>>2]=t[D>>2],t[h+4>>2]=e,t[s>>2]=t[h>>2],t[s+4>>2]=t[h+4>>2],Im(n,s,r,u),m=l}function uv(e){return e=e|0,(t[(Zs()|0)+24>>2]|0)+(e*12|0)|0}function Im(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;D=m,m=m+16|0,s=D+1|0,h=D,l=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(l=t[(t[e>>2]|0)+l>>2]|0),tr(s,r),s=Js(s,r)|0,If(h,u),h=bf(h,u)|0,Fy[l&15](e,s,h),m=D}function bm(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Bm(e,r,l,1),m=u}function Bm(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Id()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=ov(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,xc(s,u)|0,u),m=l}function Id(){var e=0,n=0;if(c[7704]|0||(lv(9520),Vt(34,9520,ve|0)|0,n=7704,t[n>>2]=1,t[n+4>>2]=0),!(sr(9520)|0)){e=9520,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));lv(9520)}return 9520}function ov(e){return e=e|0,0}function xc(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Id()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],w1(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Um(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function w1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Um(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=bd(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,S1(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],w1(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Bl(e,D),Aa(D),m=L;return}}function bd(e){return e=e|0,357913941}function S1(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Bl(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Aa(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function lv(e){e=e|0,av(e)}function jm(e){e=e|0,sv(e+24|0)}function sv(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function av(e){e=e|0;var n=0;n=yr()|0,jn(e,2,1,n,zm()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function zm(){return 1224}function fv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;return l=m,m=m+16|0,s=l+8|0,h=l,D=Oa(e)|0,e=t[D+4>>2]|0,t[h>>2]=t[D>>2],t[h+4>>2]=e,t[s>>2]=t[h>>2],t[s+4>>2]=t[h+4>>2],u=+Mr(n,s,r),m=l,+u}function Oa(e){return e=e|0,(t[(Id()|0)+24>>2]|0)+(e*12|0)|0}function Mr(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Rs(l,r),l=Ys(l,r)|0,h=+Ya(+rS[u&7](e,l)),m=s,+h}function Sp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],vl(e,r,l,1),m=u}function vl(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=gu()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=T1(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Ui(s,u)|0,u),m=l}function gu(){var e=0,n=0;if(c[7712]|0||(Cp(9556),Vt(35,9556,ve|0)|0,n=7712,t[n>>2]=1,t[n+4>>2]=0),!(sr(9556)|0)){e=9556,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Cp(9556)}return 9556}function T1(e){return e=e|0,0}function Ui(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=gu()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Tp(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Bd(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Tp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Bd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=T0(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Os(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Tp(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Bf(e,D),Ud(D),m=L;return}}function T0(e){return e=e|0,357913941}function Os(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Bf(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Ud(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Cp(e){e=e|0,xp(e)}function C1(e){e=e|0,x1(e+24|0)}function x1(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function xp(e){e=e|0;var n=0;n=yr()|0,jn(e,2,5,n,nr()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function nr(){return 1232}function ml(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=Gn(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],r=+Wo(n,l),m=u,+r}function Gn(e){return e=e|0,(t[(gu()|0)+24>>2]|0)+(e*12|0)|0}function Wo(e,n){e=e|0,n=n|0;var r=0;return r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),+ +Ya(+nS[r&15](e))}function Lo(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],jd(e,r,l,1),m=u}function jd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Ul()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=R1(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Rc(s,u)|0,u),m=l}function Ul(){var e=0,n=0;if(c[7720]|0||(qd(9592),Vt(36,9592,ve|0)|0,n=7720,t[n>>2]=1,t[n+4>>2]=0),!(sr(9592)|0)){e=9592,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));qd(9592)}return 9592}function R1(e){return e=e|0,0}function Rc(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Ul()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Ac(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(zd(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Ac(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function zd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Rp(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,No(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Ac(s,u,r),t[S>>2]=(t[S>>2]|0)+12,dn(e,D),Hd(D),m=L;return}}function Rp(e){return e=e|0,357913941}function No(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function dn(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Hd(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function qd(e){e=e|0,kc(e)}function Oc(e){e=e|0,Mc(e+24|0)}function Mc(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function kc(e){e=e|0;var n=0;n=yr()|0,jn(e,2,7,n,A1()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function A1(){return 1276}function Ap(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=tf(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=Hm(n,u)|0,m=r,n|0}function tf(e){return e=e|0,(t[(Ul()|0)+24>>2]|0)+(e*12|0)|0}function Hm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;return l=m,m=m+16|0,u=l,r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),I1[r&31](u,e),u=Lc(u)|0,m=l,u|0}function Lc(e){e=e|0;var n=0,r=0,u=0,l=0;return l=m,m=m+32|0,n=l+12|0,r=l,u=Iu(Wd()|0)|0,u?(is(n,u),kf(r,n),cv(e,r),e=xs(n)|0):e=O1(e)|0,m=l,e|0}function Wd(){var e=0;return c[7736]|0||(W0(9640),Vt(25,9640,ve|0)|0,e=7736,t[e>>2]=1,t[e+4>>2]=0),9640}function cv(e,n){e=e|0,n=n|0,Nc(n,e,e+8|0)|0}function O1(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0;return r=m,m=m+16|0,l=r+4|0,h=r,u=Ma(8)|0,n=u,D=pn(16)|0,t[D>>2]=t[e>>2],t[D+4>>2]=t[e+4>>2],t[D+8>>2]=t[e+8>>2],t[D+12>>2]=t[e+12>>2],s=n+4|0,t[s>>2]=D,e=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],Uf(e,s,l),t[u>>2]=e,m=r,n|0}function Uf(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,r=pn(16)|0,t[r+4>>2]=0,t[r+8>>2]=0,t[r>>2]=1244,t[r+12>>2]=n,t[e+4>>2]=r}function jf(e){e=e|0,Uv(e),_t(e)}function M1(e){e=e|0,e=t[e+12>>2]|0,e|0&&_t(e)}function jl(e){e=e|0,_t(e)}function Nc(e,n,r){return e=e|0,n=n|0,r=r|0,n=zf(t[e>>2]|0,n,r)|0,r=e+4|0,t[(t[r>>2]|0)+8>>2]=n,t[(t[r>>2]|0)+8>>2]|0}function zf(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;return u=m,m=m+16|0,l=u,ka(l),e=g0(e)|0,r=qm(e,t[n>>2]|0,+B[r>>3])|0,La(l),m=u,r|0}function qm(e,n,r){e=e|0,n=n|0,r=+r;var u=0;return u=_0(yl()|0)|0,n=ad(n)|0,Hr(0,u|0,e|0,n|0,+ +kl(r))|0}function yl(){var e=0;return c[7728]|0||(Vd(9628),e=7728,t[e>>2]=1,t[e+4>>2]=0),9628}function Vd(e){e=e|0,ll(e,Gd()|0,2)}function Gd(){return 1264}function W0(e){e=e|0,Qa(e)}function Yd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Wm(e,r,l,1),m=u}function Wm(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=k1()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=Vm(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Gm(s,u)|0,u),m=l}function k1(){var e=0,n=0;if(c[7744]|0||(hv(9684),Vt(37,9684,ve|0)|0,n=7744,t[n>>2]=1,t[n+4>>2]=0),!(sr(9684)|0)){e=9684,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));hv(9684)}return 9684}function Vm(e){return e=e|0,0}function Gm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=k1()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],dv(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Ym(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function dv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Ym(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=pv(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Km(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],dv(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Xm(e,D),Qm(D),m=L;return}}function pv(e){return e=e|0,357913941}function Km(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Xm(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Qm(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function hv(e){e=e|0,Zm(e)}function Jm(e){e=e|0,Op(e+24|0)}function Op(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function Zm(e){e=e|0;var n=0;n=yr()|0,jn(e,2,5,n,Hf()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Hf(){return 1280}function vv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=mv(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],r=yv(n,l,r)|0,m=u,r|0}function mv(e){return e=e|0,(t[(k1()|0)+24>>2]|0)+(e*12|0)|0}function yv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return h=m,m=m+32|0,l=h,s=h+16|0,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Rs(s,r),s=Ys(s,r)|0,Fy[u&15](l,e,s),s=Lc(l)|0,m=h,s|0}function Kd(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Xd(e,r,l,1),m=u}function Xd(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Mp()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=gv(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Qd(s,u)|0,u),m=l}function Mp(){var e=0,n=0;if(c[7752]|0||(Sv(9720),Vt(38,9720,ve|0)|0,n=7752,t[n>>2]=1,t[n+4>>2]=0),!(sr(9720)|0)){e=9720,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Sv(9720)}return 9720}function gv(e){return e=e|0,0}function Qd(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Mp()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],_v(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(Ev(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function _v(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function Ev(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=kp(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Dv(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],_v(s,u,r),t[S>>2]=(t[S>>2]|0)+12,wv(e,D),$m(D),m=L;return}}function kp(e){return e=e|0,357913941}function Dv(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function wv(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function $m(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Sv(e){e=e|0,Tv(e)}function ey(e){e=e|0,Jd(e+24|0)}function Jd(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function Tv(e){e=e|0;var n=0;n=yr()|0,jn(e,2,8,n,Lp()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Lp(){return 1288}function ty(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;return r=m,m=m+16|0,u=r+8|0,l=r,s=so(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],n=Np(n,u)|0,m=r,n|0}function so(e){return e=e|0,(t[(Mp()|0)+24>>2]|0)+(e*12|0)|0}function Np(e,n){e=e|0,n=n|0;var r=0;return r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),dd(Zp[r&31](e)|0)|0}function ny(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],ry(e,r,l,0),m=u}function ry(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Fp()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=nf(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Pp(s,u)|0,u),m=l}function Fp(){var e=0,n=0;if(c[7760]|0||(Bp(9756),Vt(39,9756,ve|0)|0,n=7760,t[n>>2]=1,t[n+4>>2]=0),!(sr(9756)|0)){e=9756,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Bp(9756)}return 9756}function nf(e){return e=e|0,0}function Pp(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Fp()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Ip(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(bp(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Ip(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function bp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=iy(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,uy(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Ip(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Cv(e,D),qf(D),m=L;return}}function iy(e){return e=e|0,357913941}function uy(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Cv(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function qf(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Bp(e){e=e|0,ly(e)}function xv(e){e=e|0,oy(e+24|0)}function oy(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function ly(e){e=e|0;var n=0;n=yr()|0,jn(e,2,8,n,Up()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Up(){return 1292}function jp(e,n,r){e=e|0,n=n|0,r=+r;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=sy(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],ay(n,l,r),m=u}function sy(e){return e=e|0,(t[(Fp()|0)+24>>2]|0)+(e*12|0)|0}function ay(e,n,r){e=e|0,n=n|0,r=+r;var u=0,l=0,s=0;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Pl(l,r),r=+os(l,r),$8[u&31](e,r),m=s}function Rv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],zp(e,r,l,0),m=u}function zp(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Hp()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=Zd(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,fy(s,u)|0,u),m=l}function Hp(){var e=0,n=0;if(c[7768]|0||(qp(9792),Vt(40,9792,ve|0)|0,n=7768,t[n>>2]=1,t[n+4>>2]=0),!(sr(9792)|0)){e=9792,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));qp(9792)}return 9792}function Zd(e){return e=e|0,0}function fy(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Hp()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],L1(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(cy(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function L1(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function cy(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Av(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Ov(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],L1(s,u,r),t[S>>2]=(t[S>>2]|0)+12,dy(e,D),Wf(D),m=L;return}}function Av(e){return e=e|0,357913941}function Ov(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function dy(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Wf(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function qp(e){e=e|0,hy(e)}function Mv(e){e=e|0,py(e+24|0)}function py(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function hy(e){e=e|0;var n=0;n=yr()|0,jn(e,2,1,n,Wp()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function Wp(){return 1300}function vy(e,n,r,u){e=e|0,n=n|0,r=r|0,u=+u;var l=0,s=0,h=0,D=0;l=m,m=m+16|0,s=l+8|0,h=l,D=$s(e)|0,e=t[D+4>>2]|0,t[h>>2]=t[D>>2],t[h+4>>2]=e,t[s>>2]=t[h>>2],t[s+4>>2]=t[h+4>>2],my(n,s,r,u),m=l}function $s(e){return e=e|0,(t[(Hp()|0)+24>>2]|0)+(e*12|0)|0}function my(e,n,r,u){e=e|0,n=n|0,r=r|0,u=+u;var l=0,s=0,h=0,D=0;D=m,m=m+16|0,s=D+1|0,h=D,l=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(l=t[(t[e>>2]|0)+l>>2]|0),Rs(s,r),s=Ys(s,r)|0,Pl(h,u),u=+os(h,u),lS[l&15](e,s,u),m=D}function p(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],v(e,r,l,0),m=u}function v(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=x()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=P(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,W(s,u)|0,u),m=l}function x(){var e=0,n=0;if(c[7776]|0||(At(9828),Vt(41,9828,ve|0)|0,n=7776,t[n>>2]=1,t[n+4>>2]=0),!(sr(9828)|0)){e=9828,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));At(9828)}return 9828}function P(e){return e=e|0,0}function W(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=x()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],ee(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(he(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function ee(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function he(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=De(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,be(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],ee(s,u,r),t[S>>2]=(t[S>>2]|0)+12,Et(e,D),St(D),m=L;return}}function De(e){return e=e|0,357913941}function be(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function Et(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function St(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function At(e){e=e|0,rr(e)}function on(e){e=e|0,kn(e+24|0)}function kn(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function rr(e){e=e|0;var n=0;n=yr()|0,jn(e,2,7,n,br()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function br(){return 1312}function ar(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=ui(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],di(n,l,r),m=u}function ui(e){return e=e|0,(t[(x()|0)+24>>2]|0)+(e*12|0)|0}function di(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Rs(l,r),l=Ys(l,r)|0,I1[u&31](e,l),m=s}function zl(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],Zi(e,r,l,0),m=u}function Zi(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=a0()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=ao(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,Ms(s,u)|0,u),m=l}function a0(){var e=0,n=0;if(c[7784]|0||(n_(9864),Vt(42,9864,ve|0)|0,n=7784,t[n>>2]=1,t[n+4>>2]=0),!(sr(9864)|0)){e=9864,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));n_(9864)}return 9864}function ao(e){return e=e|0,0}function Ms(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=a0()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],C0(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(kv(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function C0(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function kv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Z4(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,yy(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],C0(s,u,r),t[S>>2]=(t[S>>2]|0)+12,gy(e,D),rf(D),m=L;return}}function Z4(e){return e=e|0,357913941}function yy(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function gy(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function rf(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function n_(e){e=e|0,tE(e)}function $4(e){e=e|0,eE(e+24|0)}function eE(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function tE(e){e=e|0;var n=0;n=yr()|0,jn(e,2,8,n,nE()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function nE(){return 1320}function _y(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=rE(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],iE(n,l,r),m=u}function rE(e){return e=e|0,(t[(a0()|0)+24>>2]|0)+(e*12|0)|0}function iE(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Ey(l,r),l=r_(l,r)|0,I1[u&31](e,l),m=s}function Ey(e,n){e=e|0,n=n|0}function r_(e,n){return e=e|0,n=n|0,uE(n)|0}function uE(e){return e=e|0,e|0}function oE(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],i_(e,r,l,0),m=u}function i_(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=Vf()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=u_(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,lE(s,u)|0,u),m=l}function Vf(){var e=0,n=0;if(c[7792]|0||(Sy(9900),Vt(43,9900,ve|0)|0,n=7792,t[n>>2]=1,t[n+4>>2]=0),!(sr(9900)|0)){e=9900,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Sy(9900)}return 9900}function u_(e){return e=e|0,0}function lE(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=Vf()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],Vp(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(sE(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function Vp(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function sE(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=Lv(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,Dy(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],Vp(s,u,r),t[S>>2]=(t[S>>2]|0)+12,wy(e,D),aE(D),m=L;return}}function Lv(e){return e=e|0,357913941}function Dy(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function wy(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function aE(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function Sy(e){e=e|0,o_(e)}function fE(e){e=e|0,cE(e+24|0)}function cE(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function o_(e){e=e|0;var n=0;n=yr()|0,jn(e,2,22,n,dE()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function dE(){return 1344}function pE(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0;r=m,m=m+16|0,u=r+8|0,l=r,s=l_(e)|0,e=t[s+4>>2]|0,t[l>>2]=t[s>>2],t[l+4>>2]=e,t[u>>2]=t[l>>2],t[u+4>>2]=t[l+4>>2],Nv(n,u),m=r}function l_(e){return e=e|0,(t[(Vf()|0)+24>>2]|0)+(e*12|0)|0}function Nv(e,n){e=e|0,n=n|0;var r=0;r=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(r=t[(t[e>>2]|0)+r>>2]|0),P1[r&127](e)}function hE(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=Ty()|0,e=vE(r)|0,wi(s,n,l,e,mE(r,u)|0,u)}function Ty(){var e=0,n=0;if(c[7800]|0||(xy(9936),Vt(44,9936,ve|0)|0,n=7800,t[n>>2]=1,t[n+4>>2]=0),!(sr(9936)|0)){e=9936,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));xy(9936)}return 9936}function vE(e){return e=e|0,e|0}function mE(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=Ty()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(Cy(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(s_(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function Cy(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function s_(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=a_(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,f_(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,Cy(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,c_(e,l),d_(l),m=D;return}}function a_(e){return e=e|0,536870911}function f_(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function c_(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function d_(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function xy(e){e=e|0,h_(e)}function p_(e){e=e|0,yE(e+24|0)}function yE(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function h_(e){e=e|0;var n=0;n=yr()|0,jn(e,1,23,n,S0()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function gE(e,n){e=e|0,n=n|0,f(t[(_E(e)|0)>>2]|0,n)}function _E(e){return e=e|0,(t[(Ty()|0)+24>>2]|0)+(e<<3)|0}function f(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,tr(u,n),n=Js(u,n)|0,P1[e&127](n),m=r}function d(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=E()|0,e=C(r)|0,wi(s,n,l,e,A(r,u)|0,u)}function E(){var e=0,n=0;if(c[7808]|0||(vt(9972),Vt(45,9972,ve|0)|0,n=7808,t[n>>2]=1,t[n+4>>2]=0),!(sr(9972)|0)){e=9972,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));vt(9972)}return 9972}function C(e){return e=e|0,e|0}function A(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=E()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(j(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(V(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function j(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function V(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=te(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,se(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,j(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,Ue(e,l),Qe(l),m=D;return}}function te(e){return e=e|0,536870911}function se(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function Ue(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function Qe(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function vt(e){e=e|0,Ht(e)}function Nt(e){e=e|0,Yt(e+24|0)}function Yt(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function Ht(e){e=e|0;var n=0;n=yr()|0,jn(e,1,9,n,yn()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function yn(){return 1348}function kr(e,n){return e=e|0,n=n|0,Oi(t[(oi(e)|0)>>2]|0,n)|0}function oi(e){return e=e|0,(t[(E()|0)+24>>2]|0)+(e<<3)|0}function Oi(e,n){e=e|0,n=n|0;var r=0,u=0;return r=m,m=m+16|0,u=r,Fo(u,n),n=$i(u,n)|0,n=Cd(Zp[e&31](n)|0)|0,m=r,n|0}function Fo(e,n){e=e|0,n=n|0}function $i(e,n){return e=e|0,n=n|0,ot(n)|0}function ot(e){return e=e|0,e|0}function Ot(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=$e()|0,e=Ut(r)|0,wi(s,n,l,e,Pn(r,u)|0,u)}function $e(){var e=0,n=0;if(c[7816]|0||(Kr(10008),Vt(46,10008,ve|0)|0,n=7816,t[n>>2]=1,t[n+4>>2]=0),!(sr(10008)|0)){e=10008,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));Kr(10008)}return 10008}function Ut(e){return e=e|0,e|0}function Pn(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=$e()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(vn(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(Wi(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function vn(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function Wi(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=pi(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,Ku(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,vn(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,hr(e,l),hu(l),m=D;return}}function pi(e){return e=e|0,536870911}function Ku(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function hr(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function hu(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function Kr(e){e=e|0,Vo(e)}function xu(e){e=e|0,So(e+24|0)}function So(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function Vo(e){e=e|0;var n=0;n=yr()|0,jn(e,1,15,n,op()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function ks(e){return e=e|0,gl(t[(Xu(e)|0)>>2]|0)|0}function Xu(e){return e=e|0,(t[($e()|0)+24>>2]|0)+(e<<3)|0}function gl(e){return e=e|0,Cd(k_[e&7]()|0)|0}function uf(){var e=0;return c[7832]|0||(m_(10052),Vt(25,10052,ve|0)|0,e=7832,t[e>>2]=1,t[e+4>>2]=0),10052}function V0(e,n){e=e|0,n=n|0,t[e>>2]=Ls()|0,t[e+4>>2]=$d()|0,t[e+12>>2]=n,t[e+8>>2]=Gf()|0,t[e+32>>2]=2}function Ls(){return 11709}function $d(){return 1188}function Gf(){return N1()|0}function Fc(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(G0(r),_t(r)):n|0&&(ws(n),_t(n))}function Hl(e,n){return e=e|0,n=n|0,n&e|0}function G0(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function N1(){var e=0;return c[7824]|0||(t[2511]=v_()|0,t[2512]=0,e=7824,t[e>>2]=1,t[e+4>>2]=0),10044}function v_(){return 0}function m_(e){e=e|0,Qa(e)}function EE(e){e=e|0;var n=0,r=0,u=0,l=0,s=0;n=m,m=m+32|0,r=n+24|0,s=n+16|0,l=n+8|0,u=n,y_(e,4827),DE(e,4834,3)|0,wE(e,3682,47)|0,t[s>>2]=9,t[s+4>>2]=0,t[r>>2]=t[s>>2],t[r+4>>2]=t[s+4>>2],Ry(e,4841,r)|0,t[l>>2]=1,t[l+4>>2]=0,t[r>>2]=t[l>>2],t[r+4>>2]=t[l+4>>2],g_(e,4871,r)|0,t[u>>2]=10,t[u+4>>2]=0,t[r>>2]=t[u>>2],t[r+4>>2]=t[u+4>>2],SE(e,4891,r)|0,m=n}function y_(e,n){e=e|0,n=n|0;var r=0;r=JA()|0,t[e>>2]=r,ZA(r,n),e2(t[e>>2]|0)}function DE(e,n,r){return e=e|0,n=n|0,r=r|0,PA(e,Fr(n)|0,r,0),e|0}function wE(e,n,r){return e=e|0,n=n|0,r=r|0,EA(e,Fr(n)|0,r,0),e|0}function Ry(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],tA(e,n,l),m=u,e|0}function g_(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],IR(e,n,l),m=u,e|0}function SE(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=t[r+4>>2]|0,t[s>>2]=t[r>>2],t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],TE(e,n,l),m=u,e|0}function TE(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],CE(e,r,l,1),m=u}function CE(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=xE()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=wR(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,SR(s,u)|0,u),m=l}function xE(){var e=0,n=0;if(c[7840]|0||(I3(10100),Vt(48,10100,ve|0)|0,n=7840,t[n>>2]=1,t[n+4>>2]=0),!(sr(10100)|0)){e=10100,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));I3(10100)}return 10100}function wR(e){return e=e|0,0}function SR(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=xE()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],P3(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(TR(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function P3(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function TR(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=CR(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,xR(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],P3(s,u,r),t[S>>2]=(t[S>>2]|0)+12,RR(e,D),AR(D),m=L;return}}function CR(e){return e=e|0,357913941}function xR(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function RR(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function AR(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function I3(e){e=e|0,kR(e)}function OR(e){e=e|0,MR(e+24|0)}function MR(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function kR(e){e=e|0;var n=0;n=yr()|0,jn(e,2,6,n,LR()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function LR(){return 1364}function NR(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;return u=m,m=m+16|0,l=u+8|0,s=u,h=FR(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],r=PR(n,l,r)|0,m=u,r|0}function FR(e){return e=e|0,(t[(xE()|0)+24>>2]|0)+(e*12|0)|0}function PR(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;return s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),Rs(l,r),l=Ys(l,r)|0,l=bl(tD[u&15](e,l)|0)|0,m=s,l|0}function IR(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],bR(e,r,l,0),m=u}function bR(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=RE()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=BR(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,UR(s,u)|0,u),m=l}function RE(){var e=0,n=0;if(c[7848]|0||(B3(10136),Vt(49,10136,ve|0)|0,n=7848,t[n>>2]=1,t[n+4>>2]=0),!(sr(10136)|0)){e=10136,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));B3(10136)}return 10136}function BR(e){return e=e|0,0}function UR(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=RE()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],b3(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(jR(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function b3(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function jR(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=zR(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,HR(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],b3(s,u,r),t[S>>2]=(t[S>>2]|0)+12,qR(e,D),WR(D),m=L;return}}function zR(e){return e=e|0,357913941}function HR(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function qR(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function WR(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function B3(e){e=e|0,YR(e)}function VR(e){e=e|0,GR(e+24|0)}function GR(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function YR(e){e=e|0;var n=0;n=yr()|0,jn(e,2,9,n,KR()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function KR(){return 1372}function XR(e,n,r){e=e|0,n=n|0,r=+r;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,l=u+8|0,s=u,h=QR(e)|0,e=t[h+4>>2]|0,t[s>>2]=t[h>>2],t[s+4>>2]=e,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],JR(n,l,r),m=u}function QR(e){return e=e|0,(t[(RE()|0)+24>>2]|0)+(e*12|0)|0}function JR(e,n,r){e=e|0,n=n|0,r=+r;var u=0,l=0,s=0,h=Tt;s=m,m=m+16|0,l=s,u=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(u=t[(t[e>>2]|0)+u>>2]|0),ZR(l,r),h=w($R(l,r)),Z8[u&1](e,h),m=s}function ZR(e,n){e=e|0,n=+n}function $R(e,n){return e=e|0,n=+n,w(eA(n))}function eA(e){return e=+e,w(e)}function tA(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,l=u+8|0,s=u,D=t[r>>2]|0,h=t[r+4>>2]|0,r=Fr(n)|0,t[s>>2]=D,t[s+4>>2]=h,t[l>>2]=t[s>>2],t[l+4>>2]=t[s+4>>2],nA(e,r,l,0),m=u}function nA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0,S=0,L=0,k=0;l=m,m=m+32|0,s=l+16|0,k=l+8|0,D=l,L=t[r>>2]|0,S=t[r+4>>2]|0,h=t[e>>2]|0,e=AE()|0,t[k>>2]=L,t[k+4>>2]=S,t[s>>2]=t[k>>2],t[s+4>>2]=t[k+4>>2],r=rA(s)|0,t[D>>2]=L,t[D+4>>2]=S,t[s>>2]=t[D>>2],t[s+4>>2]=t[D+4>>2],wi(h,n,e,r,iA(s,u)|0,u),m=l}function AE(){var e=0,n=0;if(c[7856]|0||(j3(10172),Vt(50,10172,ve|0)|0,n=7856,t[n>>2]=1,t[n+4>>2]=0),!(sr(10172)|0)){e=10172,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));j3(10172)}return 10172}function rA(e){return e=e|0,0}function iA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0;return k=m,m=m+32|0,l=k+24|0,h=k+16|0,D=k,S=k+8|0,s=t[e>>2]|0,u=t[e+4>>2]|0,t[D>>2]=s,t[D+4>>2]=u,I=AE()|0,L=I+24|0,e=hn(n,4)|0,t[S>>2]=e,n=I+28|0,r=t[n>>2]|0,r>>>0<(t[I+32>>2]|0)>>>0?(t[h>>2]=s,t[h+4>>2]=u,t[l>>2]=t[h>>2],t[l+4>>2]=t[h+4>>2],U3(r,l,e),e=(t[n>>2]|0)+12|0,t[n>>2]=e):(uA(L,D,S),e=t[n>>2]|0),m=k,((e-(t[L>>2]|0)|0)/12|0)+-1|0}function U3(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=t[n+4>>2]|0,t[e>>2]=t[n>>2],t[e+4>>2]=u,t[e+8>>2]=r}function uA(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;if(L=m,m=m+48|0,u=L+32|0,h=L+24|0,D=L,S=e+4|0,l=(((t[S>>2]|0)-(t[e>>2]|0)|0)/12|0)+1|0,s=oA(e)|0,s>>>0>>0)hi(e);else{k=t[e>>2]|0,K=((t[e+8>>2]|0)-k|0)/12|0,I=K<<1,lA(D,K>>>0>>1>>>0?I>>>0>>0?l:I:s,((t[S>>2]|0)-k|0)/12|0,e+8|0),S=D+8|0,s=t[S>>2]|0,l=t[n+4>>2]|0,r=t[r>>2]|0,t[h>>2]=t[n>>2],t[h+4>>2]=l,t[u>>2]=t[h>>2],t[u+4>>2]=t[h+4>>2],U3(s,u,r),t[S>>2]=(t[S>>2]|0)+12,sA(e,D),aA(D),m=L;return}}function oA(e){return e=e|0,357913941}function lA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>357913941)$n();else{l=pn(n*12|0)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r*12|0)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n*12|0)}function sA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(((l|0)/-12|0)*12|0)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function aA(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~(((u+-12-n|0)>>>0)/12|0)*12|0)),e=t[e>>2]|0,e|0&&_t(e)}function j3(e){e=e|0,dA(e)}function fA(e){e=e|0,cA(e+24|0)}function cA(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~(((n+-12-u|0)>>>0)/12|0)*12|0)),_t(r))}function dA(e){e=e|0;var n=0;n=yr()|0,jn(e,2,3,n,pA()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function pA(){return 1380}function hA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+16|0,s=l+8|0,h=l,D=vA(e)|0,e=t[D+4>>2]|0,t[h>>2]=t[D>>2],t[h+4>>2]=e,t[s>>2]=t[h>>2],t[s+4>>2]=t[h+4>>2],mA(n,s,r,u),m=l}function vA(e){return e=e|0,(t[(AE()|0)+24>>2]|0)+(e*12|0)|0}function mA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;D=m,m=m+16|0,s=D+1|0,h=D,l=t[n>>2]|0,n=t[n+4>>2]|0,e=e+(n>>1)|0,n&1&&(l=t[(t[e>>2]|0)+l>>2]|0),Rs(s,r),s=Ys(s,r)|0,yA(h,u),h=gA(h,u)|0,Fy[l&15](e,s,h),m=D}function yA(e,n){e=e|0,n=n|0}function gA(e,n){return e=e|0,n=n|0,_A(n)|0}function _A(e){return e=e|0,(e|0)!=0|0}function EA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=OE()|0,e=DA(r)|0,wi(s,n,l,e,wA(r,u)|0,u)}function OE(){var e=0,n=0;if(c[7864]|0||(H3(10208),Vt(51,10208,ve|0)|0,n=7864,t[n>>2]=1,t[n+4>>2]=0),!(sr(10208)|0)){e=10208,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));H3(10208)}return 10208}function DA(e){return e=e|0,e|0}function wA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=OE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(z3(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(SA(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function z3(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function SA(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=TA(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,CA(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,z3(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,xA(e,l),RA(l),m=D;return}}function TA(e){return e=e|0,536870911}function CA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function xA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function RA(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function H3(e){e=e|0,MA(e)}function AA(e){e=e|0,OA(e+24|0)}function OA(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function MA(e){e=e|0;var n=0;n=yr()|0,jn(e,1,24,n,kA()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function kA(){return 1392}function LA(e,n){e=e|0,n=n|0,FA(t[(NA(e)|0)>>2]|0,n)}function NA(e){return e=e|0,(t[(OE()|0)+24>>2]|0)+(e<<3)|0}function FA(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,Fo(u,n),n=$i(u,n)|0,P1[e&127](n),m=r}function PA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=ME()|0,e=IA(r)|0,wi(s,n,l,e,bA(r,u)|0,u)}function ME(){var e=0,n=0;if(c[7872]|0||(W3(10244),Vt(52,10244,ve|0)|0,n=7872,t[n>>2]=1,t[n+4>>2]=0),!(sr(10244)|0)){e=10244,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));W3(10244)}return 10244}function IA(e){return e=e|0,e|0}function bA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=ME()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(q3(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(BA(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function q3(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function BA(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=UA(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,jA(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,q3(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,zA(e,l),HA(l),m=D;return}}function UA(e){return e=e|0,536870911}function jA(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function zA(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function HA(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function W3(e){e=e|0,VA(e)}function qA(e){e=e|0,WA(e+24|0)}function WA(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function VA(e){e=e|0;var n=0;n=yr()|0,jn(e,1,16,n,GA()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function GA(){return 1400}function YA(e){return e=e|0,XA(t[(KA(e)|0)>>2]|0)|0}function KA(e){return e=e|0,(t[(ME()|0)+24>>2]|0)+(e<<3)|0}function XA(e){return e=e|0,QA(k_[e&7]()|0)|0}function QA(e){return e=e|0,e|0}function JA(){var e=0;return c[7880]|0||(i7(10280),Vt(25,10280,ve|0)|0,e=7880,t[e>>2]=1,t[e+4>>2]=0),10280}function ZA(e,n){e=e|0,n=n|0,t[e>>2]=$A()|0,t[e+4>>2]=e7()|0,t[e+12>>2]=n,t[e+8>>2]=t7()|0,t[e+32>>2]=4}function $A(){return 11711}function e7(){return 1356}function t7(){return N1()|0}function n7(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(r7(r),_t(r)):n|0&&(i0(n),_t(n))}function r7(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function i7(e){e=e|0,Qa(e)}function u7(e){e=e|0,o7(e,4920),l7(e)|0,s7(e)|0}function o7(e,n){e=e|0,n=n|0;var r=0;r=Wd()|0,t[e>>2]=r,O7(r,n),e2(t[e>>2]|0)}function l7(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,_7()|0),e|0}function s7(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,a7()|0),e|0}function a7(){var e=0;return c[7888]|0||(V3(10328),Vt(53,10328,ve|0)|0,e=7888,t[e>>2]=1,t[e+4>>2]=0),sr(10328)|0||V3(10328),10328}function Gp(e,n){e=e|0,n=n|0,wi(e,0,n,0,0,0)}function V3(e){e=e|0,d7(e),Yp(e,10)}function f7(e){e=e|0,c7(e+24|0)}function c7(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function d7(e){e=e|0;var n=0;n=yr()|0,jn(e,5,1,n,m7()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function p7(e,n,r){e=e|0,n=n|0,r=+r,h7(e,n,r)}function Yp(e,n){e=e|0,n=n|0,t[e+20>>2]=n}function h7(e,n,r){e=e|0,n=n|0,r=+r;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+16|0,s=u+8|0,D=u+13|0,l=u,h=u+12|0,Rs(D,n),t[s>>2]=Ys(D,n)|0,Pl(h,r),B[l>>3]=+os(h,r),v7(e,s,l),m=u}function v7(e,n,r){e=e|0,n=n|0,r=r|0,b(e+8|0,t[n>>2]|0,+B[r>>3]),c[e+24>>0]=1}function m7(){return 1404}function y7(e,n){return e=e|0,n=+n,g7(e,n)|0}function g7(e,n){e=e|0,n=+n;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return u=m,m=m+16|0,s=u+4|0,h=u+8|0,D=u,l=Ma(8)|0,r=l,S=pn(16)|0,Rs(s,e),e=Ys(s,e)|0,Pl(h,n),b(S,e,+os(h,n)),h=r+4|0,t[h>>2]=S,e=pn(8)|0,h=t[h>>2]|0,t[D>>2]=0,t[s>>2]=t[D>>2],Uf(e,h,s),t[l>>2]=e,m=u,r|0}function _7(){var e=0;return c[7896]|0||(G3(10364),Vt(54,10364,ve|0)|0,e=7896,t[e>>2]=1,t[e+4>>2]=0),sr(10364)|0||G3(10364),10364}function G3(e){e=e|0,w7(e),Yp(e,55)}function E7(e){e=e|0,D7(e+24|0)}function D7(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function w7(e){e=e|0;var n=0;n=yr()|0,jn(e,5,4,n,x7()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function S7(e){e=e|0,T7(e)}function T7(e){e=e|0,C7(e)}function C7(e){e=e|0,Y3(e+8|0),c[e+24>>0]=1}function Y3(e){e=e|0,t[e>>2]=0,B[e+8>>3]=0}function x7(){return 1424}function R7(){return A7()|0}function A7(){var e=0,n=0,r=0,u=0,l=0,s=0,h=0;return n=m,m=m+16|0,l=n+4|0,h=n,r=Ma(8)|0,e=r,u=pn(16)|0,Y3(u),s=e+4|0,t[s>>2]=u,u=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],Uf(u,s,l),t[r>>2]=u,m=n,e|0}function O7(e,n){e=e|0,n=n|0,t[e>>2]=M7()|0,t[e+4>>2]=k7()|0,t[e+12>>2]=n,t[e+8>>2]=L7()|0,t[e+32>>2]=5}function M7(){return 11710}function k7(){return 1416}function L7(){return __()|0}function N7(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(F7(r),_t(r)):n|0&&_t(n)}function F7(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function __(){var e=0;return c[7904]|0||(t[2600]=P7()|0,t[2601]=0,e=7904,t[e>>2]=1,t[e+4>>2]=0),10400}function P7(){return t[357]|0}function I7(e){e=e|0,b7(e,4926),B7(e)|0}function b7(e,n){e=e|0,n=n|0;var r=0;r=Xa()|0,t[e>>2]=r,X7(r,n),e2(t[e>>2]|0)}function B7(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,U7()|0),e|0}function U7(){var e=0;return c[7912]|0||(K3(10412),Vt(56,10412,ve|0)|0,e=7912,t[e>>2]=1,t[e+4>>2]=0),sr(10412)|0||K3(10412),10412}function K3(e){e=e|0,H7(e),Yp(e,57)}function j7(e){e=e|0,z7(e+24|0)}function z7(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function H7(e){e=e|0;var n=0;n=yr()|0,jn(e,5,5,n,G7()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function q7(e){e=e|0,W7(e)}function W7(e){e=e|0,V7(e)}function V7(e){e=e|0;var n=0,r=0;n=e+8|0,r=n+48|0;do t[n>>2]=0,n=n+4|0;while((n|0)<(r|0));c[e+56>>0]=1}function G7(){return 1432}function Y7(){return K7()|0}function K7(){var e=0,n=0,r=0,u=0,l=0,s=0,h=0,D=0;h=m,m=m+16|0,e=h+4|0,n=h,r=Ma(8)|0,u=r,l=pn(48)|0,s=l,D=s+48|0;do t[s>>2]=0,s=s+4|0;while((s|0)<(D|0));return s=u+4|0,t[s>>2]=l,D=pn(8)|0,s=t[s>>2]|0,t[n>>2]=0,t[e>>2]=t[n>>2],Th(D,s,e),t[r>>2]=D,m=h,u|0}function X7(e,n){e=e|0,n=n|0,t[e>>2]=Q7()|0,t[e+4>>2]=J7()|0,t[e+12>>2]=n,t[e+8>>2]=Z7()|0,t[e+32>>2]=6}function Q7(){return 11704}function J7(){return 1436}function Z7(){return __()|0}function $7(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(eO(r),_t(r)):n|0&&_t(n)}function eO(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function tO(e){e=e|0,nO(e,4933),rO(e)|0,iO(e)|0}function nO(e,n){e=e|0,n=n|0;var r=0;r=AO()|0,t[e>>2]=r,OO(r,n),e2(t[e>>2]|0)}function rO(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,gO()|0),e|0}function iO(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,uO()|0),e|0}function uO(){var e=0;return c[7920]|0||(X3(10452),Vt(58,10452,ve|0)|0,e=7920,t[e>>2]=1,t[e+4>>2]=0),sr(10452)|0||X3(10452),10452}function X3(e){e=e|0,sO(e),Yp(e,1)}function oO(e){e=e|0,lO(e+24|0)}function lO(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function sO(e){e=e|0;var n=0;n=yr()|0,jn(e,5,1,n,dO()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function aO(e,n,r){e=e|0,n=+n,r=+r,fO(e,n,r)}function fO(e,n,r){e=e|0,n=+n,r=+r;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+32|0,s=u+8|0,D=u+17|0,l=u,h=u+16|0,Pl(D,n),B[s>>3]=+os(D,n),Pl(h,r),B[l>>3]=+os(h,r),cO(e,s,l),m=u}function cO(e,n,r){e=e|0,n=n|0,r=r|0,Q3(e+8|0,+B[n>>3],+B[r>>3]),c[e+24>>0]=1}function Q3(e,n,r){e=e|0,n=+n,r=+r,B[e>>3]=n,B[e+8>>3]=r}function dO(){return 1472}function pO(e,n){return e=+e,n=+n,hO(e,n)|0}function hO(e,n){e=+e,n=+n;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return u=m,m=m+16|0,h=u+4|0,D=u+8|0,S=u,l=Ma(8)|0,r=l,s=pn(16)|0,Pl(h,e),e=+os(h,e),Pl(D,n),Q3(s,e,+os(D,n)),D=r+4|0,t[D>>2]=s,s=pn(8)|0,D=t[D>>2]|0,t[S>>2]=0,t[h>>2]=t[S>>2],J3(s,D,h),t[l>>2]=s,m=u,r|0}function J3(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,r=pn(16)|0,t[r+4>>2]=0,t[r+8>>2]=0,t[r>>2]=1452,t[r+12>>2]=n,t[e+4>>2]=r}function vO(e){e=e|0,Uv(e),_t(e)}function mO(e){e=e|0,e=t[e+12>>2]|0,e|0&&_t(e)}function yO(e){e=e|0,_t(e)}function gO(){var e=0;return c[7928]|0||(Z3(10488),Vt(59,10488,ve|0)|0,e=7928,t[e>>2]=1,t[e+4>>2]=0),sr(10488)|0||Z3(10488),10488}function Z3(e){e=e|0,DO(e),Yp(e,60)}function _O(e){e=e|0,EO(e+24|0)}function EO(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function DO(e){e=e|0;var n=0;n=yr()|0,jn(e,5,6,n,CO()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function wO(e){e=e|0,SO(e)}function SO(e){e=e|0,TO(e)}function TO(e){e=e|0,$3(e+8|0),c[e+24>>0]=1}function $3(e){e=e|0,t[e>>2]=0,t[e+4>>2]=0,t[e+8>>2]=0,t[e+12>>2]=0}function CO(){return 1492}function xO(){return RO()|0}function RO(){var e=0,n=0,r=0,u=0,l=0,s=0,h=0;return n=m,m=m+16|0,l=n+4|0,h=n,r=Ma(8)|0,e=r,u=pn(16)|0,$3(u),s=e+4|0,t[s>>2]=u,u=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],J3(u,s,l),t[r>>2]=u,m=n,e|0}function AO(){var e=0;return c[7936]|0||(PO(10524),Vt(25,10524,ve|0)|0,e=7936,t[e>>2]=1,t[e+4>>2]=0),10524}function OO(e,n){e=e|0,n=n|0,t[e>>2]=MO()|0,t[e+4>>2]=kO()|0,t[e+12>>2]=n,t[e+8>>2]=LO()|0,t[e+32>>2]=7}function MO(){return 11700}function kO(){return 1484}function LO(){return __()|0}function NO(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(FO(r),_t(r)):n|0&&_t(n)}function FO(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function PO(e){e=e|0,Qa(e)}function IO(e,n,r){e=e|0,n=n|0,r=r|0,e=Fr(n)|0,n=bO(r)|0,r=BO(r,0)|0,hM(e,n,r,kE()|0,0)}function bO(e){return e=e|0,e|0}function BO(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=kE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(t8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(VO(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function kE(){var e=0,n=0;if(c[7944]|0||(e8(10568),Vt(61,10568,ve|0)|0,n=7944,t[n>>2]=1,t[n+4>>2]=0),!(sr(10568)|0)){e=10568,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));e8(10568)}return 10568}function e8(e){e=e|0,zO(e)}function UO(e){e=e|0,jO(e+24|0)}function jO(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function zO(e){e=e|0;var n=0;n=yr()|0,jn(e,1,17,n,ev()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function HO(e){return e=e|0,WO(t[(qO(e)|0)>>2]|0)|0}function qO(e){return e=e|0,(t[(kE()|0)+24>>2]|0)+(e<<3)|0}function WO(e){return e=e|0,qo(k_[e&7]()|0)|0}function t8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function VO(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=GO(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,YO(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,t8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,KO(e,l),XO(l),m=D;return}}function GO(e){return e=e|0,536870911}function YO(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function KO(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function XO(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function QO(){JO()}function JO(){ZO(10604)}function ZO(e){e=e|0,$O(e,4955)}function $O(e,n){e=e|0,n=n|0;var r=0;r=eM()|0,t[e>>2]=r,tM(r,n),e2(t[e>>2]|0)}function eM(){var e=0;return c[7952]|0||(fM(10612),Vt(25,10612,ve|0)|0,e=7952,t[e>>2]=1,t[e+4>>2]=0),10612}function tM(e,n){e=e|0,n=n|0,t[e>>2]=uM()|0,t[e+4>>2]=oM()|0,t[e+12>>2]=n,t[e+8>>2]=lM()|0,t[e+32>>2]=8}function e2(e){e=e|0;var n=0,r=0;n=m,m=m+16|0,r=n,Fv()|0,t[r>>2]=e,nM(10608,r),m=n}function Fv(){return c[11714]|0||(t[2652]=0,Vt(62,10608,ve|0)|0,c[11714]=1),10608}function nM(e,n){e=e|0,n=n|0;var r=0;r=pn(8)|0,t[r+4>>2]=t[n>>2],t[r>>2]=t[e>>2],t[e>>2]=r}function rM(e){e=e|0,iM(e)}function iM(e){e=e|0;var n=0,r=0;if(n=t[e>>2]|0,n|0)do r=n,n=t[n>>2]|0,_t(r);while((n|0)!=0);t[e>>2]=0}function uM(){return 11715}function oM(){return 1496}function lM(){return N1()|0}function sM(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(aM(r),_t(r)):n|0&&_t(n)}function aM(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function fM(e){e=e|0,Qa(e)}function cM(e,n){e=e|0,n=n|0;var r=0,u=0;Fv()|0,r=t[2652]|0;e:do if(r|0){for(;u=t[r+4>>2]|0,!(u|0?(I8(LE(u)|0,e)|0)==0:0);)if(r=t[r>>2]|0,!r)break e;dM(u,n)}while(0)}function LE(e){return e=e|0,t[e+12>>2]|0}function dM(e,n){e=e|0,n=n|0;var r=0;e=e+36|0,r=t[e>>2]|0,r|0&&(ca(r),_t(r)),r=pn(4)|0,Sf(r,n),t[e>>2]=r}function NE(){return c[11716]|0||(t[2664]=0,Vt(63,10656,ve|0)|0,c[11716]=1),10656}function n8(){var e=0;return c[11717]|0?e=t[2665]|0:(pM(),t[2665]=1504,c[11717]=1,e=1504),e|0}function pM(){c[11740]|0||(c[11718]=hn(hn(8,0)|0,0)|0,c[11719]=hn(hn(0,0)|0,0)|0,c[11720]=hn(hn(0,16)|0,0)|0,c[11721]=hn(hn(8,0)|0,0)|0,c[11722]=hn(hn(0,0)|0,0)|0,c[11723]=hn(hn(8,0)|0,0)|0,c[11724]=hn(hn(0,0)|0,0)|0,c[11725]=hn(hn(8,0)|0,0)|0,c[11726]=hn(hn(0,0)|0,0)|0,c[11727]=hn(hn(8,0)|0,0)|0,c[11728]=hn(hn(0,0)|0,0)|0,c[11729]=hn(hn(0,0)|0,32)|0,c[11730]=hn(hn(0,0)|0,32)|0,c[11740]=1)}function r8(){return 1572}function hM(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0,k=0;s=m,m=m+32|0,k=s+16|0,L=s+12|0,S=s+8|0,D=s+4|0,h=s,t[k>>2]=e,t[L>>2]=n,t[S>>2]=r,t[D>>2]=u,t[h>>2]=l,NE()|0,vM(10656,k,L,S,D,h),m=s}function vM(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0;h=pn(24)|0,gd(h+4|0,t[n>>2]|0,t[r>>2]|0,t[u>>2]|0,t[l>>2]|0,t[s>>2]|0),t[h>>2]=t[e>>2],t[e>>2]=h}function i8(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0,ft=0;if(ft=m,m=m+32|0,Te=ft+20|0,ye=ft+8|0,Ze=ft+4|0,Ge=ft,n=t[n>>2]|0,n|0){Be=Te+4|0,S=Te+8|0,L=ye+4|0,k=ye+8|0,I=ye+8|0,K=Te+8|0;do{if(h=n+4|0,D=FE(h)|0,D|0){if(l=Ay(D)|0,t[Te>>2]=0,t[Be>>2]=0,t[S>>2]=0,u=(Oy(D)|0)+1|0,mM(Te,u),u|0)for(;u=u+-1|0,Yf(ye,t[l>>2]|0),s=t[Be>>2]|0,s>>>0<(t[K>>2]|0)>>>0?(t[s>>2]=t[ye>>2],t[Be>>2]=(t[Be>>2]|0)+4):PE(Te,ye),u;)l=l+4|0;u=My(D)|0,t[ye>>2]=0,t[L>>2]=0,t[k>>2]=0;e:do if(t[u>>2]|0)for(l=0,s=0;;){if((l|0)==(s|0)?yM(ye,u):(t[l>>2]=t[u>>2],t[L>>2]=(t[L>>2]|0)+4),u=u+4|0,!(t[u>>2]|0))break e;l=t[L>>2]|0,s=t[I>>2]|0}while(0);t[Ze>>2]=E_(h)|0,t[Ge>>2]=sr(D)|0,gM(r,e,Ze,Ge,Te,ye),IE(ye),F1(Te)}n=t[n>>2]|0}while((n|0)!=0)}m=ft}function FE(e){return e=e|0,t[e+12>>2]|0}function Ay(e){return e=e|0,t[e+12>>2]|0}function Oy(e){return e=e|0,t[e+16>>2]|0}function mM(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;l=m,m=m+32|0,r=l,u=t[e>>2]|0,(t[e+8>>2]|0)-u>>2>>>0>>0&&(d8(r,n,(t[e+4>>2]|0)-u>>2,e+8|0),p8(e,r),h8(r)),m=l}function PE(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0;if(h=m,m=m+32|0,r=h,u=e+4|0,l=((t[u>>2]|0)-(t[e>>2]|0)>>2)+1|0,s=c8(e)|0,s>>>0>>0)hi(e);else{D=t[e>>2]|0,L=(t[e+8>>2]|0)-D|0,S=L>>1,d8(r,L>>2>>>0>>1>>>0?S>>>0>>0?l:S:s,(t[u>>2]|0)-D>>2,e+8|0),s=r+8|0,t[t[s>>2]>>2]=t[n>>2],t[s>>2]=(t[s>>2]|0)+4,p8(e,r),h8(r),m=h;return}}function My(e){return e=e|0,t[e+8>>2]|0}function yM(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0;if(h=m,m=m+32|0,r=h,u=e+4|0,l=((t[u>>2]|0)-(t[e>>2]|0)>>2)+1|0,s=f8(e)|0,s>>>0>>0)hi(e);else{D=t[e>>2]|0,L=(t[e+8>>2]|0)-D|0,S=L>>1,bM(r,L>>2>>>0>>1>>>0?S>>>0>>0?l:S:s,(t[u>>2]|0)-D>>2,e+8|0),s=r+8|0,t[t[s>>2]>>2]=t[n>>2],t[s>>2]=(t[s>>2]|0)+4,BM(e,r),UM(r),m=h;return}}function E_(e){return e=e|0,t[e>>2]|0}function gM(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,_M(e,n,r,u,l,s)}function IE(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-4-u|0)>>>2)<<2)),_t(r))}function F1(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-4-u|0)>>>2)<<2)),_t(r))}function _M(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0,S=0,L=0,k=0,I=0;h=m,m=m+48|0,k=h+40|0,D=h+32|0,I=h+24|0,S=h+12|0,L=h,ka(D),e=g0(e)|0,t[I>>2]=t[n>>2],r=t[r>>2]|0,u=t[u>>2]|0,bE(S,l),EM(L,s),t[k>>2]=t[I>>2],DM(e,k,r,u,S,L),IE(L),F1(S),La(D),m=h}function bE(e,n){e=e|0,n=n|0;var r=0,u=0;t[e>>2]=0,t[e+4>>2]=0,t[e+8>>2]=0,r=n+4|0,u=(t[r>>2]|0)-(t[n>>2]|0)>>2,u|0&&(PM(e,u),IM(e,t[n>>2]|0,t[r>>2]|0,u))}function EM(e,n){e=e|0,n=n|0;var r=0,u=0;t[e>>2]=0,t[e+4>>2]=0,t[e+8>>2]=0,r=n+4|0,u=(t[r>>2]|0)-(t[n>>2]|0)>>2,u|0&&(NM(e,u),FM(e,t[n>>2]|0,t[r>>2]|0,u))}function DM(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0,S=0,L=0,k=0,I=0;h=m,m=m+32|0,k=h+28|0,I=h+24|0,D=h+12|0,S=h,L=_0(wM()|0)|0,t[I>>2]=t[n>>2],t[k>>2]=t[I>>2],n=Kp(k)|0,r=u8(r)|0,u=BE(u)|0,t[D>>2]=t[l>>2],k=l+4|0,t[D+4>>2]=t[k>>2],I=l+8|0,t[D+8>>2]=t[I>>2],t[I>>2]=0,t[k>>2]=0,t[l>>2]=0,l=UE(D)|0,t[S>>2]=t[s>>2],k=s+4|0,t[S+4>>2]=t[k>>2],I=s+8|0,t[S+8>>2]=t[I>>2],t[I>>2]=0,t[k>>2]=0,t[s>>2]=0,Qo(0,L|0,e|0,n|0,r|0,u|0,l|0,SM(S)|0)|0,IE(S),F1(D),m=h}function wM(){var e=0;return c[7968]|0||(kM(10708),e=7968,t[e>>2]=1,t[e+4>>2]=0),10708}function Kp(e){return e=e|0,l8(e)|0}function u8(e){return e=e|0,o8(e)|0}function BE(e){return e=e|0,qo(e)|0}function UE(e){return e=e|0,CM(e)|0}function SM(e){return e=e|0,TM(e)|0}function TM(e){e=e|0;var n=0,r=0,u=0;if(u=(t[e+4>>2]|0)-(t[e>>2]|0)|0,r=u>>2,u=Ma(u+4|0)|0,t[u>>2]=r,r|0){n=0;do t[u+4+(n<<2)>>2]=o8(t[(t[e>>2]|0)+(n<<2)>>2]|0)|0,n=n+1|0;while((n|0)!=(r|0))}return u|0}function o8(e){return e=e|0,e|0}function CM(e){e=e|0;var n=0,r=0,u=0;if(u=(t[e+4>>2]|0)-(t[e>>2]|0)|0,r=u>>2,u=Ma(u+4|0)|0,t[u>>2]=r,r|0){n=0;do t[u+4+(n<<2)>>2]=l8((t[e>>2]|0)+(n<<2)|0)|0,n=n+1|0;while((n|0)!=(r|0))}return u|0}function l8(e){e=e|0;var n=0,r=0,u=0,l=0;return l=m,m=m+32|0,n=l+12|0,r=l,u=Iu(s8()|0)|0,u?(is(n,u),kf(r,n),sF(e,r),e=xs(n)|0):e=xM(e)|0,m=l,e|0}function s8(){var e=0;return c[7960]|0||(MM(10664),Vt(25,10664,ve|0)|0,e=7960,t[e>>2]=1,t[e+4>>2]=0),10664}function xM(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0;return r=m,m=m+16|0,l=r+4|0,h=r,u=Ma(8)|0,n=u,D=pn(4)|0,t[D>>2]=t[e>>2],s=n+4|0,t[s>>2]=D,e=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],a8(e,s,l),t[u>>2]=e,m=r,n|0}function a8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,r=pn(16)|0,t[r+4>>2]=0,t[r+8>>2]=0,t[r>>2]=1656,t[r+12>>2]=n,t[e+4>>2]=r}function RM(e){e=e|0,Uv(e),_t(e)}function AM(e){e=e|0,e=t[e+12>>2]|0,e|0&&_t(e)}function OM(e){e=e|0,_t(e)}function MM(e){e=e|0,Qa(e)}function kM(e){e=e|0,ll(e,LM()|0,5)}function LM(){return 1676}function NM(e,n){e=e|0,n=n|0;var r=0;if((f8(e)|0)>>>0>>0&&hi(e),n>>>0>1073741823)$n();else{r=pn(n<<2)|0,t[e+4>>2]=r,t[e>>2]=r,t[e+8>>2]=r+(n<<2);return}}function FM(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,u=e+4|0,e=r-n|0,(e|0)>0&&(gr(t[u>>2]|0,n|0,e|0)|0,t[u>>2]=(t[u>>2]|0)+(e>>>2<<2))}function f8(e){return e=e|0,1073741823}function PM(e,n){e=e|0,n=n|0;var r=0;if((c8(e)|0)>>>0>>0&&hi(e),n>>>0>1073741823)$n();else{r=pn(n<<2)|0,t[e+4>>2]=r,t[e>>2]=r,t[e+8>>2]=r+(n<<2);return}}function IM(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,u=e+4|0,e=r-n|0,(e|0)>0&&(gr(t[u>>2]|0,n|0,e|0)|0,t[u>>2]=(t[u>>2]|0)+(e>>>2<<2))}function c8(e){return e=e|0,1073741823}function bM(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>1073741823)$n();else{l=pn(n<<2)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<2)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<2)}function BM(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>2)<<2)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function UM(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-4-n|0)>>>2)<<2)),e=t[e>>2]|0,e|0&&_t(e)}function d8(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>1073741823)$n();else{l=pn(n<<2)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<2)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<2)}function p8(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>2)<<2)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function h8(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-4-n|0)>>>2)<<2)),e=t[e>>2]|0,e|0&&_t(e)}function jM(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0;if(ye=m,m=m+32|0,k=ye+20|0,I=ye+12|0,L=ye+16|0,K=ye+4|0,Be=ye,Te=ye+8|0,D=n8()|0,s=t[D>>2]|0,h=t[s>>2]|0,h|0)for(S=t[D+8>>2]|0,D=t[D+4>>2]|0;Yf(k,h),zM(e,k,D,S),s=s+4|0,h=t[s>>2]|0,h;)S=S+1|0,D=D+1|0;if(s=r8()|0,h=t[s>>2]|0,h|0)do Yf(k,h),t[I>>2]=t[s+4>>2],HM(n,k,I),s=s+8|0,h=t[s>>2]|0;while((h|0)!=0);if(s=t[(Fv()|0)>>2]|0,s|0)do n=t[s+4>>2]|0,Yf(k,t[(Pv(n)|0)>>2]|0),t[I>>2]=LE(n)|0,qM(r,k,I),s=t[s>>2]|0;while((s|0)!=0);if(Yf(L,0),s=NE()|0,t[k>>2]=t[L>>2],i8(k,s,l),s=t[(Fv()|0)>>2]|0,s|0){e=k+4|0,n=k+8|0,r=k+8|0;do{if(S=t[s+4>>2]|0,Yf(I,t[(Pv(S)|0)>>2]|0),WM(K,v8(S)|0),h=t[K>>2]|0,h|0){t[k>>2]=0,t[e>>2]=0,t[n>>2]=0;do Yf(Be,t[(Pv(t[h+4>>2]|0)|0)>>2]|0),D=t[e>>2]|0,D>>>0<(t[r>>2]|0)>>>0?(t[D>>2]=t[Be>>2],t[e>>2]=(t[e>>2]|0)+4):PE(k,Be),h=t[h>>2]|0;while((h|0)!=0);VM(u,I,k),F1(k)}t[Te>>2]=t[I>>2],L=m8(S)|0,t[k>>2]=t[Te>>2],i8(k,L,l),Ed(K),s=t[s>>2]|0}while((s|0)!=0)}m=ye}function zM(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,rk(e,n,r,u)}function HM(e,n,r){e=e|0,n=n|0,r=r|0,nk(e,n,r)}function Pv(e){return e=e|0,e|0}function qM(e,n,r){e=e|0,n=n|0,r=r|0,ZM(e,n,r)}function v8(e){return e=e|0,e+16|0}function WM(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;if(s=m,m=m+16|0,l=s+8|0,r=s,t[e>>2]=0,u=t[n>>2]|0,t[l>>2]=u,t[r>>2]=e,r=JM(r)|0,u|0){if(u=pn(12)|0,h=(y8(l)|0)+4|0,e=t[h+4>>2]|0,n=u+4|0,t[n>>2]=t[h>>2],t[n+4>>2]=e,n=t[t[l>>2]>>2]|0,t[l>>2]=n,!n)e=u;else for(n=u;e=pn(12)|0,S=(y8(l)|0)+4|0,D=t[S+4>>2]|0,h=e+4|0,t[h>>2]=t[S>>2],t[h+4>>2]=D,t[n>>2]=e,h=t[t[l>>2]>>2]|0,t[l>>2]=h,h;)n=e;t[e>>2]=t[r>>2],t[r>>2]=u}m=s}function VM(e,n,r){e=e|0,n=n|0,r=r|0,GM(e,n,r)}function m8(e){return e=e|0,e+24|0}function GM(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+32|0,h=u+24|0,l=u+16|0,D=u+12|0,s=u,ka(l),e=g0(e)|0,t[D>>2]=t[n>>2],bE(s,r),t[h>>2]=t[D>>2],YM(e,h,s),F1(s),La(l),m=u}function YM(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=m,m=m+32|0,h=u+16|0,D=u+12|0,l=u,s=_0(KM()|0)|0,t[D>>2]=t[n>>2],t[h>>2]=t[D>>2],n=Kp(h)|0,t[l>>2]=t[r>>2],h=r+4|0,t[l+4>>2]=t[h>>2],D=r+8|0,t[l+8>>2]=t[D>>2],t[D>>2]=0,t[h>>2]=0,t[r>>2]=0,Io(0,s|0,e|0,n|0,UE(l)|0)|0,F1(l),m=u}function KM(){var e=0;return c[7976]|0||(XM(10720),e=7976,t[e>>2]=1,t[e+4>>2]=0),10720}function XM(e){e=e|0,ll(e,QM()|0,2)}function QM(){return 1732}function JM(e){return e=e|0,t[e>>2]|0}function y8(e){return e=e|0,t[e>>2]|0}function ZM(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+32|0,s=u+16|0,l=u+8|0,h=u,ka(l),e=g0(e)|0,t[h>>2]=t[n>>2],r=t[r>>2]|0,t[s>>2]=t[h>>2],g8(e,s,r),La(l),m=u}function g8(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+16|0,s=u+4|0,h=u,l=_0($M()|0)|0,t[h>>2]=t[n>>2],t[s>>2]=t[h>>2],n=Kp(s)|0,Io(0,l|0,e|0,n|0,u8(r)|0)|0,m=u}function $M(){var e=0;return c[7984]|0||(ek(10732),e=7984,t[e>>2]=1,t[e+4>>2]=0),10732}function ek(e){e=e|0,ll(e,tk()|0,2)}function tk(){return 1744}function nk(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;u=m,m=m+32|0,s=u+16|0,l=u+8|0,h=u,ka(l),e=g0(e)|0,t[h>>2]=t[n>>2],r=t[r>>2]|0,t[s>>2]=t[h>>2],g8(e,s,r),La(l),m=u}function rk(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+32|0,h=l+16|0,s=l+8|0,D=l,ka(s),e=g0(e)|0,t[D>>2]=t[n>>2],r=c[r>>0]|0,u=c[u>>0]|0,t[h>>2]=t[D>>2],ik(e,h,r,u),La(s),m=l}function ik(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+16|0,h=l+4|0,D=l,s=_0(uk()|0)|0,t[D>>2]=t[n>>2],t[h>>2]=t[D>>2],n=Kp(h)|0,r=Iv(r)|0,Hn(0,s|0,e|0,n|0,r|0,Iv(u)|0)|0,m=l}function uk(){var e=0;return c[7992]|0||(lk(10744),e=7992,t[e>>2]=1,t[e+4>>2]=0),10744}function Iv(e){return e=e|0,ok(e)|0}function ok(e){return e=e|0,e&255|0}function lk(e){e=e|0,ll(e,sk()|0,3)}function sk(){return 1756}function ak(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;switch(K=m,m=m+32|0,D=K+8|0,S=K+4|0,L=K+20|0,k=K,Ta(e,0),u=lF(n)|0,t[D>>2]=0,I=D+4|0,t[I>>2]=0,t[D+8>>2]=0,u<<24>>24){case 0:{c[L>>0]=0,fk(S,r,L),D_(e,S)|0,jo(S);break}case 8:{I=VE(n)|0,c[L>>0]=8,Yf(k,t[I+4>>2]|0),ck(S,r,L,k,I+8|0),D_(e,S)|0,jo(S);break}case 9:{if(s=VE(n)|0,n=t[s+4>>2]|0,n|0)for(h=D+8|0,l=s+12|0;n=n+-1|0,Yf(S,t[l>>2]|0),u=t[I>>2]|0,u>>>0<(t[h>>2]|0)>>>0?(t[u>>2]=t[S>>2],t[I>>2]=(t[I>>2]|0)+4):PE(D,S),n;)l=l+4|0;c[L>>0]=9,Yf(k,t[s+8>>2]|0),dk(S,r,L,k,D),D_(e,S)|0,jo(S);break}default:I=VE(n)|0,c[L>>0]=u,Yf(k,t[I+4>>2]|0),pk(S,r,L,k),D_(e,S)|0,jo(S)}F1(D),m=K}function fk(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;u=m,m=m+16|0,l=u,ka(l),n=g0(n)|0,xk(e,n,c[r>>0]|0),La(l),m=u}function D_(e,n){e=e|0,n=n|0;var r=0;return r=t[e>>2]|0,r|0&&qr(r|0),t[e>>2]=t[n>>2],t[n>>2]=0,e|0}function ck(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0;s=m,m=m+32|0,D=s+16|0,h=s+8|0,S=s,ka(h),n=g0(n)|0,r=c[r>>0]|0,t[S>>2]=t[u>>2],l=t[l>>2]|0,t[D>>2]=t[S>>2],wk(e,n,r,D,l),La(h),m=s}function dk(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0;s=m,m=m+32|0,S=s+24|0,h=s+16|0,L=s+12|0,D=s,ka(h),n=g0(n)|0,r=c[r>>0]|0,t[L>>2]=t[u>>2],bE(D,l),t[S>>2]=t[L>>2],gk(e,n,r,S,D),F1(D),La(h),m=s}function pk(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+32|0,h=l+16|0,s=l+8|0,D=l,ka(s),n=g0(n)|0,r=c[r>>0]|0,t[D>>2]=t[u>>2],t[h>>2]=t[D>>2],hk(e,n,r,h),La(s),m=l}function hk(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0,h=0,D=0;l=m,m=m+16|0,s=l+4|0,D=l,h=_0(vk()|0)|0,r=Iv(r)|0,t[D>>2]=t[u>>2],t[s>>2]=t[D>>2],w_(e,Io(0,h|0,n|0,r|0,Kp(s)|0)|0),m=l}function vk(){var e=0;return c[8e3]|0||(mk(10756),e=8e3,t[e>>2]=1,t[e+4>>2]=0),10756}function w_(e,n){e=e|0,n=n|0,Ta(e,n)}function mk(e){e=e|0,ll(e,yk()|0,2)}function yk(){return 1772}function gk(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0;s=m,m=m+32|0,S=s+16|0,L=s+12|0,h=s,D=_0(_k()|0)|0,r=Iv(r)|0,t[L>>2]=t[u>>2],t[S>>2]=t[L>>2],u=Kp(S)|0,t[h>>2]=t[l>>2],S=l+4|0,t[h+4>>2]=t[S>>2],L=l+8|0,t[h+8>>2]=t[L>>2],t[L>>2]=0,t[S>>2]=0,t[l>>2]=0,w_(e,Hn(0,D|0,n|0,r|0,u|0,UE(h)|0)|0),F1(h),m=s}function _k(){var e=0;return c[8008]|0||(Ek(10768),e=8008,t[e>>2]=1,t[e+4>>2]=0),10768}function Ek(e){e=e|0,ll(e,Dk()|0,3)}function Dk(){return 1784}function wk(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0;s=m,m=m+16|0,D=s+4|0,S=s,h=_0(Sk()|0)|0,r=Iv(r)|0,t[S>>2]=t[u>>2],t[D>>2]=t[S>>2],u=Kp(D)|0,w_(e,Hn(0,h|0,n|0,r|0,u|0,BE(l)|0)|0),m=s}function Sk(){var e=0;return c[8016]|0||(Tk(10780),e=8016,t[e>>2]=1,t[e+4>>2]=0),10780}function Tk(e){e=e|0,ll(e,Ck()|0,3)}function Ck(){return 1800}function xk(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;u=_0(Rk()|0)|0,w_(e,Ki(0,u|0,n|0,Iv(r)|0)|0)}function Rk(){var e=0;return c[8024]|0||(Ak(10792),e=8024,t[e>>2]=1,t[e+4>>2]=0),10792}function Ak(e){e=e|0,ll(e,Ok()|0,1)}function Ok(){return 1816}function Mk(){kk(),Lk(),Nk()}function kk(){t[2702]=G8(65536)|0}function Lk(){$k(10856)}function Nk(){Fk(10816)}function Fk(e){e=e|0,Pk(e,5044),Ik(e)|0}function Pk(e,n){e=e|0,n=n|0;var r=0;r=s8()|0,t[e>>2]=r,Yk(r,n),e2(t[e>>2]|0)}function Ik(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,bk()|0),e|0}function bk(){var e=0;return c[8032]|0||(_8(10820),Vt(64,10820,ve|0)|0,e=8032,t[e>>2]=1,t[e+4>>2]=0),sr(10820)|0||_8(10820),10820}function _8(e){e=e|0,jk(e),Yp(e,25)}function Bk(e){e=e|0,Uk(e+24|0)}function Uk(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function jk(e){e=e|0;var n=0;n=yr()|0,jn(e,5,18,n,Wk()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function zk(e,n){e=e|0,n=n|0,Hk(e,n)}function Hk(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;r=m,m=m+16|0,u=r,l=r+4|0,If(l,n),t[u>>2]=bf(l,n)|0,qk(e,u),m=r}function qk(e,n){e=e|0,n=n|0,E8(e+4|0,t[n>>2]|0),c[e+8>>0]=1}function E8(e,n){e=e|0,n=n|0,t[e>>2]=n}function Wk(){return 1824}function Vk(e){return e=e|0,Gk(e)|0}function Gk(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0;return r=m,m=m+16|0,l=r+4|0,h=r,u=Ma(8)|0,n=u,D=pn(4)|0,If(l,e),E8(D,bf(l,e)|0),s=n+4|0,t[s>>2]=D,e=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],a8(e,s,l),t[u>>2]=e,m=r,n|0}function Ma(e){e=e|0;var n=0,r=0;return e=e+7&-8,(e>>>0<=32768?(n=t[2701]|0,e>>>0<=(65536-n|0)>>>0):0)?(r=(t[2702]|0)+n|0,t[2701]=n+e,e=r):(e=G8(e+8|0)|0,t[e>>2]=t[2703],t[2703]=e,e=e+8|0),e|0}function Yk(e,n){e=e|0,n=n|0,t[e>>2]=Kk()|0,t[e+4>>2]=Xk()|0,t[e+12>>2]=n,t[e+8>>2]=Qk()|0,t[e+32>>2]=9}function Kk(){return 11744}function Xk(){return 1832}function Qk(){return __()|0}function Jk(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(Zk(r),_t(r)):n|0&&_t(n)}function Zk(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function $k(e){e=e|0,eL(e,5052),tL(e)|0,nL(e,5058,26)|0,rL(e,5069,1)|0,iL(e,5077,10)|0,uL(e,5087,19)|0,oL(e,5094,27)|0}function eL(e,n){e=e|0,n=n|0;var r=0;r=$N()|0,t[e>>2]=r,eF(r,n),e2(t[e>>2]|0)}function tL(e){e=e|0;var n=0;return n=t[e>>2]|0,Gp(n,UN()|0),e|0}function nL(e,n,r){return e=e|0,n=n|0,r=r|0,DN(e,Fr(n)|0,r,0),e|0}function rL(e,n,r){return e=e|0,n=n|0,r=r|0,oN(e,Fr(n)|0,r,0),e|0}function iL(e,n,r){return e=e|0,n=n|0,r=r|0,bL(e,Fr(n)|0,r,0),e|0}function uL(e,n,r){return e=e|0,n=n|0,r=r|0,wL(e,Fr(n)|0,r,0),e|0}function D8(e,n){e=e|0,n=n|0;var r=0,u=0;e:for(;;){for(r=t[2703]|0;;){if((r|0)==(n|0))break e;if(u=t[r>>2]|0,t[2703]=u,!r)r=u;else break}_t(r)}t[2701]=e}function oL(e,n,r){return e=e|0,n=n|0,r=r|0,lL(e,Fr(n)|0,r,0),e|0}function lL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=jE()|0,e=sL(r)|0,wi(s,n,l,e,aL(r,u)|0,u)}function jE(){var e=0,n=0;if(c[8040]|0||(S8(10860),Vt(65,10860,ve|0)|0,n=8040,t[n>>2]=1,t[n+4>>2]=0),!(sr(10860)|0)){e=10860,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));S8(10860)}return 10860}function sL(e){return e=e|0,e|0}function aL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=jE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(w8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(fL(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function w8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function fL(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=cL(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,dL(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,w8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,pL(e,l),hL(l),m=D;return}}function cL(e){return e=e|0,536870911}function dL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function pL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function hL(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function S8(e){e=e|0,yL(e)}function vL(e){e=e|0,mL(e+24|0)}function mL(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function yL(e){e=e|0;var n=0;n=yr()|0,jn(e,1,11,n,gL()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function gL(){return 1840}function _L(e,n,r){e=e|0,n=n|0,r=r|0,DL(t[(EL(e)|0)>>2]|0,n,r)}function EL(e){return e=e|0,(t[(jE()|0)+24>>2]|0)+(e<<3)|0}function DL(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;u=m,m=m+16|0,s=u+1|0,l=u,If(s,n),n=bf(s,n)|0,If(l,r),r=bf(l,r)|0,I1[e&31](n,r),m=u}function wL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=zE()|0,e=SL(r)|0,wi(s,n,l,e,TL(r,u)|0,u)}function zE(){var e=0,n=0;if(c[8048]|0||(C8(10896),Vt(66,10896,ve|0)|0,n=8048,t[n>>2]=1,t[n+4>>2]=0),!(sr(10896)|0)){e=10896,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));C8(10896)}return 10896}function SL(e){return e=e|0,e|0}function TL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=zE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(T8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(CL(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function T8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function CL(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=xL(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,RL(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,T8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,AL(e,l),OL(l),m=D;return}}function xL(e){return e=e|0,536870911}function RL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function AL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function OL(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function C8(e){e=e|0,LL(e)}function ML(e){e=e|0,kL(e+24|0)}function kL(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function LL(e){e=e|0;var n=0;n=yr()|0,jn(e,1,11,n,NL()|0,1),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function NL(){return 1852}function FL(e,n){return e=e|0,n=n|0,IL(t[(PL(e)|0)>>2]|0,n)|0}function PL(e){return e=e|0,(t[(zE()|0)+24>>2]|0)+(e<<3)|0}function IL(e,n){e=e|0,n=n|0;var r=0,u=0;return r=m,m=m+16|0,u=r,If(u,n),n=bf(u,n)|0,n=qo(Zp[e&31](n)|0)|0,m=r,n|0}function bL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=HE()|0,e=BL(r)|0,wi(s,n,l,e,UL(r,u)|0,u)}function HE(){var e=0,n=0;if(c[8056]|0||(R8(10932),Vt(67,10932,ve|0)|0,n=8056,t[n>>2]=1,t[n+4>>2]=0),!(sr(10932)|0)){e=10932,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));R8(10932)}return 10932}function BL(e){return e=e|0,e|0}function UL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=HE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(x8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(jL(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function x8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function jL(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=zL(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,HL(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,x8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,qL(e,l),WL(l),m=D;return}}function zL(e){return e=e|0,536870911}function HL(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function qL(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function WL(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function R8(e){e=e|0,KL(e)}function VL(e){e=e|0,YL(e+24|0)}function YL(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function KL(e){e=e|0;var n=0;n=yr()|0,jn(e,1,7,n,XL()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function XL(){return 1860}function QL(e,n,r){return e=e|0,n=n|0,r=r|0,ZL(t[(JL(e)|0)>>2]|0,n,r)|0}function JL(e){return e=e|0,(t[(HE()|0)+24>>2]|0)+(e<<3)|0}function ZL(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0;return u=m,m=m+32|0,h=u+12|0,s=u+8|0,D=u,S=u+16|0,l=u+4|0,$L(S,n),eN(D,S,n),Ks(l,r),r=Xs(l,r)|0,t[h>>2]=t[D>>2],Fy[e&15](s,h,r),r=tN(s)|0,jo(s),Qs(l),m=u,r|0}function $L(e,n){e=e|0,n=n|0}function eN(e,n,r){e=e|0,n=n|0,r=r|0,nN(e,r)}function tN(e){return e=e|0,g0(e)|0}function nN(e,n){e=e|0,n=n|0;var r=0,u=0,l=0;l=m,m=m+16|0,r=l,u=n,u&1?(rN(r,0),eu(u|0,r|0)|0,iN(e,r),uN(r)):t[e>>2]=t[n>>2],m=l}function rN(e,n){e=e|0,n=n|0,cd(e,n),t[e+4>>2]=0,c[e+8>>0]=0}function iN(e,n){e=e|0,n=n|0,t[e>>2]=t[n+4>>2]}function uN(e){e=e|0,c[e+8>>0]=0}function oN(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=qE()|0,e=lN(r)|0,wi(s,n,l,e,sN(r,u)|0,u)}function qE(){var e=0,n=0;if(c[8064]|0||(O8(10968),Vt(68,10968,ve|0)|0,n=8064,t[n>>2]=1,t[n+4>>2]=0),!(sr(10968)|0)){e=10968,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));O8(10968)}return 10968}function lN(e){return e=e|0,e|0}function sN(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=qE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(A8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(aN(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function A8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function aN(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=fN(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,cN(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,A8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,dN(e,l),pN(l),m=D;return}}function fN(e){return e=e|0,536870911}function cN(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function dN(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function pN(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function O8(e){e=e|0,mN(e)}function hN(e){e=e|0,vN(e+24|0)}function vN(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function mN(e){e=e|0;var n=0;n=yr()|0,jn(e,1,1,n,yN()|0,5),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function yN(){return 1872}function gN(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,EN(t[(_N(e)|0)>>2]|0,n,r,u,l,s)}function _N(e){return e=e|0,(t[(qE()|0)+24>>2]|0)+(e<<3)|0}function EN(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0,S=0,L=0,k=0,I=0;h=m,m=m+32|0,D=h+16|0,S=h+12|0,L=h+8|0,k=h+4|0,I=h,Ks(D,n),n=Xs(D,n)|0,Ks(S,r),r=Xs(S,r)|0,Ks(L,u),u=Xs(L,u)|0,Ks(k,l),l=Xs(k,l)|0,Ks(I,s),s=Xs(I,s)|0,J8[e&1](n,r,u,l,s),Qs(I),Qs(k),Qs(L),Qs(S),Qs(D),m=h}function DN(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;s=t[e>>2]|0,l=WE()|0,e=wN(r)|0,wi(s,n,l,e,SN(r,u)|0,u)}function WE(){var e=0,n=0;if(c[8072]|0||(k8(11004),Vt(69,11004,ve|0)|0,n=8072,t[n>>2]=1,t[n+4>>2]=0),!(sr(11004)|0)){e=11004,n=e+36|0;do t[e>>2]=0,e=e+4|0;while((e|0)<(n|0));k8(11004)}return 11004}function wN(e){return e=e|0,e|0}function SN(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0,D=0,S=0;return D=m,m=m+16|0,l=D,s=D+4|0,t[l>>2]=e,S=WE()|0,h=S+24|0,n=hn(n,4)|0,t[s>>2]=n,r=S+28|0,u=t[r>>2]|0,u>>>0<(t[S+32>>2]|0)>>>0?(M8(u,e,n),n=(t[r>>2]|0)+8|0,t[r>>2]=n):(TN(h,l,s),n=t[r>>2]|0),m=D,(n-(t[h>>2]|0)>>3)+-1|0}function M8(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,t[e+4>>2]=r}function TN(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0;if(D=m,m=m+32|0,l=D,s=e+4|0,h=((t[s>>2]|0)-(t[e>>2]|0)>>3)+1|0,u=CN(e)|0,u>>>0>>0)hi(e);else{S=t[e>>2]|0,k=(t[e+8>>2]|0)-S|0,L=k>>2,xN(l,k>>3>>>0>>1>>>0?L>>>0>>0?h:L:u,(t[s>>2]|0)-S>>3,e+8|0),h=l+8|0,M8(t[h>>2]|0,t[n>>2]|0,t[r>>2]|0),t[h>>2]=(t[h>>2]|0)+8,RN(e,l),AN(l),m=D;return}}function CN(e){return e=e|0,536870911}function xN(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0;t[e+12>>2]=0,t[e+16>>2]=u;do if(n)if(n>>>0>536870911)$n();else{l=pn(n<<3)|0;break}else l=0;while(0);t[e>>2]=l,u=l+(r<<3)|0,t[e+8>>2]=u,t[e+4>>2]=u,t[e+12>>2]=l+(n<<3)}function RN(e,n){e=e|0,n=n|0;var r=0,u=0,l=0,s=0,h=0;u=t[e>>2]|0,h=e+4|0,s=n+4|0,l=(t[h>>2]|0)-u|0,r=(t[s>>2]|0)+(0-(l>>3)<<3)|0,t[s>>2]=r,(l|0)>0?(gr(r|0,u|0,l|0)|0,u=s,r=t[s>>2]|0):u=s,s=t[e>>2]|0,t[e>>2]=r,t[u>>2]=s,s=n+8|0,l=t[h>>2]|0,t[h>>2]=t[s>>2],t[s>>2]=l,s=e+8|0,h=n+12|0,e=t[s>>2]|0,t[s>>2]=t[h>>2],t[h>>2]=e,t[n>>2]=t[u>>2]}function AN(e){e=e|0;var n=0,r=0,u=0;n=t[e+4>>2]|0,r=e+8|0,u=t[r>>2]|0,(u|0)!=(n|0)&&(t[r>>2]=u+(~((u+-8-n|0)>>>3)<<3)),e=t[e>>2]|0,e|0&&_t(e)}function k8(e){e=e|0,kN(e)}function ON(e){e=e|0,MN(e+24|0)}function MN(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function kN(e){e=e|0;var n=0;n=yr()|0,jn(e,1,12,n,LN()|0,2),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function LN(){return 1896}function NN(e,n,r){e=e|0,n=n|0,r=r|0,PN(t[(FN(e)|0)>>2]|0,n,r)}function FN(e){return e=e|0,(t[(WE()|0)+24>>2]|0)+(e<<3)|0}function PN(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;u=m,m=m+16|0,s=u+4|0,l=u,IN(s,n),n=bN(s,n)|0,Ks(l,r),r=Xs(l,r)|0,I1[e&31](n,r),Qs(l),m=u}function IN(e,n){e=e|0,n=n|0}function bN(e,n){return e=e|0,n=n|0,BN(n)|0}function BN(e){return e=e|0,e|0}function UN(){var e=0;return c[8080]|0||(L8(11040),Vt(70,11040,ve|0)|0,e=8080,t[e>>2]=1,t[e+4>>2]=0),sr(11040)|0||L8(11040),11040}function L8(e){e=e|0,HN(e),Yp(e,71)}function jN(e){e=e|0,zN(e+24|0)}function zN(e){e=e|0;var n=0,r=0,u=0;r=t[e>>2]|0,u=r,r|0&&(e=e+4|0,n=t[e>>2]|0,(n|0)!=(r|0)&&(t[e>>2]=n+(~((n+-8-u|0)>>>3)<<3)),_t(r))}function HN(e){e=e|0;var n=0;n=yr()|0,jn(e,5,7,n,GN()|0,0),t[e+24>>2]=0,t[e+28>>2]=0,t[e+32>>2]=0}function qN(e){e=e|0,WN(e)}function WN(e){e=e|0,VN(e)}function VN(e){e=e|0,c[e+8>>0]=1}function GN(){return 1936}function YN(){return KN()|0}function KN(){var e=0,n=0,r=0,u=0,l=0,s=0,h=0;return n=m,m=m+16|0,l=n+4|0,h=n,r=Ma(8)|0,e=r,s=e+4|0,t[s>>2]=pn(1)|0,u=pn(8)|0,s=t[s>>2]|0,t[h>>2]=0,t[l>>2]=t[h>>2],XN(u,s,l),t[r>>2]=u,m=n,e|0}function XN(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]=n,r=pn(16)|0,t[r+4>>2]=0,t[r+8>>2]=0,t[r>>2]=1916,t[r+12>>2]=n,t[e+4>>2]=r}function QN(e){e=e|0,Uv(e),_t(e)}function JN(e){e=e|0,e=t[e+12>>2]|0,e|0&&_t(e)}function ZN(e){e=e|0,_t(e)}function $N(){var e=0;return c[8088]|0||(oF(11076),Vt(25,11076,ve|0)|0,e=8088,t[e>>2]=1,t[e+4>>2]=0),11076}function eF(e,n){e=e|0,n=n|0,t[e>>2]=tF()|0,t[e+4>>2]=nF()|0,t[e+12>>2]=n,t[e+8>>2]=rF()|0,t[e+32>>2]=10}function tF(){return 11745}function nF(){return 1940}function rF(){return N1()|0}function iF(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,(Hl(u,896)|0)==512?r|0&&(uF(r),_t(r)):n|0&&_t(n)}function uF(e){e=e|0,e=t[e+4>>2]|0,e|0&&t2(e)}function oF(e){e=e|0,Qa(e)}function Yf(e,n){e=e|0,n=n|0,t[e>>2]=n}function VE(e){return e=e|0,t[e>>2]|0}function lF(e){return e=e|0,c[t[e>>2]>>0]|0}function sF(e,n){e=e|0,n=n|0;var r=0,u=0;r=m,m=m+16|0,u=r,t[u>>2]=t[e>>2],aF(n,u)|0,m=r}function aF(e,n){e=e|0,n=n|0;var r=0;return r=fF(t[e>>2]|0,n)|0,n=e+4|0,t[(t[n>>2]|0)+8>>2]=r,t[(t[n>>2]|0)+8>>2]|0}function fF(e,n){e=e|0,n=n|0;var r=0,u=0;return r=m,m=m+16|0,u=r,ka(u),e=g0(e)|0,n=cF(e,t[n>>2]|0)|0,La(u),m=r,n|0}function ka(e){e=e|0,t[e>>2]=t[2701],t[e+4>>2]=t[2703]}function cF(e,n){e=e|0,n=n|0;var r=0;return r=_0(dF()|0)|0,Ki(0,r|0,e|0,BE(n)|0)|0}function La(e){e=e|0,D8(t[e>>2]|0,t[e+4>>2]|0)}function dF(){var e=0;return c[8096]|0||(pF(11120),e=8096,t[e>>2]=1,t[e+4>>2]=0),11120}function pF(e){e=e|0,ll(e,hF()|0,1)}function hF(){return 1948}function vF(){mF()}function mF(){var e=0,n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0;if(Te=m,m=m+16|0,k=Te+4|0,I=Te,bn(65536,10804,t[2702]|0,10812),r=n8()|0,n=t[r>>2]|0,e=t[n>>2]|0,e|0)for(u=t[r+8>>2]|0,r=t[r+4>>2]|0;Ql(e|0,M[r>>0]|0|0,c[u>>0]|0),n=n+4|0,e=t[n>>2]|0,e;)u=u+1|0,r=r+1|0;if(e=r8()|0,n=t[e>>2]|0,n|0)do k0(n|0,t[e+4>>2]|0),e=e+8|0,n=t[e>>2]|0;while((n|0)!=0);k0(yF()|0,5167),L=Fv()|0,e=t[L>>2]|0;e:do if(e|0){do gF(t[e+4>>2]|0),e=t[e>>2]|0;while((e|0)!=0);if(e=t[L>>2]|0,e|0){S=L;do{for(;l=e,e=t[e>>2]|0,l=t[l+4>>2]|0,!!(_F(l)|0);)if(t[I>>2]=S,t[k>>2]=t[I>>2],EF(L,k)|0,!e)break e;if(DF(l),S=t[S>>2]|0,n=N8(l)|0,s=c0()|0,h=m,m=m+((1*(n<<2)|0)+15&-16)|0,D=m,m=m+((1*(n<<2)|0)+15&-16)|0,n=t[(v8(l)|0)>>2]|0,n|0)for(r=h,u=D;t[r>>2]=t[(Pv(t[n+4>>2]|0)|0)>>2],t[u>>2]=t[n+8>>2],n=t[n>>2]|0,n;)r=r+4|0,u=u+4|0;ye=Pv(l)|0,n=wF(l)|0,r=N8(l)|0,u=SF(l)|0,L0(ye|0,n|0,h|0,D|0,r|0,u|0,LE(l)|0),gi(s|0)}while((e|0)!=0)}}while(0);if(e=t[(NE()|0)>>2]|0,e|0)do ye=e+4|0,L=FE(ye)|0,l=My(L)|0,s=Ay(L)|0,h=(Oy(L)|0)+1|0,D=S_(L)|0,S=F8(ye)|0,L=sr(L)|0,k=E_(ye)|0,I=GE(ye)|0,f0(0,l|0,s|0,h|0,D|0,S|0,L|0,k|0,I|0,YE(ye)|0),e=t[e>>2]|0;while((e|0)!=0);e=t[(Fv()|0)>>2]|0;e:do if(e|0){t:for(;;){if(n=t[e+4>>2]|0,n|0?(K=t[(Pv(n)|0)>>2]|0,Be=t[(m8(n)|0)>>2]|0,Be|0):0){r=Be;do{n=r+4|0,u=FE(n)|0;n:do if(u|0)switch(sr(u)|0){case 0:break t;case 4:case 3:case 2:{D=My(u)|0,S=Ay(u)|0,L=(Oy(u)|0)+1|0,k=S_(u)|0,I=sr(u)|0,ye=E_(n)|0,f0(K|0,D|0,S|0,L|0,k|0,0,I|0,ye|0,GE(n)|0,YE(n)|0);break n}case 1:{h=My(u)|0,D=Ay(u)|0,S=(Oy(u)|0)+1|0,L=S_(u)|0,k=F8(n)|0,I=sr(u)|0,ye=E_(n)|0,f0(K|0,h|0,D|0,S|0,L|0,k|0,I|0,ye|0,GE(n)|0,YE(n)|0);break n}case 5:{L=My(u)|0,k=Ay(u)|0,I=(Oy(u)|0)+1|0,ye=S_(u)|0,f0(K|0,L|0,k|0,I|0,ye|0,TF(u)|0,sr(u)|0,0,0,0);break n}default:break n}while(0);r=t[r>>2]|0}while((r|0)!=0)}if(e=t[e>>2]|0,!e)break e}$n()}while(0);bs(),m=Te}function yF(){return 11703}function gF(e){e=e|0,c[e+40>>0]=0}function _F(e){return e=e|0,(c[e+40>>0]|0)!=0|0}function EF(e,n){return e=e|0,n=n|0,n=CF(n)|0,e=t[n>>2]|0,t[n>>2]=t[e>>2],_t(e),t[n>>2]|0}function DF(e){e=e|0,c[e+40>>0]=1}function N8(e){return e=e|0,t[e+20>>2]|0}function wF(e){return e=e|0,t[e+8>>2]|0}function SF(e){return e=e|0,t[e+32>>2]|0}function S_(e){return e=e|0,t[e+4>>2]|0}function F8(e){return e=e|0,t[e+4>>2]|0}function GE(e){return e=e|0,t[e+8>>2]|0}function YE(e){return e=e|0,t[e+16>>2]|0}function TF(e){return e=e|0,t[e+20>>2]|0}function CF(e){return e=e|0,t[e>>2]|0}function T_(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0,ft=0,Me=0,Pe=0,Zt=0;Zt=m,m=m+16|0,K=Zt;do if(e>>>0<245){if(L=e>>>0<11?16:e+11&-8,e=L>>>3,I=t[2783]|0,r=I>>>e,r&3|0)return n=(r&1^1)+e|0,e=11172+(n<<1<<2)|0,r=e+8|0,u=t[r>>2]|0,l=u+8|0,s=t[l>>2]|0,(e|0)==(s|0)?t[2783]=I&~(1<>2]=e,t[r>>2]=s),Pe=n<<3,t[u+4>>2]=Pe|3,Pe=u+Pe+4|0,t[Pe>>2]=t[Pe>>2]|1,Pe=l,m=Zt,Pe|0;if(k=t[2785]|0,L>>>0>k>>>0){if(r|0)return n=2<>>12&16,n=n>>>h,r=n>>>5&8,n=n>>>r,l=n>>>2&4,n=n>>>l,e=n>>>1&2,n=n>>>e,u=n>>>1&1,u=(r|h|l|e|u)+(n>>>u)|0,n=11172+(u<<1<<2)|0,e=n+8|0,l=t[e>>2]|0,h=l+8|0,r=t[h>>2]|0,(n|0)==(r|0)?(e=I&~(1<>2]=n,t[e>>2]=r,e=I),s=(u<<3)-L|0,t[l+4>>2]=L|3,u=l+L|0,t[u+4>>2]=s|1,t[u+s>>2]=s,k|0&&(l=t[2788]|0,n=k>>>3,r=11172+(n<<1<<2)|0,n=1<>2]|0):(t[2783]=e|n,n=r,e=r+8|0),t[e>>2]=l,t[n+12>>2]=l,t[l+8>>2]=n,t[l+12>>2]=r),t[2785]=s,t[2788]=u,Pe=h,m=Zt,Pe|0;if(D=t[2784]|0,D){if(r=(D&0-D)+-1|0,h=r>>>12&16,r=r>>>h,s=r>>>5&8,r=r>>>s,S=r>>>2&4,r=r>>>S,u=r>>>1&2,r=r>>>u,e=r>>>1&1,e=t[11436+((s|h|S|u|e)+(r>>>e)<<2)>>2]|0,r=(t[e+4>>2]&-8)-L|0,u=t[e+16+(((t[e+16>>2]|0)==0&1)<<2)>>2]|0,!u)S=e,s=r;else{do h=(t[u+4>>2]&-8)-L|0,S=h>>>0>>0,r=S?h:r,e=S?u:e,u=t[u+16+(((t[u+16>>2]|0)==0&1)<<2)>>2]|0;while((u|0)!=0);S=e,s=r}if(h=S+L|0,S>>>0>>0){l=t[S+24>>2]|0,n=t[S+12>>2]|0;do if((n|0)==(S|0)){if(e=S+20|0,n=t[e>>2]|0,!n&&(e=S+16|0,n=t[e>>2]|0,!n)){r=0;break}for(;;){if(r=n+20|0,u=t[r>>2]|0,u|0){n=u,e=r;continue}if(r=n+16|0,u=t[r>>2]|0,u)n=u,e=r;else break}t[e>>2]=0,r=n}else r=t[S+8>>2]|0,t[r+12>>2]=n,t[n+8>>2]=r,r=n;while(0);do if(l|0){if(n=t[S+28>>2]|0,e=11436+(n<<2)|0,(S|0)==(t[e>>2]|0)){if(t[e>>2]=r,!r){t[2784]=D&~(1<>2]|0)!=(S|0)&1)<<2)>>2]=r,!r)break;t[r+24>>2]=l,n=t[S+16>>2]|0,n|0&&(t[r+16>>2]=n,t[n+24>>2]=r),n=t[S+20>>2]|0,n|0&&(t[r+20>>2]=n,t[n+24>>2]=r)}while(0);return s>>>0<16?(Pe=s+L|0,t[S+4>>2]=Pe|3,Pe=S+Pe+4|0,t[Pe>>2]=t[Pe>>2]|1):(t[S+4>>2]=L|3,t[h+4>>2]=s|1,t[h+s>>2]=s,k|0&&(u=t[2788]|0,n=k>>>3,r=11172+(n<<1<<2)|0,n=1<>2]|0):(t[2783]=I|n,n=r,e=r+8|0),t[e>>2]=u,t[n+12>>2]=u,t[u+8>>2]=n,t[u+12>>2]=r),t[2785]=s,t[2788]=h),Pe=S+8|0,m=Zt,Pe|0}else I=L}else I=L}else I=L}else if(e>>>0<=4294967231)if(e=e+11|0,L=e&-8,S=t[2784]|0,S){u=0-L|0,e=e>>>8,e?L>>>0>16777215?D=31:(I=(e+1048320|0)>>>16&8,Me=e<>>16&4,Me=Me<>>16&2,D=14-(k|I|D)+(Me<>>15)|0,D=L>>>(D+7|0)&1|D<<1):D=0,r=t[11436+(D<<2)>>2]|0;e:do if(!r)r=0,e=0,Me=57;else for(e=0,h=L<<((D|0)==31?0:25-(D>>>1)|0),s=0;;){if(l=(t[r+4>>2]&-8)-L|0,l>>>0>>0)if(l)e=r,u=l;else{e=r,u=0,l=r,Me=61;break e}if(l=t[r+20>>2]|0,r=t[r+16+(h>>>31<<2)>>2]|0,s=(l|0)==0|(l|0)==(r|0)?s:l,l=(r|0)==0,l){r=s,Me=57;break}else h=h<<((l^1)&1)}while(0);if((Me|0)==57){if((r|0)==0&(e|0)==0){if(e=2<>>12&16,I=I>>>h,s=I>>>5&8,I=I>>>s,D=I>>>2&4,I=I>>>D,k=I>>>1&2,I=I>>>k,r=I>>>1&1,e=0,r=t[11436+((s|h|D|k|r)+(I>>>r)<<2)>>2]|0}r?(l=r,Me=61):(D=e,h=u)}if((Me|0)==61)for(;;)if(Me=0,r=(t[l+4>>2]&-8)-L|0,I=r>>>0>>0,r=I?r:u,e=I?l:e,l=t[l+16+(((t[l+16>>2]|0)==0&1)<<2)>>2]|0,l)u=r,Me=61;else{D=e,h=r;break}if((D|0)!=0?h>>>0<((t[2785]|0)-L|0)>>>0:0){if(s=D+L|0,D>>>0>=s>>>0)return Pe=0,m=Zt,Pe|0;l=t[D+24>>2]|0,n=t[D+12>>2]|0;do if((n|0)==(D|0)){if(e=D+20|0,n=t[e>>2]|0,!n&&(e=D+16|0,n=t[e>>2]|0,!n)){n=0;break}for(;;){if(r=n+20|0,u=t[r>>2]|0,u|0){n=u,e=r;continue}if(r=n+16|0,u=t[r>>2]|0,u)n=u,e=r;else break}t[e>>2]=0}else Pe=t[D+8>>2]|0,t[Pe+12>>2]=n,t[n+8>>2]=Pe;while(0);do if(l){if(e=t[D+28>>2]|0,r=11436+(e<<2)|0,(D|0)==(t[r>>2]|0)){if(t[r>>2]=n,!n){u=S&~(1<>2]|0)!=(D|0)&1)<<2)>>2]=n,!n){u=S;break}t[n+24>>2]=l,e=t[D+16>>2]|0,e|0&&(t[n+16>>2]=e,t[e+24>>2]=n),e=t[D+20>>2]|0,e&&(t[n+20>>2]=e,t[e+24>>2]=n),u=S}else u=S;while(0);do if(h>>>0>=16){if(t[D+4>>2]=L|3,t[s+4>>2]=h|1,t[s+h>>2]=h,n=h>>>3,h>>>0<256){r=11172+(n<<1<<2)|0,e=t[2783]|0,n=1<>2]|0):(t[2783]=e|n,n=r,e=r+8|0),t[e>>2]=s,t[n+12>>2]=s,t[s+8>>2]=n,t[s+12>>2]=r;break}if(n=h>>>8,n?h>>>0>16777215?n=31:(Me=(n+1048320|0)>>>16&8,Pe=n<>>16&4,Pe=Pe<>>16&2,n=14-(ft|Me|n)+(Pe<>>15)|0,n=h>>>(n+7|0)&1|n<<1):n=0,r=11436+(n<<2)|0,t[s+28>>2]=n,e=s+16|0,t[e+4>>2]=0,t[e>>2]=0,e=1<>2]=s,t[s+24>>2]=r,t[s+12>>2]=s,t[s+8>>2]=s;break}for(e=h<<((n|0)==31?0:25-(n>>>1)|0),r=t[r>>2]|0;;){if((t[r+4>>2]&-8|0)==(h|0)){Me=97;break}if(u=r+16+(e>>>31<<2)|0,n=t[u>>2]|0,n)e=e<<1,r=n;else{Me=96;break}}if((Me|0)==96){t[u>>2]=s,t[s+24>>2]=r,t[s+12>>2]=s,t[s+8>>2]=s;break}else if((Me|0)==97){Me=r+8|0,Pe=t[Me>>2]|0,t[Pe+12>>2]=s,t[Me>>2]=s,t[s+8>>2]=Pe,t[s+12>>2]=r,t[s+24>>2]=0;break}}else Pe=h+L|0,t[D+4>>2]=Pe|3,Pe=D+Pe+4|0,t[Pe>>2]=t[Pe>>2]|1;while(0);return Pe=D+8|0,m=Zt,Pe|0}else I=L}else I=L;else I=-1;while(0);if(r=t[2785]|0,r>>>0>=I>>>0)return n=r-I|0,e=t[2788]|0,n>>>0>15?(Pe=e+I|0,t[2788]=Pe,t[2785]=n,t[Pe+4>>2]=n|1,t[Pe+n>>2]=n,t[e+4>>2]=I|3):(t[2785]=0,t[2788]=0,t[e+4>>2]=r|3,Pe=e+r+4|0,t[Pe>>2]=t[Pe>>2]|1),Pe=e+8|0,m=Zt,Pe|0;if(h=t[2786]|0,h>>>0>I>>>0)return ft=h-I|0,t[2786]=ft,Pe=t[2789]|0,Me=Pe+I|0,t[2789]=Me,t[Me+4>>2]=ft|1,t[Pe+4>>2]=I|3,Pe=Pe+8|0,m=Zt,Pe|0;if(t[2901]|0?e=t[2903]|0:(t[2903]=4096,t[2902]=4096,t[2904]=-1,t[2905]=-1,t[2906]=0,t[2894]=0,e=K&-16^1431655768,t[K>>2]=e,t[2901]=e,e=4096),D=I+48|0,S=I+47|0,s=e+S|0,l=0-e|0,L=s&l,L>>>0<=I>>>0||(e=t[2893]|0,e|0?(k=t[2891]|0,K=k+L|0,K>>>0<=k>>>0|K>>>0>e>>>0):0))return Pe=0,m=Zt,Pe|0;e:do if(t[2894]&4)n=0,Me=133;else{r=t[2789]|0;t:do if(r){for(u=11580;e=t[u>>2]|0,!(e>>>0<=r>>>0?(ye=u+4|0,(e+(t[ye>>2]|0)|0)>>>0>r>>>0):0);)if(e=t[u+8>>2]|0,e)u=e;else{Me=118;break t}if(n=s-h&l,n>>>0<2147483647)if(e=n2(n|0)|0,(e|0)==((t[u>>2]|0)+(t[ye>>2]|0)|0)){if((e|0)!=(-1|0)){h=n,s=e,Me=135;break e}}else u=e,Me=126;else n=0}else Me=118;while(0);do if((Me|0)==118)if(r=n2(0)|0,(r|0)!=(-1|0)?(n=r,Be=t[2902]|0,Te=Be+-1|0,n=((Te&n|0)==0?0:(Te+n&0-Be)-n|0)+L|0,Be=t[2891]|0,Te=n+Be|0,n>>>0>I>>>0&n>>>0<2147483647):0){if(ye=t[2893]|0,ye|0?Te>>>0<=Be>>>0|Te>>>0>ye>>>0:0){n=0;break}if(e=n2(n|0)|0,(e|0)==(r|0)){h=n,s=r,Me=135;break e}else u=e,Me=126}else n=0;while(0);do if((Me|0)==126){if(r=0-n|0,!(D>>>0>n>>>0&(n>>>0<2147483647&(u|0)!=(-1|0))))if((u|0)==(-1|0)){n=0;break}else{h=n,s=u,Me=135;break e}if(e=t[2903]|0,e=S-n+e&0-e,e>>>0>=2147483647){h=n,s=u,Me=135;break e}if((n2(e|0)|0)==(-1|0)){n2(r|0)|0,n=0;break}else{h=e+n|0,s=u,Me=135;break e}}while(0);t[2894]=t[2894]|4,Me=133}while(0);if((((Me|0)==133?L>>>0<2147483647:0)?(ft=n2(L|0)|0,ye=n2(0)|0,Ze=ye-ft|0,Ge=Ze>>>0>(I+40|0)>>>0,!((ft|0)==(-1|0)|Ge^1|ft>>>0>>0&((ft|0)!=(-1|0)&(ye|0)!=(-1|0))^1)):0)&&(h=Ge?Ze:n,s=ft,Me=135),(Me|0)==135){n=(t[2891]|0)+h|0,t[2891]=n,n>>>0>(t[2892]|0)>>>0&&(t[2892]=n),S=t[2789]|0;do if(S){for(n=11580;;){if(e=t[n>>2]|0,r=n+4|0,u=t[r>>2]|0,(s|0)==(e+u|0)){Me=145;break}if(l=t[n+8>>2]|0,l)n=l;else break}if(((Me|0)==145?(t[n+12>>2]&8|0)==0:0)?S>>>0>>0&S>>>0>=e>>>0:0){t[r>>2]=u+h,Pe=S+8|0,Pe=(Pe&7|0)==0?0:0-Pe&7,Me=S+Pe|0,Pe=(t[2786]|0)+(h-Pe)|0,t[2789]=Me,t[2786]=Pe,t[Me+4>>2]=Pe|1,t[Me+Pe+4>>2]=40,t[2790]=t[2905];break}for(s>>>0<(t[2787]|0)>>>0&&(t[2787]=s),r=s+h|0,n=11580;;){if((t[n>>2]|0)==(r|0)){Me=153;break}if(e=t[n+8>>2]|0,e)n=e;else break}if((Me|0)==153?(t[n+12>>2]&8|0)==0:0){t[n>>2]=s,k=n+4|0,t[k>>2]=(t[k>>2]|0)+h,k=s+8|0,k=s+((k&7|0)==0?0:0-k&7)|0,n=r+8|0,n=r+((n&7|0)==0?0:0-n&7)|0,L=k+I|0,D=n-k-I|0,t[k+4>>2]=I|3;do if((n|0)!=(S|0)){if((n|0)==(t[2788]|0)){Pe=(t[2785]|0)+D|0,t[2785]=Pe,t[2788]=L,t[L+4>>2]=Pe|1,t[L+Pe>>2]=Pe;break}if(e=t[n+4>>2]|0,(e&3|0)==1){h=e&-8,u=e>>>3;e:do if(e>>>0<256)if(e=t[n+8>>2]|0,r=t[n+12>>2]|0,(r|0)==(e|0)){t[2783]=t[2783]&~(1<>2]=r,t[r+8>>2]=e;break}else{s=t[n+24>>2]|0,e=t[n+12>>2]|0;do if((e|0)==(n|0)){if(u=n+16|0,r=u+4|0,e=t[r>>2]|0,!e)if(e=t[u>>2]|0,e)r=u;else{e=0;break}for(;;){if(u=e+20|0,l=t[u>>2]|0,l|0){e=l,r=u;continue}if(u=e+16|0,l=t[u>>2]|0,l)e=l,r=u;else break}t[r>>2]=0}else Pe=t[n+8>>2]|0,t[Pe+12>>2]=e,t[e+8>>2]=Pe;while(0);if(!s)break;r=t[n+28>>2]|0,u=11436+(r<<2)|0;do if((n|0)!=(t[u>>2]|0)){if(t[s+16+(((t[s+16>>2]|0)!=(n|0)&1)<<2)>>2]=e,!e)break e}else{if(t[u>>2]=e,e|0)break;t[2784]=t[2784]&~(1<>2]=s,r=n+16|0,u=t[r>>2]|0,u|0&&(t[e+16>>2]=u,t[u+24>>2]=e),r=t[r+4>>2]|0,!r)break;t[e+20>>2]=r,t[r+24>>2]=e}while(0);n=n+h|0,l=h+D|0}else l=D;if(n=n+4|0,t[n>>2]=t[n>>2]&-2,t[L+4>>2]=l|1,t[L+l>>2]=l,n=l>>>3,l>>>0<256){r=11172+(n<<1<<2)|0,e=t[2783]|0,n=1<>2]|0):(t[2783]=e|n,n=r,e=r+8|0),t[e>>2]=L,t[n+12>>2]=L,t[L+8>>2]=n,t[L+12>>2]=r;break}n=l>>>8;do if(!n)n=0;else{if(l>>>0>16777215){n=31;break}Me=(n+1048320|0)>>>16&8,Pe=n<>>16&4,Pe=Pe<>>16&2,n=14-(ft|Me|n)+(Pe<>>15)|0,n=l>>>(n+7|0)&1|n<<1}while(0);if(u=11436+(n<<2)|0,t[L+28>>2]=n,e=L+16|0,t[e+4>>2]=0,t[e>>2]=0,e=t[2784]|0,r=1<>2]=L,t[L+24>>2]=u,t[L+12>>2]=L,t[L+8>>2]=L;break}for(e=l<<((n|0)==31?0:25-(n>>>1)|0),r=t[u>>2]|0;;){if((t[r+4>>2]&-8|0)==(l|0)){Me=194;break}if(u=r+16+(e>>>31<<2)|0,n=t[u>>2]|0,n)e=e<<1,r=n;else{Me=193;break}}if((Me|0)==193){t[u>>2]=L,t[L+24>>2]=r,t[L+12>>2]=L,t[L+8>>2]=L;break}else if((Me|0)==194){Me=r+8|0,Pe=t[Me>>2]|0,t[Pe+12>>2]=L,t[Me>>2]=L,t[L+8>>2]=Pe,t[L+12>>2]=r,t[L+24>>2]=0;break}}else Pe=(t[2786]|0)+D|0,t[2786]=Pe,t[2789]=L,t[L+4>>2]=Pe|1;while(0);return Pe=k+8|0,m=Zt,Pe|0}for(n=11580;e=t[n>>2]|0,!(e>>>0<=S>>>0?(Pe=e+(t[n+4>>2]|0)|0,Pe>>>0>S>>>0):0);)n=t[n+8>>2]|0;l=Pe+-47|0,e=l+8|0,e=l+((e&7|0)==0?0:0-e&7)|0,l=S+16|0,e=e>>>0>>0?S:e,n=e+8|0,r=s+8|0,r=(r&7|0)==0?0:0-r&7,Me=s+r|0,r=h+-40-r|0,t[2789]=Me,t[2786]=r,t[Me+4>>2]=r|1,t[Me+r+4>>2]=40,t[2790]=t[2905],r=e+4|0,t[r>>2]=27,t[n>>2]=t[2895],t[n+4>>2]=t[2896],t[n+8>>2]=t[2897],t[n+12>>2]=t[2898],t[2895]=s,t[2896]=h,t[2898]=0,t[2897]=n,n=e+24|0;do Me=n,n=n+4|0,t[n>>2]=7;while((Me+8|0)>>>0>>0);if((e|0)!=(S|0)){if(s=e-S|0,t[r>>2]=t[r>>2]&-2,t[S+4>>2]=s|1,t[e>>2]=s,n=s>>>3,s>>>0<256){r=11172+(n<<1<<2)|0,e=t[2783]|0,n=1<>2]|0):(t[2783]=e|n,n=r,e=r+8|0),t[e>>2]=S,t[n+12>>2]=S,t[S+8>>2]=n,t[S+12>>2]=r;break}if(n=s>>>8,n?s>>>0>16777215?r=31:(Me=(n+1048320|0)>>>16&8,Pe=n<>>16&4,Pe=Pe<>>16&2,r=14-(ft|Me|r)+(Pe<>>15)|0,r=s>>>(r+7|0)&1|r<<1):r=0,u=11436+(r<<2)|0,t[S+28>>2]=r,t[S+20>>2]=0,t[l>>2]=0,n=t[2784]|0,e=1<>2]=S,t[S+24>>2]=u,t[S+12>>2]=S,t[S+8>>2]=S;break}for(e=s<<((r|0)==31?0:25-(r>>>1)|0),r=t[u>>2]|0;;){if((t[r+4>>2]&-8|0)==(s|0)){Me=216;break}if(u=r+16+(e>>>31<<2)|0,n=t[u>>2]|0,n)e=e<<1,r=n;else{Me=215;break}}if((Me|0)==215){t[u>>2]=S,t[S+24>>2]=r,t[S+12>>2]=S,t[S+8>>2]=S;break}else if((Me|0)==216){Me=r+8|0,Pe=t[Me>>2]|0,t[Pe+12>>2]=S,t[Me>>2]=S,t[S+8>>2]=Pe,t[S+12>>2]=r,t[S+24>>2]=0;break}}}else{Pe=t[2787]|0,(Pe|0)==0|s>>>0>>0&&(t[2787]=s),t[2895]=s,t[2896]=h,t[2898]=0,t[2792]=t[2901],t[2791]=-1,n=0;do Pe=11172+(n<<1<<2)|0,t[Pe+12>>2]=Pe,t[Pe+8>>2]=Pe,n=n+1|0;while((n|0)!=32);Pe=s+8|0,Pe=(Pe&7|0)==0?0:0-Pe&7,Me=s+Pe|0,Pe=h+-40-Pe|0,t[2789]=Me,t[2786]=Pe,t[Me+4>>2]=Pe|1,t[Me+Pe+4>>2]=40,t[2790]=t[2905]}while(0);if(n=t[2786]|0,n>>>0>I>>>0)return ft=n-I|0,t[2786]=ft,Pe=t[2789]|0,Me=Pe+I|0,t[2789]=Me,t[Me+4>>2]=ft|1,t[Pe+4>>2]=I|3,Pe=Pe+8|0,m=Zt,Pe|0}return t[(bv()|0)>>2]=12,Pe=0,m=Zt,Pe|0}function C_(e){e=e|0;var n=0,r=0,u=0,l=0,s=0,h=0,D=0,S=0;if(!!e){r=e+-8|0,l=t[2787]|0,e=t[e+-4>>2]|0,n=e&-8,S=r+n|0;do if(e&1)D=r,h=r;else{if(u=t[r>>2]|0,!(e&3)||(h=r+(0-u)|0,s=u+n|0,h>>>0>>0))return;if((h|0)==(t[2788]|0)){if(e=S+4|0,n=t[e>>2]|0,(n&3|0)!=3){D=h,n=s;break}t[2785]=s,t[e>>2]=n&-2,t[h+4>>2]=s|1,t[h+s>>2]=s;return}if(r=u>>>3,u>>>0<256)if(e=t[h+8>>2]|0,n=t[h+12>>2]|0,(n|0)==(e|0)){t[2783]=t[2783]&~(1<>2]=n,t[n+8>>2]=e,D=h,n=s;break}l=t[h+24>>2]|0,e=t[h+12>>2]|0;do if((e|0)==(h|0)){if(r=h+16|0,n=r+4|0,e=t[n>>2]|0,!e)if(e=t[r>>2]|0,e)n=r;else{e=0;break}for(;;){if(r=e+20|0,u=t[r>>2]|0,u|0){e=u,n=r;continue}if(r=e+16|0,u=t[r>>2]|0,u)e=u,n=r;else break}t[n>>2]=0}else D=t[h+8>>2]|0,t[D+12>>2]=e,t[e+8>>2]=D;while(0);if(l){if(n=t[h+28>>2]|0,r=11436+(n<<2)|0,(h|0)==(t[r>>2]|0)){if(t[r>>2]=e,!e){t[2784]=t[2784]&~(1<>2]|0)!=(h|0)&1)<<2)>>2]=e,!e){D=h,n=s;break}t[e+24>>2]=l,n=h+16|0,r=t[n>>2]|0,r|0&&(t[e+16>>2]=r,t[r+24>>2]=e),n=t[n+4>>2]|0,n?(t[e+20>>2]=n,t[n+24>>2]=e,D=h,n=s):(D=h,n=s)}else D=h,n=s}while(0);if(!(h>>>0>=S>>>0)&&(e=S+4|0,u=t[e>>2]|0,!!(u&1))){if(u&2)t[e>>2]=u&-2,t[D+4>>2]=n|1,t[h+n>>2]=n,l=n;else{if(e=t[2788]|0,(S|0)==(t[2789]|0)){if(S=(t[2786]|0)+n|0,t[2786]=S,t[2789]=D,t[D+4>>2]=S|1,(D|0)!=(e|0))return;t[2788]=0,t[2785]=0;return}if((S|0)==(e|0)){S=(t[2785]|0)+n|0,t[2785]=S,t[2788]=h,t[D+4>>2]=S|1,t[h+S>>2]=S;return}l=(u&-8)+n|0,r=u>>>3;do if(u>>>0<256)if(n=t[S+8>>2]|0,e=t[S+12>>2]|0,(e|0)==(n|0)){t[2783]=t[2783]&~(1<>2]=e,t[e+8>>2]=n;break}else{s=t[S+24>>2]|0,e=t[S+12>>2]|0;do if((e|0)==(S|0)){if(r=S+16|0,n=r+4|0,e=t[n>>2]|0,!e)if(e=t[r>>2]|0,e)n=r;else{r=0;break}for(;;){if(r=e+20|0,u=t[r>>2]|0,u|0){e=u,n=r;continue}if(r=e+16|0,u=t[r>>2]|0,u)e=u,n=r;else break}t[n>>2]=0,r=e}else r=t[S+8>>2]|0,t[r+12>>2]=e,t[e+8>>2]=r,r=e;while(0);if(s|0){if(e=t[S+28>>2]|0,n=11436+(e<<2)|0,(S|0)==(t[n>>2]|0)){if(t[n>>2]=r,!r){t[2784]=t[2784]&~(1<>2]|0)!=(S|0)&1)<<2)>>2]=r,!r)break;t[r+24>>2]=s,e=S+16|0,n=t[e>>2]|0,n|0&&(t[r+16>>2]=n,t[n+24>>2]=r),e=t[e+4>>2]|0,e|0&&(t[r+20>>2]=e,t[e+24>>2]=r)}}while(0);if(t[D+4>>2]=l|1,t[h+l>>2]=l,(D|0)==(t[2788]|0)){t[2785]=l;return}}if(e=l>>>3,l>>>0<256){r=11172+(e<<1<<2)|0,n=t[2783]|0,e=1<>2]|0):(t[2783]=n|e,e=r,n=r+8|0),t[n>>2]=D,t[e+12>>2]=D,t[D+8>>2]=e,t[D+12>>2]=r;return}e=l>>>8,e?l>>>0>16777215?e=31:(h=(e+1048320|0)>>>16&8,S=e<>>16&4,S=S<>>16&2,e=14-(s|h|e)+(S<>>15)|0,e=l>>>(e+7|0)&1|e<<1):e=0,u=11436+(e<<2)|0,t[D+28>>2]=e,t[D+20>>2]=0,t[D+16>>2]=0,n=t[2784]|0,r=1<>>1)|0),r=t[u>>2]|0;;){if((t[r+4>>2]&-8|0)==(l|0)){e=73;break}if(u=r+16+(n>>>31<<2)|0,e=t[u>>2]|0,e)n=n<<1,r=e;else{e=72;break}}if((e|0)==72){t[u>>2]=D,t[D+24>>2]=r,t[D+12>>2]=D,t[D+8>>2]=D;break}else if((e|0)==73){h=r+8|0,S=t[h>>2]|0,t[S+12>>2]=D,t[h>>2]=D,t[D+8>>2]=S,t[D+12>>2]=r,t[D+24>>2]=0;break}}else t[2784]=n|r,t[u>>2]=D,t[D+24>>2]=u,t[D+12>>2]=D,t[D+8>>2]=D;while(0);if(S=(t[2791]|0)+-1|0,t[2791]=S,!S)e=11588;else return;for(;e=t[e>>2]|0,e;)e=e+8|0;t[2791]=-1}}}function xF(){return 11628}function RF(e){e=e|0;var n=0,r=0;return n=m,m=m+16|0,r=n,t[r>>2]=MF(t[e+60>>2]|0)|0,e=x_(Ou(6,r|0)|0)|0,m=n,e|0}function P8(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0;I=m,m=m+48|0,L=I+16|0,s=I,l=I+32|0,D=e+28|0,u=t[D>>2]|0,t[l>>2]=u,S=e+20|0,u=(t[S>>2]|0)-u|0,t[l+4>>2]=u,t[l+8>>2]=n,t[l+12>>2]=r,u=u+r|0,h=e+60|0,t[s>>2]=t[h>>2],t[s+4>>2]=l,t[s+8>>2]=2,s=x_(mo(146,s|0)|0)|0;e:do if((u|0)!=(s|0)){for(n=2;!((s|0)<0);)if(u=u-s|0,Be=t[l+4>>2]|0,K=s>>>0>Be>>>0,l=K?l+8|0:l,n=(K<<31>>31)+n|0,Be=s-(K?Be:0)|0,t[l>>2]=(t[l>>2]|0)+Be,K=l+4|0,t[K>>2]=(t[K>>2]|0)-Be,t[L>>2]=t[h>>2],t[L+4>>2]=l,t[L+8>>2]=n,s=x_(mo(146,L|0)|0)|0,(u|0)==(s|0)){k=3;break e}t[e+16>>2]=0,t[D>>2]=0,t[S>>2]=0,t[e>>2]=t[e>>2]|32,(n|0)==2?r=0:r=r-(t[l+4>>2]|0)|0}else k=3;while(0);return(k|0)==3&&(Be=t[e+44>>2]|0,t[e+16>>2]=Be+(t[e+48>>2]|0),t[D>>2]=Be,t[S>>2]=Be),m=I,r|0}function AF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;return l=m,m=m+32|0,s=l,u=l+20|0,t[s>>2]=t[e+60>>2],t[s+4>>2]=0,t[s+8>>2]=n,t[s+12>>2]=u,t[s+16>>2]=r,(x_(Li(140,s|0)|0)|0)<0?(t[u>>2]=-1,e=-1):e=t[u>>2]|0,m=l,e|0}function x_(e){return e=e|0,e>>>0>4294963200&&(t[(bv()|0)>>2]=0-e,e=-1),e|0}function bv(){return(OF()|0)+64|0}function OF(){return KE()|0}function KE(){return 2084}function MF(e){return e=e|0,e|0}function kF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;return l=m,m=m+32|0,u=l,t[e+36>>2]=1,((t[e>>2]&64|0)==0?(t[u>>2]=t[e+60>>2],t[u+4>>2]=21523,t[u+8>>2]=l+16,bo(54,u|0)|0):0)&&(c[e+75>>0]=-1),u=P8(e,n,r)|0,m=l,u|0}function I8(e,n){e=e|0,n=n|0;var r=0,u=0;if(r=c[e>>0]|0,u=c[n>>0]|0,r<<24>>24==0?1:r<<24>>24!=u<<24>>24)e=u;else{do e=e+1|0,n=n+1|0,r=c[e>>0]|0,u=c[n>>0]|0;while(!(r<<24>>24==0?1:r<<24>>24!=u<<24>>24));e=u}return(r&255)-(e&255)|0}function LF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0;e:do if(!r)e=0;else{for(;u=c[e>>0]|0,l=c[n>>0]|0,u<<24>>24==l<<24>>24;)if(r=r+-1|0,r)e=e+1|0,n=n+1|0;else{e=0;break e}e=(u&255)-(l&255)|0}while(0);return e|0}function b8(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0;ye=m,m=m+224|0,k=ye+120|0,I=ye+80|0,Be=ye,Te=ye+136|0,u=I,l=u+40|0;do t[u>>2]=0,u=u+4|0;while((u|0)<(l|0));return t[k>>2]=t[r>>2],(XE(0,n,k,Be,I)|0)<0?r=-1:((t[e+76>>2]|0)>-1?K=NF(e)|0:K=0,r=t[e>>2]|0,L=r&32,(c[e+74>>0]|0)<1&&(t[e>>2]=r&-33),u=e+48|0,t[u>>2]|0?r=XE(e,n,k,Be,I)|0:(l=e+44|0,s=t[l>>2]|0,t[l>>2]=Te,h=e+28|0,t[h>>2]=Te,D=e+20|0,t[D>>2]=Te,t[u>>2]=80,S=e+16|0,t[S>>2]=Te+80,r=XE(e,n,k,Be,I)|0,s&&(M_[t[e+36>>2]&7](e,0,0)|0,r=(t[D>>2]|0)==0?-1:r,t[l>>2]=s,t[u>>2]=0,t[S>>2]=0,t[h>>2]=0,t[D>>2]=0)),u=t[e>>2]|0,t[e>>2]=u|L,K|0&&FF(e),r=(u&32|0)==0?r:-1),m=ye,r|0}function XE(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0,ft=0,Me=0,Pe=0,Zt=0,Br=0,In=0,gn=0,_r=0,Pr=0,Ln=0;Ln=m,m=m+64|0,In=Ln+16|0,gn=Ln,Zt=Ln+24|0,_r=Ln+8|0,Pr=Ln+20|0,t[In>>2]=n,ft=(e|0)!=0,Me=Zt+40|0,Pe=Me,Zt=Zt+39|0,Br=_r+4|0,h=0,s=0,k=0;e:for(;;){do if((s|0)>-1)if((h|0)>(2147483647-s|0)){t[(bv()|0)>>2]=75,s=-1;break}else{s=h+s|0;break}while(0);if(h=c[n>>0]|0,h<<24>>24)D=n;else{Ge=87;break}t:for(;;){switch(h<<24>>24){case 37:{h=D,Ge=9;break t}case 0:{h=D;break t}default:}Ze=D+1|0,t[In>>2]=Ze,h=c[Ze>>0]|0,D=Ze}t:do if((Ge|0)==9)for(;;){if(Ge=0,(c[D+1>>0]|0)!=37)break t;if(h=h+1|0,D=D+2|0,t[In>>2]=D,(c[D>>0]|0)==37)Ge=9;else break}while(0);if(h=h-n|0,ft&&Y0(e,n,h),h|0){n=D;continue}S=D+1|0,h=(c[S>>0]|0)+-48|0,h>>>0<10?(Ze=(c[D+2>>0]|0)==36,ye=Ze?h:-1,k=Ze?1:k,S=Ze?D+3|0:S):ye=-1,t[In>>2]=S,h=c[S>>0]|0,D=(h<<24>>24)+-32|0;t:do if(D>>>0<32)for(L=0,I=h;;){if(h=1<>2]=S,h=c[S>>0]|0,D=(h<<24>>24)+-32|0,D>>>0>=32)break;I=h}else L=0;while(0);if(h<<24>>24==42){if(D=S+1|0,h=(c[D>>0]|0)+-48|0,h>>>0<10?(c[S+2>>0]|0)==36:0)t[l+(h<<2)>>2]=10,h=t[u+((c[D>>0]|0)+-48<<3)>>2]|0,k=1,S=S+3|0;else{if(k|0){s=-1;break}ft?(k=(t[r>>2]|0)+(4-1)&~(4-1),h=t[k>>2]|0,t[r>>2]=k+4,k=0,S=D):(h=0,k=0,S=D)}t[In>>2]=S,Ze=(h|0)<0,h=Ze?0-h|0:h,L=Ze?L|8192:L}else{if(h=B8(In)|0,(h|0)<0){s=-1;break}S=t[In>>2]|0}do if((c[S>>0]|0)==46){if((c[S+1>>0]|0)!=42){t[In>>2]=S+1,D=B8(In)|0,S=t[In>>2]|0;break}if(I=S+2|0,D=(c[I>>0]|0)+-48|0,D>>>0<10?(c[S+3>>0]|0)==36:0){t[l+(D<<2)>>2]=10,D=t[u+((c[I>>0]|0)+-48<<3)>>2]|0,S=S+4|0,t[In>>2]=S;break}if(k|0){s=-1;break e}ft?(Ze=(t[r>>2]|0)+(4-1)&~(4-1),D=t[Ze>>2]|0,t[r>>2]=Ze+4):D=0,t[In>>2]=I,S=I}else D=-1;while(0);for(Te=0;;){if(((c[S>>0]|0)+-65|0)>>>0>57){s=-1;break e}if(Ze=S+1|0,t[In>>2]=Ze,I=c[(c[S>>0]|0)+-65+(5178+(Te*58|0))>>0]|0,K=I&255,(K+-1|0)>>>0<8)Te=K,S=Ze;else break}if(!(I<<24>>24)){s=-1;break}Be=(ye|0)>-1;do if(I<<24>>24==19)if(Be){s=-1;break e}else Ge=49;else{if(Be){t[l+(ye<<2)>>2]=K,Be=u+(ye<<3)|0,ye=t[Be+4>>2]|0,Ge=gn,t[Ge>>2]=t[Be>>2],t[Ge+4>>2]=ye,Ge=49;break}if(!ft){s=0;break e}U8(gn,K,r)}while(0);if((Ge|0)==49?(Ge=0,!ft):0){h=0,n=Ze;continue}S=c[S>>0]|0,S=(Te|0)!=0&(S&15|0)==3?S&-33:S,Be=L&-65537,ye=(L&8192|0)==0?L:Be;t:do switch(S|0){case 110:switch((Te&255)<<24>>24){case 0:{t[t[gn>>2]>>2]=s,h=0,n=Ze;continue e}case 1:{t[t[gn>>2]>>2]=s,h=0,n=Ze;continue e}case 2:{h=t[gn>>2]|0,t[h>>2]=s,t[h+4>>2]=((s|0)<0)<<31>>31,h=0,n=Ze;continue e}case 3:{_[t[gn>>2]>>1]=s,h=0,n=Ze;continue e}case 4:{c[t[gn>>2]>>0]=s,h=0,n=Ze;continue e}case 6:{t[t[gn>>2]>>2]=s,h=0,n=Ze;continue e}case 7:{h=t[gn>>2]|0,t[h>>2]=s,t[h+4>>2]=((s|0)<0)<<31>>31,h=0,n=Ze;continue e}default:{h=0,n=Ze;continue e}}case 112:{S=120,D=D>>>0>8?D:8,n=ye|8,Ge=61;break}case 88:case 120:{n=ye,Ge=61;break}case 111:{S=gn,n=t[S>>2]|0,S=t[S+4>>2]|0,K=IF(n,S,Me)|0,Be=Pe-K|0,L=0,I=5642,D=(ye&8|0)==0|(D|0)>(Be|0)?D:Be+1|0,Be=ye,Ge=67;break}case 105:case 100:if(S=gn,n=t[S>>2]|0,S=t[S+4>>2]|0,(S|0)<0){n=R_(0,0,n|0,S|0)|0,S=tt,L=gn,t[L>>2]=n,t[L+4>>2]=S,L=1,I=5642,Ge=66;break t}else{L=(ye&2049|0)!=0&1,I=(ye&2048|0)==0?(ye&1|0)==0?5642:5644:5643,Ge=66;break t}case 117:{S=gn,L=0,I=5642,n=t[S>>2]|0,S=t[S+4>>2]|0,Ge=66;break}case 99:{c[Zt>>0]=t[gn>>2],n=Zt,L=0,I=5642,K=Me,S=1,D=Be;break}case 109:{S=bF(t[(bv()|0)>>2]|0)|0,Ge=71;break}case 115:{S=t[gn>>2]|0,S=S|0?S:5652,Ge=71;break}case 67:{t[_r>>2]=t[gn>>2],t[Br>>2]=0,t[gn>>2]=_r,K=-1,S=_r,Ge=75;break}case 83:{n=t[gn>>2]|0,D?(K=D,S=n,Ge=75):(_l(e,32,h,0,ye),n=0,Ge=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{h=UF(e,+B[gn>>3],h,D,ye,S)|0,n=Ze;continue e}default:L=0,I=5642,K=Me,S=D,D=ye}while(0);t:do if((Ge|0)==61)ye=gn,Te=t[ye>>2]|0,ye=t[ye+4>>2]|0,K=PF(Te,ye,Me,S&32)|0,I=(n&8|0)==0|(Te|0)==0&(ye|0)==0,L=I?0:2,I=I?5642:5642+(S>>4)|0,Be=n,n=Te,S=ye,Ge=67;else if((Ge|0)==66)K=Bv(n,S,Me)|0,Be=ye,Ge=67;else if((Ge|0)==71)Ge=0,ye=BF(S,0,D)|0,Te=(ye|0)==0,n=S,L=0,I=5642,K=Te?S+D|0:ye,S=Te?D:ye-S|0,D=Be;else if((Ge|0)==75){for(Ge=0,I=S,n=0,D=0;L=t[I>>2]|0,!(!L||(D=j8(Pr,L)|0,(D|0)<0|D>>>0>(K-n|0)>>>0));)if(n=D+n|0,K>>>0>n>>>0)I=I+4|0;else break;if((D|0)<0){s=-1;break e}if(_l(e,32,h,n,ye),!n)n=0,Ge=84;else for(L=0;;){if(D=t[S>>2]|0,!D){Ge=84;break t}if(D=j8(Pr,D)|0,L=D+L|0,(L|0)>(n|0)){Ge=84;break t}if(Y0(e,Pr,D),L>>>0>=n>>>0){Ge=84;break}else S=S+4|0}}while(0);if((Ge|0)==67)Ge=0,S=(n|0)!=0|(S|0)!=0,ye=(D|0)!=0|S,S=((S^1)&1)+(Pe-K)|0,n=ye?K:Me,K=Me,S=ye?(D|0)>(S|0)?D:S:D,D=(D|0)>-1?Be&-65537:Be;else if((Ge|0)==84){Ge=0,_l(e,32,h,n,ye^8192),h=(h|0)>(n|0)?h:n,n=Ze;continue}Te=K-n|0,Be=(S|0)<(Te|0)?Te:S,ye=Be+L|0,h=(h|0)<(ye|0)?ye:h,_l(e,32,h,ye,D),Y0(e,I,L),_l(e,48,h,ye,D^65536),_l(e,48,Be,Te,0),Y0(e,n,Te),_l(e,32,h,ye,D^8192),n=Ze}e:do if((Ge|0)==87&&!e)if(!k)s=0;else{for(s=1;n=t[l+(s<<2)>>2]|0,!!n;)if(U8(u+(s<<3)|0,n,r),s=s+1|0,(s|0)>=10){s=1;break e}for(;;){if(t[l+(s<<2)>>2]|0){s=-1;break e}if(s=s+1|0,(s|0)>=10){s=1;break}}}while(0);return m=Ln,s|0}function NF(e){return e=e|0,0}function FF(e){e=e|0}function Y0(e,n,r){e=e|0,n=n|0,r=r|0,t[e>>2]&32||KF(n,r,e)|0}function B8(e){e=e|0;var n=0,r=0,u=0;if(r=t[e>>2]|0,u=(c[r>>0]|0)+-48|0,u>>>0<10){n=0;do n=u+(n*10|0)|0,r=r+1|0,t[e>>2]=r,u=(c[r>>0]|0)+-48|0;while(u>>>0<10)}else n=0;return n|0}function U8(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;e:do if(n>>>0<=20)do switch(n|0){case 9:{u=(t[r>>2]|0)+(4-1)&~(4-1),n=t[u>>2]|0,t[r>>2]=u+4,t[e>>2]=n;break e}case 10:{u=(t[r>>2]|0)+(4-1)&~(4-1),n=t[u>>2]|0,t[r>>2]=u+4,u=e,t[u>>2]=n,t[u+4>>2]=((n|0)<0)<<31>>31;break e}case 11:{u=(t[r>>2]|0)+(4-1)&~(4-1),n=t[u>>2]|0,t[r>>2]=u+4,u=e,t[u>>2]=n,t[u+4>>2]=0;break e}case 12:{u=(t[r>>2]|0)+(8-1)&~(8-1),n=u,l=t[n>>2]|0,n=t[n+4>>2]|0,t[r>>2]=u+8,u=e,t[u>>2]=l,t[u+4>>2]=n;break e}case 13:{l=(t[r>>2]|0)+(4-1)&~(4-1),u=t[l>>2]|0,t[r>>2]=l+4,u=(u&65535)<<16>>16,l=e,t[l>>2]=u,t[l+4>>2]=((u|0)<0)<<31>>31;break e}case 14:{l=(t[r>>2]|0)+(4-1)&~(4-1),u=t[l>>2]|0,t[r>>2]=l+4,l=e,t[l>>2]=u&65535,t[l+4>>2]=0;break e}case 15:{l=(t[r>>2]|0)+(4-1)&~(4-1),u=t[l>>2]|0,t[r>>2]=l+4,u=(u&255)<<24>>24,l=e,t[l>>2]=u,t[l+4>>2]=((u|0)<0)<<31>>31;break e}case 16:{l=(t[r>>2]|0)+(4-1)&~(4-1),u=t[l>>2]|0,t[r>>2]=l+4,l=e,t[l>>2]=u&255,t[l+4>>2]=0;break e}case 17:{l=(t[r>>2]|0)+(8-1)&~(8-1),s=+B[l>>3],t[r>>2]=l+8,B[e>>3]=s;break e}case 18:{l=(t[r>>2]|0)+(8-1)&~(8-1),s=+B[l>>3],t[r>>2]=l+8,B[e>>3]=s;break e}default:break e}while(0);while(0)}function PF(e,n,r,u){if(e=e|0,n=n|0,r=r|0,u=u|0,!((e|0)==0&(n|0)==0))do r=r+-1|0,c[r>>0]=M[5694+(e&15)>>0]|0|u,e=A_(e|0,n|0,4)|0,n=tt;while(!((e|0)==0&(n|0)==0));return r|0}function IF(e,n,r){if(e=e|0,n=n|0,r=r|0,!((e|0)==0&(n|0)==0))do r=r+-1|0,c[r>>0]=e&7|48,e=A_(e|0,n|0,3)|0,n=tt;while(!((e|0)==0&(n|0)==0));return r|0}function Bv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;if(n>>>0>0|(n|0)==0&e>>>0>4294967295){for(;u=$E(e|0,n|0,10,0)|0,r=r+-1|0,c[r>>0]=u&255|48,u=e,e=ZE(e|0,n|0,10,0)|0,n>>>0>9|(n|0)==9&u>>>0>4294967295;)n=tt;n=e}else n=e;if(n)for(;r=r+-1|0,c[r>>0]=(n>>>0)%10|0|48,!(n>>>0<10);)n=(n>>>0)/10|0;return r|0}function bF(e){return e=e|0,WF(e,t[(qF()|0)+188>>2]|0)|0}function BF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;s=n&255,u=(r|0)!=0;e:do if(u&(e&3|0)!=0)for(l=n&255;;){if((c[e>>0]|0)==l<<24>>24){h=6;break e}if(e=e+1|0,r=r+-1|0,u=(r|0)!=0,!(u&(e&3|0)!=0)){h=5;break}}else h=5;while(0);(h|0)==5&&(u?h=6:r=0);e:do if((h|0)==6&&(l=n&255,(c[e>>0]|0)!=l<<24>>24)){u=lr(s,16843009)|0;t:do if(r>>>0>3){for(;s=t[e>>2]^u,!((s&-2139062144^-2139062144)&s+-16843009|0);)if(e=e+4|0,r=r+-4|0,r>>>0<=3){h=11;break t}}else h=11;while(0);if((h|0)==11&&!r){r=0;break}for(;;){if((c[e>>0]|0)==l<<24>>24)break e;if(e=e+1|0,r=r+-1|0,!r){r=0;break}}}while(0);return(r|0?e:0)|0}function _l(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0;if(h=m,m=m+256|0,s=h,(r|0)>(u|0)&(l&73728|0)==0){if(l=r-u|0,jv(s|0,n|0,(l>>>0<256?l:256)|0)|0,l>>>0>255){n=r-u|0;do Y0(e,s,256),l=l+-256|0;while(l>>>0>255);l=n&255}Y0(e,s,l)}m=h}function j8(e,n){return e=e|0,n=n|0,e?e=zF(e,n,0)|0:e=0,e|0}function UF(e,n,r,u,l,s){e=e|0,n=+n,r=r|0,u=u|0,l=l|0,s=s|0;var h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0,ye=0,Ze=0,Ge=0,ft=0,Me=0,Pe=0,Zt=0,Br=0,In=0,gn=0,_r=0,Pr=0,Ln=0,uu=0;uu=m,m=m+560|0,S=uu+8|0,Ze=uu,Ln=uu+524|0,Pr=Ln,L=uu+512|0,t[Ze>>2]=0,_r=L+12|0,z8(n)|0,(tt|0)<0?(n=-n,In=1,Br=5659):(In=(l&2049|0)!=0&1,Br=(l&2048|0)==0?(l&1|0)==0?5660:5665:5662),z8(n)|0,gn=tt&2146435072;do if(gn>>>0<2146435072|(gn|0)==2146435072&0<0){if(Be=+jF(n,Ze)*2,h=Be!=0,h&&(t[Ze>>2]=(t[Ze>>2]|0)+-1),ft=s|32,(ft|0)==97){Te=s&32,K=(Te|0)==0?Br:Br+9|0,I=In|2,h=12-u|0;do if(u>>>0>11|(h|0)==0)n=Be;else{n=8;do h=h+-1|0,n=n*16;while((h|0)!=0);if((c[K>>0]|0)==45){n=-(n+(-Be-n));break}else{n=Be+n-n;break}}while(0);D=t[Ze>>2]|0,h=(D|0)<0?0-D|0:D,h=Bv(h,((h|0)<0)<<31>>31,_r)|0,(h|0)==(_r|0)&&(h=L+11|0,c[h>>0]=48),c[h+-1>>0]=(D>>31&2)+43,k=h+-2|0,c[k>>0]=s+15,L=(u|0)<1,S=(l&8|0)==0,h=Ln;do gn=~~n,D=h+1|0,c[h>>0]=M[5694+gn>>0]|Te,n=(n-+(gn|0))*16,((D-Pr|0)==1?!(S&(L&n==0)):0)?(c[D>>0]=46,h=h+2|0):h=D;while(n!=0);gn=h-Pr|0,Pr=_r-k|0,_r=(u|0)!=0&(gn+-2|0)<(u|0)?u+2|0:gn,h=Pr+I+_r|0,_l(e,32,r,h,l),Y0(e,K,I),_l(e,48,r,h,l^65536),Y0(e,Ln,gn),_l(e,48,_r-gn|0,0,0),Y0(e,k,Pr),_l(e,32,r,h,l^8192);break}D=(u|0)<0?6:u,h?(h=(t[Ze>>2]|0)+-28|0,t[Ze>>2]=h,n=Be*268435456):(n=Be,h=t[Ze>>2]|0),gn=(h|0)<0?S:S+288|0,S=gn;do Pe=~~n>>>0,t[S>>2]=Pe,S=S+4|0,n=(n-+(Pe>>>0))*1e9;while(n!=0);if((h|0)>0)for(L=gn,I=S;;){if(k=(h|0)<29?h:29,h=I+-4|0,h>>>0>=L>>>0){S=0;do Me=Y8(t[h>>2]|0,0,k|0)|0,Me=JE(Me|0,tt|0,S|0,0)|0,Pe=tt,Ge=$E(Me|0,Pe|0,1e9,0)|0,t[h>>2]=Ge,S=ZE(Me|0,Pe|0,1e9,0)|0,h=h+-4|0;while(h>>>0>=L>>>0);S&&(L=L+-4|0,t[L>>2]=S)}for(S=I;!(S>>>0<=L>>>0);)if(h=S+-4|0,!(t[h>>2]|0))S=h;else break;if(h=(t[Ze>>2]|0)-k|0,t[Ze>>2]=h,(h|0)>0)I=S;else break}else L=gn;if((h|0)<0){u=((D+25|0)/9|0)+1|0,ye=(ft|0)==102;do{if(Te=0-h|0,Te=(Te|0)<9?Te:9,L>>>0>>0){k=(1<>>Te,K=0,h=L;do Pe=t[h>>2]|0,t[h>>2]=(Pe>>>Te)+K,K=lr(Pe&k,I)|0,h=h+4|0;while(h>>>0>>0);h=(t[L>>2]|0)==0?L+4|0:L,K?(t[S>>2]=K,L=h,h=S+4|0):(L=h,h=S)}else L=(t[L>>2]|0)==0?L+4|0:L,h=S;S=ye?gn:L,S=(h-S>>2|0)>(u|0)?S+(u<<2)|0:h,h=(t[Ze>>2]|0)+Te|0,t[Ze>>2]=h}while((h|0)<0);h=L,u=S}else h=L,u=S;if(Pe=gn,h>>>0>>0){if(S=(Pe-h>>2)*9|0,k=t[h>>2]|0,k>>>0>=10){L=10;do L=L*10|0,S=S+1|0;while(k>>>0>=L>>>0)}}else S=0;if(ye=(ft|0)==103,Ge=(D|0)!=0,L=D-((ft|0)!=102?S:0)+((Ge&ye)<<31>>31)|0,(L|0)<(((u-Pe>>2)*9|0)+-9|0)){if(L=L+9216|0,Te=gn+4+(((L|0)/9|0)+-1024<<2)|0,L=((L|0)%9|0)+1|0,(L|0)<9){k=10;do k=k*10|0,L=L+1|0;while((L|0)!=9)}else k=10;if(I=t[Te>>2]|0,K=(I>>>0)%(k>>>0)|0,L=(Te+4|0)==(u|0),L&(K|0)==0)L=Te;else if(Be=(((I>>>0)/(k>>>0)|0)&1|0)==0?9007199254740992:9007199254740994,Me=(k|0)/2|0,n=K>>>0>>0?.5:L&(K|0)==(Me|0)?1:1.5,In&&(Me=(c[Br>>0]|0)==45,n=Me?-n:n,Be=Me?-Be:Be),L=I-K|0,t[Te>>2]=L,Be+n!=Be){if(Me=L+k|0,t[Te>>2]=Me,Me>>>0>999999999)for(S=Te;L=S+-4|0,t[S>>2]=0,L>>>0>>0&&(h=h+-4|0,t[h>>2]=0),Me=(t[L>>2]|0)+1|0,t[L>>2]=Me,Me>>>0>999999999;)S=L;else L=Te;if(S=(Pe-h>>2)*9|0,I=t[h>>2]|0,I>>>0>=10){k=10;do k=k*10|0,S=S+1|0;while(I>>>0>=k>>>0)}}else L=Te;L=L+4|0,L=u>>>0>L>>>0?L:u,Me=h}else L=u,Me=h;for(ft=L;;){if(ft>>>0<=Me>>>0){Ze=0;break}if(h=ft+-4|0,!(t[h>>2]|0))ft=h;else{Ze=1;break}}u=0-S|0;do if(ye)if(h=((Ge^1)&1)+D|0,(h|0)>(S|0)&(S|0)>-5?(k=s+-1|0,D=h+-1-S|0):(k=s+-2|0,D=h+-1|0),h=l&8,h)Te=h;else{if(Ze?(Zt=t[ft+-4>>2]|0,(Zt|0)!=0):0)if((Zt>>>0)%10|0)L=0;else{L=0,h=10;do h=h*10|0,L=L+1|0;while(!((Zt>>>0)%(h>>>0)|0|0))}else L=9;if(h=((ft-Pe>>2)*9|0)+-9|0,(k|32|0)==102){Te=h-L|0,Te=(Te|0)>0?Te:0,D=(D|0)<(Te|0)?D:Te,Te=0;break}else{Te=h+S-L|0,Te=(Te|0)>0?Te:0,D=(D|0)<(Te|0)?D:Te,Te=0;break}}else k=s,Te=l&8;while(0);if(ye=D|Te,I=(ye|0)!=0&1,K=(k|32|0)==102,K)Ge=0,h=(S|0)>0?S:0;else{if(h=(S|0)<0?u:S,h=Bv(h,((h|0)<0)<<31>>31,_r)|0,L=_r,(L-h|0)<2)do h=h+-1|0,c[h>>0]=48;while((L-h|0)<2);c[h+-1>>0]=(S>>31&2)+43,h=h+-2|0,c[h>>0]=k,Ge=h,h=L-h|0}if(h=In+1+D+I+h|0,_l(e,32,r,h,l),Y0(e,Br,In),_l(e,48,r,h,l^65536),K){k=Me>>>0>gn>>>0?gn:Me,Te=Ln+9|0,I=Te,K=Ln+8|0,L=k;do{if(S=Bv(t[L>>2]|0,0,Te)|0,(L|0)==(k|0))(S|0)==(Te|0)&&(c[K>>0]=48,S=K);else if(S>>>0>Ln>>>0){jv(Ln|0,48,S-Pr|0)|0;do S=S+-1|0;while(S>>>0>Ln>>>0)}Y0(e,S,I-S|0),L=L+4|0}while(L>>>0<=gn>>>0);if(ye|0&&Y0(e,5710,1),L>>>0>>0&(D|0)>0)for(;;){if(S=Bv(t[L>>2]|0,0,Te)|0,S>>>0>Ln>>>0){jv(Ln|0,48,S-Pr|0)|0;do S=S+-1|0;while(S>>>0>Ln>>>0)}if(Y0(e,S,(D|0)<9?D:9),L=L+4|0,S=D+-9|0,L>>>0>>0&(D|0)>9)D=S;else{D=S;break}}_l(e,48,D+9|0,9,0)}else{if(ye=Ze?ft:Me+4|0,(D|0)>-1){Ze=Ln+9|0,Te=(Te|0)==0,u=Ze,I=0-Pr|0,K=Ln+8|0,k=Me;do{S=Bv(t[k>>2]|0,0,Ze)|0,(S|0)==(Ze|0)&&(c[K>>0]=48,S=K);do if((k|0)==(Me|0)){if(L=S+1|0,Y0(e,S,1),Te&(D|0)<1){S=L;break}Y0(e,5710,1),S=L}else{if(S>>>0<=Ln>>>0)break;jv(Ln|0,48,S+I|0)|0;do S=S+-1|0;while(S>>>0>Ln>>>0)}while(0);Pr=u-S|0,Y0(e,S,(D|0)>(Pr|0)?Pr:D),D=D-Pr|0,k=k+4|0}while(k>>>0>>0&(D|0)>-1)}_l(e,48,D+18|0,18,0),Y0(e,Ge,_r-Ge|0)}_l(e,32,r,h,l^8192)}else Ln=(s&32|0)!=0,h=In+3|0,_l(e,32,r,h,l&-65537),Y0(e,Br,In),Y0(e,n!=n|!1?Ln?5686:5690:Ln?5678:5682,3),_l(e,32,r,h,l^8192);while(0);return m=uu,((h|0)<(r|0)?r:h)|0}function z8(e){e=+e;var n=0;return B[q>>3]=e,n=t[q>>2]|0,tt=t[q+4>>2]|0,n|0}function jF(e,n){return e=+e,n=n|0,+ +H8(e,n)}function H8(e,n){e=+e,n=n|0;var r=0,u=0,l=0;switch(B[q>>3]=e,r=t[q>>2]|0,u=t[q+4>>2]|0,l=A_(r|0,u|0,52)|0,l&2047){case 0:{e!=0?(e=+H8(e*18446744073709552e3,n),r=(t[n>>2]|0)+-64|0):r=0,t[n>>2]=r;break}case 2047:break;default:t[n>>2]=(l&2047)+-1022,t[q>>2]=r,t[q+4>>2]=u&-2146435073|1071644672,e=+B[q>>3]}return+e}function zF(e,n,r){e=e|0,n=n|0,r=r|0;do if(e){if(n>>>0<128){c[e>>0]=n,e=1;break}if(!(t[t[(HF()|0)+188>>2]>>2]|0))if((n&-128|0)==57216){c[e>>0]=n,e=1;break}else{t[(bv()|0)>>2]=84,e=-1;break}if(n>>>0<2048){c[e>>0]=n>>>6|192,c[e+1>>0]=n&63|128,e=2;break}if(n>>>0<55296|(n&-8192|0)==57344){c[e>>0]=n>>>12|224,c[e+1>>0]=n>>>6&63|128,c[e+2>>0]=n&63|128,e=3;break}if((n+-65536|0)>>>0<1048576){c[e>>0]=n>>>18|240,c[e+1>>0]=n>>>12&63|128,c[e+2>>0]=n>>>6&63|128,c[e+3>>0]=n&63|128,e=4;break}else{t[(bv()|0)>>2]=84,e=-1;break}}else e=1;while(0);return e|0}function HF(){return KE()|0}function qF(){return KE()|0}function WF(e,n){e=e|0,n=n|0;var r=0,u=0;for(u=0;;){if((M[5712+u>>0]|0)==(e|0)){e=2;break}if(r=u+1|0,(r|0)==87){r=5800,u=87,e=5;break}else u=r}if((e|0)==2&&(u?(r=5800,e=5):r=5800),(e|0)==5)for(;;){do e=r,r=r+1|0;while((c[e>>0]|0)!=0);if(u=u+-1|0,u)e=5;else break}return VF(r,t[n+20>>2]|0)|0}function VF(e,n){return e=e|0,n=n|0,GF(e,n)|0}function GF(e,n){return e=e|0,n=n|0,n?n=YF(t[n>>2]|0,t[n+4>>2]|0,e)|0:n=0,(n|0?n:e)|0}function YF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0;K=(t[e>>2]|0)+1794895138|0,s=Xp(t[e+8>>2]|0,K)|0,u=Xp(t[e+12>>2]|0,K)|0,l=Xp(t[e+16>>2]|0,K)|0;e:do if((s>>>0>>2>>>0?(I=n-(s<<2)|0,u>>>0>>0&l>>>0>>0):0)?((l|u)&3|0)==0:0){for(I=u>>>2,k=l>>>2,L=0;;){if(D=s>>>1,S=L+D|0,h=S<<1,l=h+I|0,u=Xp(t[e+(l<<2)>>2]|0,K)|0,l=Xp(t[e+(l+1<<2)>>2]|0,K)|0,!(l>>>0>>0&u>>>0<(n-l|0)>>>0)){u=0;break e}if(c[e+(l+u)>>0]|0){u=0;break e}if(u=I8(r,e+l|0)|0,!u)break;if(u=(u|0)<0,(s|0)==1){u=0;break e}else L=u?L:S,s=u?D:s-D|0}u=h+k|0,l=Xp(t[e+(u<<2)>>2]|0,K)|0,u=Xp(t[e+(u+1<<2)>>2]|0,K)|0,u>>>0>>0&l>>>0<(n-u|0)>>>0?u=(c[e+(u+l)>>0]|0)==0?e+u|0:0:u=0}else u=0;while(0);return u|0}function Xp(e,n){e=e|0,n=n|0;var r=0;return r=Q8(e|0)|0,((n|0)==0?e:r)|0}function KF(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0,D=0;u=r+16|0,l=t[u>>2]|0,l?s=5:XF(r)|0?u=0:(l=t[u>>2]|0,s=5);e:do if((s|0)==5){if(D=r+20|0,h=t[D>>2]|0,u=h,(l-h|0)>>>0>>0){u=M_[t[r+36>>2]&7](r,e,n)|0;break}t:do if((c[r+75>>0]|0)>-1){for(h=n;;){if(!h){s=0,l=e;break t}if(l=h+-1|0,(c[e+l>>0]|0)==10)break;h=l}if(u=M_[t[r+36>>2]&7](r,e,h)|0,u>>>0>>0)break e;s=h,l=e+h|0,n=n-h|0,u=t[D>>2]|0}else s=0,l=e;while(0);gr(u|0,l|0,n|0)|0,t[D>>2]=(t[D>>2]|0)+n,u=s+n|0}while(0);return u|0}function XF(e){e=e|0;var n=0,r=0;return n=e+74|0,r=c[n>>0]|0,c[n>>0]=r+255|r,n=t[e>>2]|0,n&8?(t[e>>2]=n|32,e=-1):(t[e+8>>2]=0,t[e+4>>2]=0,r=t[e+44>>2]|0,t[e+28>>2]=r,t[e+20>>2]=r,t[e+16>>2]=r+(t[e+48>>2]|0),e=0),e|0}function Ru(e,n){e=w(e),n=w(n);var r=0,u=0;r=q8(e)|0;do if((r&2147483647)>>>0<=2139095040){if(u=q8(n)|0,(u&2147483647)>>>0<=2139095040)if((u^r|0)<0){e=(r|0)<0?n:e;break}else{e=e>2]=e,t[q>>2]|0|0}function Qp(e,n){e=w(e),n=w(n);var r=0,u=0;r=W8(e)|0;do if((r&2147483647)>>>0<=2139095040){if(u=W8(n)|0,(u&2147483647)>>>0<=2139095040)if((u^r|0)<0){e=(r|0)<0?e:n;break}else{e=e>2]=e,t[q>>2]|0|0}function QE(e,n){e=w(e),n=w(n);var r=0,u=0,l=0,s=0,h=0,D=0,S=0,L=0;s=(T[q>>2]=e,t[q>>2]|0),D=(T[q>>2]=n,t[q>>2]|0),r=s>>>23&255,h=D>>>23&255,S=s&-2147483648,l=D<<1;e:do if((l|0)!=0?!((r|0)==255|((QF(n)|0)&2147483647)>>>0>2139095040):0){if(u=s<<1,u>>>0<=l>>>0)return n=w(e*w(0)),w((u|0)==(l|0)?n:e);if(r)u=s&8388607|8388608;else{if(r=s<<9,(r|0)>-1){u=r,r=0;do r=r+-1|0,u=u<<1;while((u|0)>-1)}else r=0;u=s<<1-r}if(h)D=D&8388607|8388608;else{if(s=D<<9,(s|0)>-1){l=0;do l=l+-1|0,s=s<<1;while((s|0)>-1)}else l=0;h=l,D=D<<1-l}l=u-D|0,s=(l|0)>-1;t:do if((r|0)>(h|0)){for(;;){if(s)if(l)u=l;else break;if(u=u<<1,r=r+-1|0,l=u-D|0,s=(l|0)>-1,(r|0)<=(h|0))break t}n=w(e*w(0));break e}while(0);if(s)if(l)u=l;else{n=w(e*w(0));break}if(u>>>0<8388608)do u=u<<1,r=r+-1|0;while(u>>>0<8388608);(r|0)>0?r=u+-8388608|r<<23:r=u>>>(1-r|0),n=(t[q>>2]=r|S,w(T[q>>2]))}else L=3;while(0);return(L|0)==3&&(n=w(e*n),n=w(n/n)),w(n)}function QF(e){return e=w(e),T[q>>2]=e,t[q>>2]|0|0}function JF(e,n){return e=e|0,n=n|0,b8(t[582]|0,e,n)|0}function hi(e){e=e|0,$n()}function Uv(e){e=e|0}function ZF(e,n){return e=e|0,n=n|0,0}function $F(e){return e=e|0,(V8(e+4|0)|0)==-1?(P1[t[(t[e>>2]|0)+8>>2]&127](e),e=1):e=0,e|0}function V8(e){e=e|0;var n=0;return n=t[e>>2]|0,t[e>>2]=n+-1,n+-1|0}function t2(e){e=e|0,$F(e)|0&&eP(e)}function eP(e){e=e|0;var n=0;n=e+8|0,((t[n>>2]|0)!=0?(V8(n)|0)!=-1:0)||P1[t[(t[e>>2]|0)+16>>2]&127](e)}function pn(e){e=e|0;var n=0;for(n=(e|0)==0?1:e;e=T_(n)|0,!(e|0);){if(e=nP()|0,!e){e=0;break}oS[e&0]()}return e|0}function G8(e){return e=e|0,pn(e)|0}function _t(e){e=e|0,C_(e)}function tP(e){e=e|0,(c[e+11>>0]|0)<0&&_t(t[e>>2]|0)}function nP(){var e=0;return e=t[2923]|0,t[2923]=e+0,e|0}function rP(){}function R_(e,n,r,u){return e=e|0,n=n|0,r=r|0,u=u|0,u=n-u-(r>>>0>e>>>0|0)>>>0,tt=u,e-r>>>0|0|0}function JE(e,n,r,u){return e=e|0,n=n|0,r=r|0,u=u|0,r=e+r>>>0,tt=n+u+(r>>>0>>0|0)>>>0,r|0|0}function jv(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0,h=0;if(s=e+r|0,n=n&255,(r|0)>=67){for(;e&3;)c[e>>0]=n,e=e+1|0;for(u=s&-4|0,l=u-64|0,h=n|n<<8|n<<16|n<<24;(e|0)<=(l|0);)t[e>>2]=h,t[e+4>>2]=h,t[e+8>>2]=h,t[e+12>>2]=h,t[e+16>>2]=h,t[e+20>>2]=h,t[e+24>>2]=h,t[e+28>>2]=h,t[e+32>>2]=h,t[e+36>>2]=h,t[e+40>>2]=h,t[e+44>>2]=h,t[e+48>>2]=h,t[e+52>>2]=h,t[e+56>>2]=h,t[e+60>>2]=h,e=e+64|0;for(;(e|0)<(u|0);)t[e>>2]=h,e=e+4|0}for(;(e|0)<(s|0);)c[e>>0]=n,e=e+1|0;return s-r|0}function Y8(e,n,r){return e=e|0,n=n|0,r=r|0,(r|0)<32?(tt=n<>>32-r,e<>>r,e>>>r|(n&(1<>>r-32|0)}function gr(e,n,r){e=e|0,n=n|0,r=r|0;var u=0,l=0,s=0;if((r|0)>=8192)return ai(e|0,n|0,r|0)|0;if(s=e|0,l=e+r|0,(e&3)==(n&3)){for(;e&3;){if(!r)return s|0;c[e>>0]=c[n>>0]|0,e=e+1|0,n=n+1|0,r=r-1|0}for(r=l&-4|0,u=r-64|0;(e|0)<=(u|0);)t[e>>2]=t[n>>2],t[e+4>>2]=t[n+4>>2],t[e+8>>2]=t[n+8>>2],t[e+12>>2]=t[n+12>>2],t[e+16>>2]=t[n+16>>2],t[e+20>>2]=t[n+20>>2],t[e+24>>2]=t[n+24>>2],t[e+28>>2]=t[n+28>>2],t[e+32>>2]=t[n+32>>2],t[e+36>>2]=t[n+36>>2],t[e+40>>2]=t[n+40>>2],t[e+44>>2]=t[n+44>>2],t[e+48>>2]=t[n+48>>2],t[e+52>>2]=t[n+52>>2],t[e+56>>2]=t[n+56>>2],t[e+60>>2]=t[n+60>>2],e=e+64|0,n=n+64|0;for(;(e|0)<(r|0);)t[e>>2]=t[n>>2],e=e+4|0,n=n+4|0}else for(r=l-4|0;(e|0)<(r|0);)c[e>>0]=c[n>>0]|0,c[e+1>>0]=c[n+1>>0]|0,c[e+2>>0]=c[n+2>>0]|0,c[e+3>>0]=c[n+3>>0]|0,e=e+4|0,n=n+4|0;for(;(e|0)<(l|0);)c[e>>0]=c[n>>0]|0,e=e+1|0,n=n+1|0;return s|0}function K8(e){e=e|0;var n=0;return n=c[ge+(e&255)>>0]|0,(n|0)<8?n|0:(n=c[ge+(e>>8&255)>>0]|0,(n|0)<8?n+8|0:(n=c[ge+(e>>16&255)>>0]|0,(n|0)<8?n+16|0:(c[ge+(e>>>24)>>0]|0)+24|0))}function X8(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0;var s=0,h=0,D=0,S=0,L=0,k=0,I=0,K=0,Be=0,Te=0;if(k=e,S=n,L=S,h=r,K=u,D=K,!L)return s=(l|0)!=0,D?s?(t[l>>2]=e|0,t[l+4>>2]=n&0,K=0,l=0,tt=K,l|0):(K=0,l=0,tt=K,l|0):(s&&(t[l>>2]=(k>>>0)%(h>>>0),t[l+4>>2]=0),K=0,l=(k>>>0)/(h>>>0)>>>0,tt=K,l|0);s=(D|0)==0;do if(h){if(!s){if(s=(Er(D|0)|0)-(Er(L|0)|0)|0,s>>>0<=31){I=s+1|0,D=31-s|0,n=s-31>>31,h=I,e=k>>>(I>>>0)&n|L<>>(I>>>0)&n,s=0,D=k<>2]=e|0,t[l+4>>2]=S|n&0,K=0,l=0,tt=K,l|0):(K=0,l=0,tt=K,l|0)}if(s=h-1|0,s&h|0){D=(Er(h|0)|0)+33-(Er(L|0)|0)|0,Te=64-D|0,I=32-D|0,S=I>>31,Be=D-32|0,n=Be>>31,h=D,e=I-1>>31&L>>>(Be>>>0)|(L<>>(D>>>0))&n,n=n&L>>>(D>>>0),s=k<>>(Be>>>0))&S|k<>31;break}return l|0&&(t[l>>2]=s&k,t[l+4>>2]=0),(h|0)==1?(Be=S|n&0,Te=e|0|0,tt=Be,Te|0):(Te=K8(h|0)|0,Be=L>>>(Te>>>0)|0,Te=L<<32-Te|k>>>(Te>>>0)|0,tt=Be,Te|0)}else{if(s)return l|0&&(t[l>>2]=(L>>>0)%(h>>>0),t[l+4>>2]=0),Be=0,Te=(L>>>0)/(h>>>0)>>>0,tt=Be,Te|0;if(!k)return l|0&&(t[l>>2]=0,t[l+4>>2]=(L>>>0)%(D>>>0)),Be=0,Te=(L>>>0)/(D>>>0)>>>0,tt=Be,Te|0;if(s=D-1|0,!(s&D))return l|0&&(t[l>>2]=e|0,t[l+4>>2]=s&L|n&0),Be=0,Te=L>>>((K8(D|0)|0)>>>0),tt=Be,Te|0;if(s=(Er(D|0)|0)-(Er(L|0)|0)|0,s>>>0<=30){n=s+1|0,D=31-s|0,h=n,e=L<>>(n>>>0),n=L>>>(n>>>0),s=0,D=k<>2]=e|0,t[l+4>>2]=S|n&0,Be=0,Te=0,tt=Be,Te|0):(Be=0,Te=0,tt=Be,Te|0)}while(0);if(!h)L=D,S=0,D=0;else{I=r|0|0,k=K|u&0,L=JE(I|0,k|0,-1,-1)|0,r=tt,S=D,D=0;do u=S,S=s>>>31|S<<1,s=D|s<<1,u=e<<1|u>>>31|0,K=e>>>31|n<<1|0,R_(L|0,r|0,u|0,K|0)|0,Te=tt,Be=Te>>31|((Te|0)<0?-1:0)<<1,D=Be&1,e=R_(u|0,K|0,Be&I|0,(((Te|0)<0?-1:0)>>31|((Te|0)<0?-1:0)<<1)&k|0)|0,n=tt,h=h-1|0;while((h|0)!=0);L=S,S=0}return h=0,l|0&&(t[l>>2]=e,t[l+4>>2]=n),Be=(s|0)>>>31|(L|h)<<1|(h<<1|s>>>31)&0|S,Te=(s<<1|0>>>31)&-2|D,tt=Be,Te|0}function ZE(e,n,r,u){return e=e|0,n=n|0,r=r|0,u=u|0,X8(e,n,r,u,0)|0}function n2(e){e=e|0;var n=0,r=0;return r=e+15&-16|0,n=t[H>>2]|0,e=n+r|0,(r|0)>0&(e|0)<(n|0)|(e|0)<0?(fr()|0,Jl(12),-1):(t[H>>2]=e,((e|0)>(jr()|0)?(vr()|0)==0:0)?(t[H>>2]=n,Jl(12),-1):n|0)}function ky(e,n,r){e=e|0,n=n|0,r=r|0;var u=0;if((n|0)<(e|0)&(e|0)<(n+r|0)){for(u=e,n=n+r|0,e=e+r|0;(r|0)>0;)e=e-1|0,n=n-1|0,r=r-1|0,c[e>>0]=c[n>>0]|0;e=u}else gr(e,n,r)|0;return e|0}function $E(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0;var l=0,s=0;return s=m,m=m+16|0,l=s|0,X8(e,n,r,u,l)|0,m=s,tt=t[l+4>>2]|0,t[l>>2]|0|0}function Q8(e){return e=e|0,(e&255)<<24|(e>>8&255)<<16|(e>>16&255)<<8|e>>>24|0}function iP(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,J8[e&1](n|0,r|0,u|0,l|0,s|0)}function uP(e,n,r){e=e|0,n=n|0,r=w(r),Z8[e&1](n|0,w(r))}function oP(e,n,r){e=e|0,n=n|0,r=+r,$8[e&31](n|0,+r)}function lP(e,n,r,u){return e=e|0,n=n|0,r=w(r),u=w(u),w(eS[e&0](n|0,w(r),w(u)))}function sP(e,n){e=e|0,n=n|0,P1[e&127](n|0)}function aP(e,n,r){e=e|0,n=n|0,r=r|0,I1[e&31](n|0,r|0)}function fP(e,n){return e=e|0,n=n|0,Zp[e&31](n|0)|0}function cP(e,n,r,u,l){e=e|0,n=n|0,r=+r,u=+u,l=l|0,tS[e&1](n|0,+r,+u,l|0)}function dP(e,n,r,u){e=e|0,n=n|0,r=+r,u=+u,GP[e&1](n|0,+r,+u)}function pP(e,n,r,u){return e=e|0,n=n|0,r=r|0,u=u|0,M_[e&7](n|0,r|0,u|0)|0}function hP(e,n,r,u){return e=e|0,n=n|0,r=r|0,u=u|0,+YP[e&1](n|0,r|0,u|0)}function vP(e,n){return e=e|0,n=n|0,+nS[e&15](n|0)}function mP(e,n,r){return e=e|0,n=n|0,r=+r,KP[e&1](n|0,+r)|0}function yP(e,n,r){return e=e|0,n=n|0,r=r|0,tD[e&15](n|0,r|0)|0}function gP(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=+u,l=+l,s=s|0,XP[e&1](n|0,r|0,+u,+l,s|0)}function _P(e,n,r,u,l,s,h){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,h=h|0,QP[e&1](n|0,r|0,u|0,l|0,s|0,h|0)}function EP(e,n,r){return e=e|0,n=n|0,r=r|0,+rS[e&7](n|0,r|0)}function DP(e){return e=e|0,k_[e&7]()|0}function wP(e,n,r,u,l,s){return e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,iS[e&1](n|0,r|0,u|0,l|0,s|0)|0}function SP(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=+l,JP[e&1](n|0,r|0,u|0,+l)}function TP(e,n,r,u,l,s,h){e=e|0,n=n|0,r=r|0,u=w(u),l=l|0,s=w(s),h=h|0,uS[e&1](n|0,r|0,w(u),l|0,w(s),h|0)}function CP(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,Fy[e&15](n|0,r|0,u|0)}function xP(e){e=e|0,oS[e&0]()}function RP(e,n,r,u){e=e|0,n=n|0,r=r|0,u=+u,lS[e&15](n|0,r|0,+u)}function AP(e,n,r){return e=e|0,n=+n,r=+r,ZP[e&1](+n,+r)|0}function OP(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,nD[e&15](n|0,r|0,u|0,l|0)}function MP(e,n,r,u,l){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,jt(0)}function kP(e,n){e=e|0,n=w(n),jt(1)}function ea(e,n){e=e|0,n=+n,jt(2)}function LP(e,n,r){return e=e|0,n=w(n),r=w(r),jt(3),Tt}function Zn(e){e=e|0,jt(4)}function Ly(e,n){e=e|0,n=n|0,jt(5)}function Na(e){return e=e|0,jt(6),0}function NP(e,n,r,u){e=e|0,n=+n,r=+r,u=u|0,jt(7)}function FP(e,n,r){e=e|0,n=+n,r=+r,jt(8)}function PP(e,n,r){return e=e|0,n=n|0,r=r|0,jt(9),0}function IP(e,n,r){return e=e|0,n=n|0,r=r|0,jt(10),0}function Jp(e){return e=e|0,jt(11),0}function bP(e,n){return e=e|0,n=+n,jt(12),0}function Ny(e,n){return e=e|0,n=n|0,jt(13),0}function BP(e,n,r,u,l){e=e|0,n=n|0,r=+r,u=+u,l=l|0,jt(14)}function UP(e,n,r,u,l,s){e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,s=s|0,jt(15)}function eD(e,n){return e=e|0,n=n|0,jt(16),0}function jP(){return jt(17),0}function zP(e,n,r,u,l){return e=e|0,n=n|0,r=r|0,u=u|0,l=l|0,jt(18),0}function HP(e,n,r,u){e=e|0,n=n|0,r=r|0,u=+u,jt(19)}function qP(e,n,r,u,l,s){e=e|0,n=n|0,r=w(r),u=u|0,l=w(l),s=s|0,jt(20)}function O_(e,n,r){e=e|0,n=n|0,r=r|0,jt(21)}function WP(){jt(22)}function zv(e,n,r){e=e|0,n=n|0,r=+r,jt(23)}function VP(e,n){return e=+e,n=+n,jt(24),0}function Hv(e,n,r,u){e=e|0,n=n|0,r=r|0,u=u|0,jt(25)}var J8=[MP,jM],Z8=[kP,no],$8=[ea,da,Ss,Ts,ns,H0,Df,ol,Wa,ro,wf,Wc,pc,Ol,Cs,pa,od,ha,hc,ea,ea,ea,ea,ea,ea,ea,ea,ea,ea,ea,ea,ea],eS=[LP],P1=[Zn,Uv,cn,us,D0,jf,M1,jl,vO,mO,yO,RM,AM,OM,QN,JN,ZN,Ne,cc,ja,Gu,zo,yh,Tf,r1,Ff,Da,kh,ym,g1,_1,Zh,mp,Pd,jm,C1,Oc,Jm,ey,xv,Mv,on,$4,fE,p_,Nt,xu,to,OR,VR,fA,AA,qA,f7,E7,S7,j7,q7,oO,_O,wO,UO,rM,_d,Bk,vL,ML,VL,hN,ON,jN,qN,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn,Zn],I1=[Ly,D2,rd,qc,Rl,ul,w2,Ws,Al,za,Ha,qa,Ml,ze,lt,$t,Wn,si,ur,Va,T2,_h,pE,gE,LA,zk,cM,D8,Ly,Ly,Ly,Ly],Zp=[Na,RF,Ef,y,J,de,gt,xt,Lt,xr,du,Ho,Ga,ld,Xc,ks,YA,HO,Vk,Ma,Na,Na,Na,Na,Na,Na,Na,Na,Na,Na,Na,Na],tS=[NP,R2],GP=[FP,aO],M_=[PP,P8,AF,kF,Wh,vv,NR,QL],YP=[IP,fv],nS=[Jp,uo,Ve,ci,gh,al,va,A2,O2,vc,Jp,Jp,Jp,Jp,Jp,Jp],KP=[bP,y7],tD=[Ny,ZF,S2,dl,W2,xm,dp,Ap,ty,kr,j0,FL,Ny,Ny,Ny,Ny],XP=[BP,xh],QP=[UP,gN],rS=[eD,Qi,M2,pd,Qc,ml,eD,eD],k_=[jP,Jc,u0,wo,R7,Y7,xO,YN],iS=[zP,li],JP=[HP,vy],uS=[qP,sd],Fy=[O_,R,io,Gr,Cu,m1,Fd,ar,_y,m0,ak,_L,NN,O_,O_,O_],oS=[WP],lS=[zv,id,y0,ud,z0,Vc,qi,g,jp,XR,p7,zv,zv,zv,zv,zv],ZP=[VP,pO],nD=[Hv,wp,Fc,hA,n7,N7,$7,NO,sM,Jk,iF,Hv,Hv,Hv,Hv,Hv];return{_llvm_bswap_i32:Q8,dynCall_idd:AP,dynCall_i:DP,_i64Subtract:R_,___udivdi3:ZE,dynCall_vif:uP,setThrew:ms,dynCall_viii:CP,_bitshift64Lshr:A_,_bitshift64Shl:Y8,dynCall_vi:sP,dynCall_viiddi:gP,dynCall_diii:hP,dynCall_iii:yP,_memset:jv,_sbrk:n2,_memcpy:gr,__GLOBAL__sub_I_Yoga_cpp:ru,dynCall_vii:aP,___uremdi3:$E,dynCall_vid:oP,stackAlloc:d0,_nbind_init:vF,getTempRet0:Q,dynCall_di:vP,dynCall_iid:mP,setTempRet0:Bo,_i64Add:JE,dynCall_fiff:lP,dynCall_iiii:pP,_emscripten_get_global_libc:xF,dynCall_viid:RP,dynCall_viiid:SP,dynCall_viififi:TP,dynCall_ii:fP,__GLOBAL__sub_I_Binding_cc:Mk,dynCall_viiii:OP,dynCall_iiiiii:wP,stackSave:nl,dynCall_viiiii:iP,__GLOBAL__sub_I_nbind_cc:Vs,dynCall_vidd:dP,_free:C_,runPostSets:rP,dynCall_viiiiii:_P,establishStackSpace:ju,_memmove:ky,stackRestore:Zl,_malloc:T_,__GLOBAL__sub_I_common_cc:QO,dynCall_viddi:cP,dynCall_dii:EP,dynCall_v:xP}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(i){this.name="ExitStatus",this.message="Program terminated with exit("+i+")",this.status=i}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function i(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=i)},Module.callMain=Module.callMain=function(o){o=o||[],ensureInitRuntime();var a=o.length+1;function c(){for(var O=0;O<4-1;O++)_.push(0)}var _=[allocate(intArrayFromString(Module.thisProgram),"i8",ALLOC_NORMAL)];c();for(var t=0;t0||(preRun(),runDependencies>0)||Module.calledRun)return;function o(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(i),postRun()))}Module.setStatus?(Module.setStatus("Running..."),setTimeout(function(){setTimeout(function(){Module.setStatus("")},1),o()},1)):o()}Module.run=Module.run=run;function exit(i,o){o&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=i,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(i)),ENVIRONMENT_IS_NODE&&process.exit(i),Module.quit(i,new ExitStatus(i)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(i){Module.onAbort&&Module.onAbort(i),i!==void 0?(Module.print(i),Module.printErr(i),i=JSON.stringify(i)):i="",ABORT=!0,EXITSTATUS=1;var o=` -If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,a="abort("+i+") at "+stackTrace()+o;throw abortDecorators&&abortDecorators.forEach(function(c){a=c(a,i)}),a}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit=="function"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var eh=Ke((VW,ST)=>{"use strict";var WI=DT(),VI=wT(),UD=!1,jD=null;VI({},function(i,o){if(!UD){if(UD=!0,i)throw i;jD=o}});if(!UD)throw new Error("Failed to load the yoga module - it needed to be loaded synchronously, but didn't");ST.exports=WI(jD.bind,jD.lib)});var CT=Ke((GW,TT)=>{"use strict";TT.exports=({onlyFirst:i=!1}={})=>{let o=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(o,i?void 0:"g")}});var zD=Ke((YW,xT)=>{"use strict";var GI=CT();xT.exports=i=>typeof i=="string"?i.replace(GI(),""):i});var qD=Ke((KW,HD)=>{"use strict";var RT=i=>Number.isNaN(i)?!1:i>=4352&&(i<=4447||i===9001||i===9002||11904<=i&&i<=12871&&i!==12351||12880<=i&&i<=19903||19968<=i&&i<=42182||43360<=i&&i<=43388||44032<=i&&i<=55203||63744<=i&&i<=64255||65040<=i&&i<=65049||65072<=i&&i<=65131||65281<=i&&i<=65376||65504<=i&&i<=65510||110592<=i&&i<=110593||127488<=i&&i<=127569||131072<=i&&i<=262141);HD.exports=RT;HD.exports.default=RT});var OT=Ke((XW,AT)=>{"use strict";AT.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g}});var Z_=Ke((QW,WD)=>{"use strict";var YI=zD(),KI=qD(),XI=OT(),MT=i=>{if(i=i.replace(XI()," "),typeof i!="string"||i.length===0)return 0;i=YI(i);let o=0;for(let a=0;a=127&&c<=159||c>=768&&c<=879||(c>65535&&a++,o+=KI(c)?2:1)}return o};WD.exports=MT;WD.exports.default=MT});var GD=Ke((JW,VD)=>{"use strict";var QI=Z_(),kT=i=>{let o=0;for(let a of i.split(` -`))o=Math.max(o,QI(a));return o};VD.exports=kT;VD.exports.default=kT});var LT=Ke(Jy=>{"use strict";var JI=Jy&&Jy.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Jy,"__esModule",{value:!0});var ZI=JI(GD()),YD={};Jy.default=i=>{if(i.length===0)return{width:0,height:0};if(YD[i])return YD[i];let o=ZI.default(i),a=i.split(` -`).length;return YD[i]={width:o,height:a},{width:o,height:a}}});var NT=Ke(Zy=>{"use strict";var $I=Zy&&Zy.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Zy,"__esModule",{value:!0});var Vi=$I(eh()),eb=(i,o)=>{"position"in o&&i.setPositionType(o.position==="absolute"?Vi.default.POSITION_TYPE_ABSOLUTE:Vi.default.POSITION_TYPE_RELATIVE)},tb=(i,o)=>{"marginLeft"in o&&i.setMargin(Vi.default.EDGE_START,o.marginLeft||0),"marginRight"in o&&i.setMargin(Vi.default.EDGE_END,o.marginRight||0),"marginTop"in o&&i.setMargin(Vi.default.EDGE_TOP,o.marginTop||0),"marginBottom"in o&&i.setMargin(Vi.default.EDGE_BOTTOM,o.marginBottom||0)},nb=(i,o)=>{"paddingLeft"in o&&i.setPadding(Vi.default.EDGE_LEFT,o.paddingLeft||0),"paddingRight"in o&&i.setPadding(Vi.default.EDGE_RIGHT,o.paddingRight||0),"paddingTop"in o&&i.setPadding(Vi.default.EDGE_TOP,o.paddingTop||0),"paddingBottom"in o&&i.setPadding(Vi.default.EDGE_BOTTOM,o.paddingBottom||0)},rb=(i,o)=>{var a;"flexGrow"in o&&i.setFlexGrow((a=o.flexGrow)!==null&&a!==void 0?a:0),"flexShrink"in o&&i.setFlexShrink(typeof o.flexShrink=="number"?o.flexShrink:1),"flexDirection"in o&&(o.flexDirection==="row"&&i.setFlexDirection(Vi.default.FLEX_DIRECTION_ROW),o.flexDirection==="row-reverse"&&i.setFlexDirection(Vi.default.FLEX_DIRECTION_ROW_REVERSE),o.flexDirection==="column"&&i.setFlexDirection(Vi.default.FLEX_DIRECTION_COLUMN),o.flexDirection==="column-reverse"&&i.setFlexDirection(Vi.default.FLEX_DIRECTION_COLUMN_REVERSE)),"flexBasis"in o&&(typeof o.flexBasis=="number"?i.setFlexBasis(o.flexBasis):typeof o.flexBasis=="string"?i.setFlexBasisPercent(Number.parseInt(o.flexBasis,10)):i.setFlexBasis(NaN)),"alignItems"in o&&((o.alignItems==="stretch"||!o.alignItems)&&i.setAlignItems(Vi.default.ALIGN_STRETCH),o.alignItems==="flex-start"&&i.setAlignItems(Vi.default.ALIGN_FLEX_START),o.alignItems==="center"&&i.setAlignItems(Vi.default.ALIGN_CENTER),o.alignItems==="flex-end"&&i.setAlignItems(Vi.default.ALIGN_FLEX_END)),"alignSelf"in o&&((o.alignSelf==="auto"||!o.alignSelf)&&i.setAlignSelf(Vi.default.ALIGN_AUTO),o.alignSelf==="flex-start"&&i.setAlignSelf(Vi.default.ALIGN_FLEX_START),o.alignSelf==="center"&&i.setAlignSelf(Vi.default.ALIGN_CENTER),o.alignSelf==="flex-end"&&i.setAlignSelf(Vi.default.ALIGN_FLEX_END)),"justifyContent"in o&&((o.justifyContent==="flex-start"||!o.justifyContent)&&i.setJustifyContent(Vi.default.JUSTIFY_FLEX_START),o.justifyContent==="center"&&i.setJustifyContent(Vi.default.JUSTIFY_CENTER),o.justifyContent==="flex-end"&&i.setJustifyContent(Vi.default.JUSTIFY_FLEX_END),o.justifyContent==="space-between"&&i.setJustifyContent(Vi.default.JUSTIFY_SPACE_BETWEEN),o.justifyContent==="space-around"&&i.setJustifyContent(Vi.default.JUSTIFY_SPACE_AROUND))},ib=(i,o)=>{var a,c;"width"in o&&(typeof o.width=="number"?i.setWidth(o.width):typeof o.width=="string"?i.setWidthPercent(Number.parseInt(o.width,10)):i.setWidthAuto()),"height"in o&&(typeof o.height=="number"?i.setHeight(o.height):typeof o.height=="string"?i.setHeightPercent(Number.parseInt(o.height,10)):i.setHeightAuto()),"minWidth"in o&&(typeof o.minWidth=="string"?i.setMinWidthPercent(Number.parseInt(o.minWidth,10)):i.setMinWidth((a=o.minWidth)!==null&&a!==void 0?a:0)),"minHeight"in o&&(typeof o.minHeight=="string"?i.setMinHeightPercent(Number.parseInt(o.minHeight,10)):i.setMinHeight((c=o.minHeight)!==null&&c!==void 0?c:0))},ub=(i,o)=>{"display"in o&&i.setDisplay(o.display==="flex"?Vi.default.DISPLAY_FLEX:Vi.default.DISPLAY_NONE)},ob=(i,o)=>{if("borderStyle"in o){let a=typeof o.borderStyle=="string"?1:0;i.setBorder(Vi.default.EDGE_TOP,a),i.setBorder(Vi.default.EDGE_BOTTOM,a),i.setBorder(Vi.default.EDGE_LEFT,a),i.setBorder(Vi.default.EDGE_RIGHT,a)}};Zy.default=(i,o={})=>{eb(i,o),tb(i,o),nb(i,o),rb(i,o),ib(i,o),ub(i,o),ob(i,o)}});var PT=Ke((eV,FT)=>{"use strict";FT.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var KD=Ke((tV,IT)=>{var $y=PT(),bT={};for(let i of Object.keys($y))bT[$y[i]]=i;var zn={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};IT.exports=zn;for(let i of Object.keys(zn)){if(!("channels"in zn[i]))throw new Error("missing channels property: "+i);if(!("labels"in zn[i]))throw new Error("missing channel labels property: "+i);if(zn[i].labels.length!==zn[i].channels)throw new Error("channel and label counts mismatch: "+i);let{channels:o,labels:a}=zn[i];delete zn[i].channels,delete zn[i].labels,Object.defineProperty(zn[i],"channels",{value:o}),Object.defineProperty(zn[i],"labels",{value:a})}zn.rgb.hsl=function(i){let o=i[0]/255,a=i[1]/255,c=i[2]/255,_=Math.min(o,a,c),t=Math.max(o,a,c),M=t-_,N,O;t===_?N=0:o===t?N=(a-c)/M:a===t?N=2+(c-o)/M:c===t&&(N=4+(o-a)/M),N=Math.min(N*60,360),N<0&&(N+=360);let T=(_+t)/2;return t===_?O=0:T<=.5?O=M/(t+_):O=M/(2-t-_),[N,O*100,T*100]};zn.rgb.hsv=function(i){let o,a,c,_,t,M=i[0]/255,N=i[1]/255,O=i[2]/255,T=Math.max(M,N,O),B=T-Math.min(M,N,O),H=function(q){return(T-q)/6/B+1/2};return B===0?(_=0,t=0):(t=B/T,o=H(M),a=H(N),c=H(O),M===T?_=c-a:N===T?_=1/3+o-c:O===T&&(_=2/3+a-o),_<0?_+=1:_>1&&(_-=1)),[_*360,t*100,T*100]};zn.rgb.hwb=function(i){let o=i[0],a=i[1],c=i[2],_=zn.rgb.hsl(i)[0],t=1/255*Math.min(o,Math.min(a,c));return c=1-1/255*Math.max(o,Math.max(a,c)),[_,t*100,c*100]};zn.rgb.cmyk=function(i){let o=i[0]/255,a=i[1]/255,c=i[2]/255,_=Math.min(1-o,1-a,1-c),t=(1-o-_)/(1-_)||0,M=(1-a-_)/(1-_)||0,N=(1-c-_)/(1-_)||0;return[t*100,M*100,N*100,_*100]};function lb(i,o){return(i[0]-o[0])**2+(i[1]-o[1])**2+(i[2]-o[2])**2}zn.rgb.keyword=function(i){let o=bT[i];if(o)return o;let a=Infinity,c;for(let _ of Object.keys($y)){let t=$y[_],M=lb(i,t);M.04045?((o+.055)/1.055)**2.4:o/12.92,a=a>.04045?((a+.055)/1.055)**2.4:a/12.92,c=c>.04045?((c+.055)/1.055)**2.4:c/12.92;let _=o*.4124+a*.3576+c*.1805,t=o*.2126+a*.7152+c*.0722,M=o*.0193+a*.1192+c*.9505;return[_*100,t*100,M*100]};zn.rgb.lab=function(i){let o=zn.rgb.xyz(i),a=o[0],c=o[1],_=o[2];a/=95.047,c/=100,_/=108.883,a=a>.008856?a**(1/3):7.787*a+16/116,c=c>.008856?c**(1/3):7.787*c+16/116,_=_>.008856?_**(1/3):7.787*_+16/116;let t=116*c-16,M=500*(a-c),N=200*(c-_);return[t,M,N]};zn.hsl.rgb=function(i){let o=i[0]/360,a=i[1]/100,c=i[2]/100,_,t,M;if(a===0)return M=c*255,[M,M,M];c<.5?_=c*(1+a):_=c+a-c*a;let N=2*c-_,O=[0,0,0];for(let T=0;T<3;T++)t=o+1/3*-(T-1),t<0&&t++,t>1&&t--,6*t<1?M=N+(_-N)*6*t:2*t<1?M=_:3*t<2?M=N+(_-N)*(2/3-t)*6:M=N,O[T]=M*255;return O};zn.hsl.hsv=function(i){let o=i[0],a=i[1]/100,c=i[2]/100,_=a,t=Math.max(c,.01);c*=2,a*=c<=1?c:2-c,_*=t<=1?t:2-t;let M=(c+a)/2,N=c===0?2*_/(t+_):2*a/(c+a);return[o,N*100,M*100]};zn.hsv.rgb=function(i){let o=i[0]/60,a=i[1]/100,c=i[2]/100,_=Math.floor(o)%6,t=o-Math.floor(o),M=255*c*(1-a),N=255*c*(1-a*t),O=255*c*(1-a*(1-t));switch(c*=255,_){case 0:return[c,O,M];case 1:return[N,c,M];case 2:return[M,c,O];case 3:return[M,N,c];case 4:return[O,M,c];case 5:return[c,M,N]}};zn.hsv.hsl=function(i){let o=i[0],a=i[1]/100,c=i[2]/100,_=Math.max(c,.01),t,M;M=(2-a)*c;let N=(2-a)*_;return t=a*_,t/=N<=1?N:2-N,t=t||0,M/=2,[o,t*100,M*100]};zn.hwb.rgb=function(i){let o=i[0]/360,a=i[1]/100,c=i[2]/100,_=a+c,t;_>1&&(a/=_,c/=_);let M=Math.floor(6*o),N=1-c;t=6*o-M,(M&1)!=0&&(t=1-t);let O=a+t*(N-a),T,B,H;switch(M){default:case 6:case 0:T=N,B=O,H=a;break;case 1:T=O,B=N,H=a;break;case 2:T=a,B=N,H=O;break;case 3:T=a,B=O,H=N;break;case 4:T=O,B=a,H=N;break;case 5:T=N,B=a,H=O;break}return[T*255,B*255,H*255]};zn.cmyk.rgb=function(i){let o=i[0]/100,a=i[1]/100,c=i[2]/100,_=i[3]/100,t=1-Math.min(1,o*(1-_)+_),M=1-Math.min(1,a*(1-_)+_),N=1-Math.min(1,c*(1-_)+_);return[t*255,M*255,N*255]};zn.xyz.rgb=function(i){let o=i[0]/100,a=i[1]/100,c=i[2]/100,_,t,M;return _=o*3.2406+a*-1.5372+c*-.4986,t=o*-.9689+a*1.8758+c*.0415,M=o*.0557+a*-.204+c*1.057,_=_>.0031308?1.055*_**(1/2.4)-.055:_*12.92,t=t>.0031308?1.055*t**(1/2.4)-.055:t*12.92,M=M>.0031308?1.055*M**(1/2.4)-.055:M*12.92,_=Math.min(Math.max(0,_),1),t=Math.min(Math.max(0,t),1),M=Math.min(Math.max(0,M),1),[_*255,t*255,M*255]};zn.xyz.lab=function(i){let o=i[0],a=i[1],c=i[2];o/=95.047,a/=100,c/=108.883,o=o>.008856?o**(1/3):7.787*o+16/116,a=a>.008856?a**(1/3):7.787*a+16/116,c=c>.008856?c**(1/3):7.787*c+16/116;let _=116*a-16,t=500*(o-a),M=200*(a-c);return[_,t,M]};zn.lab.xyz=function(i){let o=i[0],a=i[1],c=i[2],_,t,M;t=(o+16)/116,_=a/500+t,M=t-c/200;let N=t**3,O=_**3,T=M**3;return t=N>.008856?N:(t-16/116)/7.787,_=O>.008856?O:(_-16/116)/7.787,M=T>.008856?T:(M-16/116)/7.787,_*=95.047,t*=100,M*=108.883,[_,t,M]};zn.lab.lch=function(i){let o=i[0],a=i[1],c=i[2],_;_=Math.atan2(c,a)*360/2/Math.PI,_<0&&(_+=360);let M=Math.sqrt(a*a+c*c);return[o,M,_]};zn.lch.lab=function(i){let o=i[0],a=i[1],_=i[2]/360*2*Math.PI,t=a*Math.cos(_),M=a*Math.sin(_);return[o,t,M]};zn.rgb.ansi16=function(i,o=null){let[a,c,_]=i,t=o===null?zn.rgb.hsv(i)[2]:o;if(t=Math.round(t/50),t===0)return 30;let M=30+(Math.round(_/255)<<2|Math.round(c/255)<<1|Math.round(a/255));return t===2&&(M+=60),M};zn.hsv.ansi16=function(i){return zn.rgb.ansi16(zn.hsv.rgb(i),i[2])};zn.rgb.ansi256=function(i){let o=i[0],a=i[1],c=i[2];return o===a&&a===c?o<8?16:o>248?231:Math.round((o-8)/247*24)+232:16+36*Math.round(o/255*5)+6*Math.round(a/255*5)+Math.round(c/255*5)};zn.ansi16.rgb=function(i){let o=i%10;if(o===0||o===7)return i>50&&(o+=3.5),o=o/10.5*255,[o,o,o];let a=(~~(i>50)+1)*.5,c=(o&1)*a*255,_=(o>>1&1)*a*255,t=(o>>2&1)*a*255;return[c,_,t]};zn.ansi256.rgb=function(i){if(i>=232){let t=(i-232)*10+8;return[t,t,t]}i-=16;let o,a=Math.floor(i/36)/5*255,c=Math.floor((o=i%36)/6)/5*255,_=o%6/5*255;return[a,c,_]};zn.rgb.hex=function(i){let a=(((Math.round(i[0])&255)<<16)+((Math.round(i[1])&255)<<8)+(Math.round(i[2])&255)).toString(16).toUpperCase();return"000000".substring(a.length)+a};zn.hex.rgb=function(i){let o=i.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!o)return[0,0,0];let a=o[0];o[0].length===3&&(a=a.split("").map(N=>N+N).join(""));let c=parseInt(a,16),_=c>>16&255,t=c>>8&255,M=c&255;return[_,t,M]};zn.rgb.hcg=function(i){let o=i[0]/255,a=i[1]/255,c=i[2]/255,_=Math.max(Math.max(o,a),c),t=Math.min(Math.min(o,a),c),M=_-t,N,O;return M<1?N=t/(1-M):N=0,M<=0?O=0:_===o?O=(a-c)/M%6:_===a?O=2+(c-o)/M:O=4+(o-a)/M,O/=6,O%=1,[O*360,M*100,N*100]};zn.hsl.hcg=function(i){let o=i[1]/100,a=i[2]/100,c=a<.5?2*o*a:2*o*(1-a),_=0;return c<1&&(_=(a-.5*c)/(1-c)),[i[0],c*100,_*100]};zn.hsv.hcg=function(i){let o=i[1]/100,a=i[2]/100,c=o*a,_=0;return c<1&&(_=(a-c)/(1-c)),[i[0],c*100,_*100]};zn.hcg.rgb=function(i){let o=i[0]/360,a=i[1]/100,c=i[2]/100;if(a===0)return[c*255,c*255,c*255];let _=[0,0,0],t=o%1*6,M=t%1,N=1-M,O=0;switch(Math.floor(t)){case 0:_[0]=1,_[1]=M,_[2]=0;break;case 1:_[0]=N,_[1]=1,_[2]=0;break;case 2:_[0]=0,_[1]=1,_[2]=M;break;case 3:_[0]=0,_[1]=N,_[2]=1;break;case 4:_[0]=M,_[1]=0,_[2]=1;break;default:_[0]=1,_[1]=0,_[2]=N}return O=(1-a)*c,[(a*_[0]+O)*255,(a*_[1]+O)*255,(a*_[2]+O)*255]};zn.hcg.hsv=function(i){let o=i[1]/100,a=i[2]/100,c=o+a*(1-o),_=0;return c>0&&(_=o/c),[i[0],_*100,c*100]};zn.hcg.hsl=function(i){let o=i[1]/100,c=i[2]/100*(1-o)+.5*o,_=0;return c>0&&c<.5?_=o/(2*c):c>=.5&&c<1&&(_=o/(2*(1-c))),[i[0],_*100,c*100]};zn.hcg.hwb=function(i){let o=i[1]/100,a=i[2]/100,c=o+a*(1-o);return[i[0],(c-o)*100,(1-c)*100]};zn.hwb.hcg=function(i){let o=i[1]/100,a=i[2]/100,c=1-a,_=c-o,t=0;return _<1&&(t=(c-_)/(1-_)),[i[0],_*100,t*100]};zn.apple.rgb=function(i){return[i[0]/65535*255,i[1]/65535*255,i[2]/65535*255]};zn.rgb.apple=function(i){return[i[0]/255*65535,i[1]/255*65535,i[2]/255*65535]};zn.gray.rgb=function(i){return[i[0]/100*255,i[0]/100*255,i[0]/100*255]};zn.gray.hsl=function(i){return[0,0,i[0]]};zn.gray.hsv=zn.gray.hsl;zn.gray.hwb=function(i){return[0,100,i[0]]};zn.gray.cmyk=function(i){return[0,0,0,i[0]]};zn.gray.lab=function(i){return[i[0],0,0]};zn.gray.hex=function(i){let o=Math.round(i[0]/100*255)&255,c=((o<<16)+(o<<8)+o).toString(16).toUpperCase();return"000000".substring(c.length)+c};zn.rgb.gray=function(i){return[(i[0]+i[1]+i[2])/3/255*100]}});var UT=Ke((nV,BT)=>{var $_=KD();function sb(){let i={},o=Object.keys($_);for(let a=o.length,c=0;c{var XD=KD(),db=UT(),Qv={},pb=Object.keys(XD);function hb(i){let o=function(...a){let c=a[0];return c==null?c:(c.length>1&&(a=c),i(a))};return"conversion"in i&&(o.conversion=i.conversion),o}function vb(i){let o=function(...a){let c=a[0];if(c==null)return c;c.length>1&&(a=c);let _=i(a);if(typeof _=="object")for(let t=_.length,M=0;M{Qv[i]={},Object.defineProperty(Qv[i],"channels",{value:XD[i].channels}),Object.defineProperty(Qv[i],"labels",{value:XD[i].labels});let o=db(i);Object.keys(o).forEach(c=>{let _=o[c];Qv[i][c]=vb(_),Qv[i][c].raw=hb(_)})});jT.exports=Qv});var t4=Ke((iV,HT)=>{"use strict";var qT=(i,o)=>(...a)=>`[${i(...a)+o}m`,WT=(i,o)=>(...a)=>{let c=i(...a);return`[${38+o};5;${c}m`},VT=(i,o)=>(...a)=>{let c=i(...a);return`[${38+o};2;${c[0]};${c[1]};${c[2]}m`},e4=i=>i,GT=(i,o,a)=>[i,o,a],Jv=(i,o,a)=>{Object.defineProperty(i,o,{get:()=>{let c=a();return Object.defineProperty(i,o,{value:c,enumerable:!0,configurable:!0}),c},enumerable:!0,configurable:!0})},QD,Zv=(i,o,a,c)=>{QD===void 0&&(QD=zT());let _=c?10:0,t={};for(let[M,N]of Object.entries(QD)){let O=M==="ansi16"?"ansi":M;M===o?t[O]=i(a,_):typeof N=="object"&&(t[O]=i(N[o],_))}return t};function mb(){let i=new Map,o={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};o.color.gray=o.color.blackBright,o.bgColor.bgGray=o.bgColor.bgBlackBright,o.color.grey=o.color.blackBright,o.bgColor.bgGrey=o.bgColor.bgBlackBright;for(let[a,c]of Object.entries(o)){for(let[_,t]of Object.entries(c))o[_]={open:`[${t[0]}m`,close:`[${t[1]}m`},c[_]=o[_],i.set(t[0],t[1]);Object.defineProperty(o,a,{value:c,enumerable:!1})}return Object.defineProperty(o,"codes",{value:i,enumerable:!1}),o.color.close="",o.bgColor.close="",Jv(o.color,"ansi",()=>Zv(qT,"ansi16",e4,!1)),Jv(o.color,"ansi256",()=>Zv(WT,"ansi256",e4,!1)),Jv(o.color,"ansi16m",()=>Zv(VT,"rgb",GT,!1)),Jv(o.bgColor,"ansi",()=>Zv(qT,"ansi16",e4,!0)),Jv(o.bgColor,"ansi256",()=>Zv(WT,"ansi256",e4,!0)),Jv(o.bgColor,"ansi16m",()=>Zv(VT,"rgb",GT,!0)),o}Object.defineProperty(HT,"exports",{enumerable:!0,get:mb})});var XT=Ke((uV,YT)=>{"use strict";var eg=Z_(),yb=zD(),gb=t4(),JD=new Set(["","\x9B"]),_b=39,KT=i=>`${JD.values().next().value}[${i}m`,Eb=i=>i.split(" ").map(o=>eg(o)),ZD=(i,o,a)=>{let c=[...o],_=!1,t=eg(yb(i[i.length-1]));for(let[M,N]of c.entries()){let O=eg(N);if(t+O<=a?i[i.length-1]+=N:(i.push(N),t=0),JD.has(N))_=!0;else if(_&&N==="m"){_=!1;continue}_||(t+=O,t===a&&M0&&i.length>1&&(i[i.length-2]+=i.pop())},Db=i=>{let o=i.split(" "),a=o.length;for(;a>0&&!(eg(o[a-1])>0);)a--;return a===o.length?i:o.slice(0,a).join(" ")+o.slice(a).join("")},wb=(i,o,a={})=>{if(a.trim!==!1&&i.trim()==="")return"";let c="",_="",t,M=Eb(i),N=[""];for(let[O,T]of i.split(" ").entries()){a.trim!==!1&&(N[N.length-1]=N[N.length-1].trimLeft());let B=eg(N[N.length-1]);if(O!==0&&(B>=o&&(a.wordWrap===!1||a.trim===!1)&&(N.push(""),B=0),(B>0||a.trim===!1)&&(N[N.length-1]+=" ",B++)),a.hard&&M[O]>o){let H=o-B,q=1+Math.floor((M[O]-H-1)/o);Math.floor((M[O]-1)/o)o&&B>0&&M[O]>0){if(a.wordWrap===!1&&Bo&&a.wordWrap===!1){ZD(N,T,o);continue}N[N.length-1]+=T}a.trim!==!1&&(N=N.map(Db)),c=N.join(` -`);for(let[O,T]of[...c].entries()){if(_+=T,JD.has(T)){let H=parseFloat(/\d[^m]*/.exec(c.slice(O,O+4)));t=H===_b?null:H}let B=gb.codes.get(Number(t));t&&B&&(c[O+1]===` -`?_+=KT(B):T===` -`&&(_+=KT(t)))}return _};YT.exports=(i,o,a)=>String(i).normalize().replace(/\r\n/g,` -`).split(` -`).map(c=>wb(c,o,a)).join(` -`)});var ZT=Ke((oV,QT)=>{"use strict";var JT="[\uD800-\uDBFF][\uDC00-\uDFFF]",Sb=i=>i&&i.exact?new RegExp(`^${JT}$`):new RegExp(JT,"g");QT.exports=Sb});var $D=Ke((lV,$T)=>{"use strict";var Tb=qD(),Cb=ZT(),eC=t4(),tC=["","\x9B"],n4=i=>`${tC[0]}[${i}m`,nC=(i,o,a)=>{let c=[];i=[...i];for(let _ of i){let t=_;_.match(";")&&(_=_.split(";")[0][0]+"0");let M=eC.codes.get(parseInt(_,10));if(M){let N=i.indexOf(M.toString());N>=0?i.splice(N,1):c.push(n4(o?M:t))}else if(o){c.push(n4(0));break}else c.push(n4(t))}if(o&&(c=c.filter((_,t)=>c.indexOf(_)===t),a!==void 0)){let _=n4(eC.codes.get(parseInt(a,10)));c=c.reduce((t,M)=>M===_?[M,...t]:[...t,M],[])}return c.join("")};$T.exports=(i,o,a)=>{let c=[...i.normalize()],_=[];a=typeof a=="number"?a:c.length;let t=!1,M,N=0,O="";for(let[T,B]of c.entries()){let H=!1;if(tC.includes(B)){let q=/\d[^m]*/.exec(i.slice(T,T+18));M=q&&q.length>0?q[0]:void 0,No&&N<=a)O+=B;else if(N===o&&!t&&M!==void 0)O=nC(_);else if(N>=a){O+=nC(_,!0,M);break}}return O}});var iC=Ke((sV,rC)=>{"use strict";var p2=$D(),xb=Z_();function r4(i,o,a){if(i.charAt(o)===" ")return o;for(let c=1;c<=3;c++)if(a){if(i.charAt(o+c)===" ")return o+c}else if(i.charAt(o-c)===" ")return o-c;return o}rC.exports=(i,o,a)=>{a=qt({position:"end",preferTruncationOnSpace:!1},a);let{position:c,space:_,preferTruncationOnSpace:t}=a,M="\u2026",N=1;if(typeof i!="string")throw new TypeError(`Expected \`input\` to be a string, got ${typeof i}`);if(typeof o!="number")throw new TypeError(`Expected \`columns\` to be a number, got ${typeof o}`);if(o<1)return"";if(o===1)return M;let O=xb(i);if(O<=o)return i;if(c==="start"){if(t){let T=r4(i,O-o+1,!0);return M+p2(i,T,O).trim()}return _===!0&&(M+=" ",N=2),M+p2(i,O-o+N,O)}if(c==="middle"){_===!0&&(M=" "+M+" ",N=3);let T=Math.floor(o/2);if(t){let B=r4(i,T),H=r4(i,O-(o-T)+1,!0);return p2(i,0,B)+M+p2(i,H,O).trim()}return p2(i,0,T)+M+p2(i,O-(o-T)+N,O)}if(c==="end"){if(t){let T=r4(i,o-1);return p2(i,0,T)+M}return _===!0&&(M=" "+M,N=2),p2(i,0,o-N)+M}throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${c}`)}});var tw=Ke(tg=>{"use strict";var uC=tg&&tg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(tg,"__esModule",{value:!0});var Rb=uC(XT()),Ab=uC(iC()),ew={};tg.default=(i,o,a)=>{let c=i+String(o)+String(a);if(ew[c])return ew[c];let _=i;if(a==="wrap"&&(_=Rb.default(i,o,{trim:!1,hard:!0})),a.startsWith("truncate")){let t="end";a==="truncate-middle"&&(t="middle"),a==="truncate-start"&&(t="start"),_=Ab.default(i,o,{position:t})}return ew[c]=_,_}});var rw=Ke(nw=>{"use strict";Object.defineProperty(nw,"__esModule",{value:!0});var oC=i=>{let o="";if(i.childNodes.length>0)for(let a of i.childNodes){let c="";a.nodeName==="#text"?c=a.nodeValue:((a.nodeName==="ink-text"||a.nodeName==="ink-virtual-text")&&(c=oC(a)),c.length>0&&typeof a.internal_transform=="function"&&(c=a.internal_transform(c))),o+=c}return o};nw.default=oC});var iw=Ke(co=>{"use strict";var ng=co&&co.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(co,"__esModule",{value:!0});co.setTextNodeValue=co.createTextNode=co.setStyle=co.setAttribute=co.removeChildNode=co.insertBeforeNode=co.appendChildNode=co.createNode=co.TEXT_NAME=void 0;var Ob=ng(eh()),lC=ng(LT()),Mb=ng(NT()),kb=ng(tw()),Lb=ng(rw());co.TEXT_NAME="#text";co.createNode=i=>{var o;let a={nodeName:i,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:i==="ink-virtual-text"?void 0:Ob.default.Node.create()};return i==="ink-text"&&((o=a.yogaNode)===null||o===void 0||o.setMeasureFunc(Nb.bind(null,a))),a};co.appendChildNode=(i,o)=>{var a;o.parentNode&&co.removeChildNode(o.parentNode,o),o.parentNode=i,i.childNodes.push(o),o.yogaNode&&((a=i.yogaNode)===null||a===void 0||a.insertChild(o.yogaNode,i.yogaNode.getChildCount())),(i.nodeName==="ink-text"||i.nodeName==="ink-virtual-text")&&i4(i)};co.insertBeforeNode=(i,o,a)=>{var c,_;o.parentNode&&co.removeChildNode(o.parentNode,o),o.parentNode=i;let t=i.childNodes.indexOf(a);if(t>=0){i.childNodes.splice(t,0,o),o.yogaNode&&((c=i.yogaNode)===null||c===void 0||c.insertChild(o.yogaNode,t));return}i.childNodes.push(o),o.yogaNode&&((_=i.yogaNode)===null||_===void 0||_.insertChild(o.yogaNode,i.yogaNode.getChildCount())),(i.nodeName==="ink-text"||i.nodeName==="ink-virtual-text")&&i4(i)};co.removeChildNode=(i,o)=>{var a,c;o.yogaNode&&((c=(a=o.parentNode)===null||a===void 0?void 0:a.yogaNode)===null||c===void 0||c.removeChild(o.yogaNode)),o.parentNode=null;let _=i.childNodes.indexOf(o);_>=0&&i.childNodes.splice(_,1),(i.nodeName==="ink-text"||i.nodeName==="ink-virtual-text")&&i4(i)};co.setAttribute=(i,o,a)=>{i.attributes[o]=a};co.setStyle=(i,o)=>{i.style=o,i.yogaNode&&Mb.default(i.yogaNode,o)};co.createTextNode=i=>{let o={nodeName:"#text",nodeValue:i,yogaNode:void 0,parentNode:null,style:{}};return co.setTextNodeValue(o,i),o};var Nb=function(i,o){var a,c;let _=i.nodeName==="#text"?i.nodeValue:Lb.default(i),t=lC.default(_);if(t.width<=o||t.width>=1&&o>0&&o<1)return t;let M=(c=(a=i.style)===null||a===void 0?void 0:a.textWrap)!==null&&c!==void 0?c:"wrap",N=kb.default(_,o,M);return lC.default(N)},sC=i=>{var o;if(!(!i||!i.parentNode))return(o=i.yogaNode)!==null&&o!==void 0?o:sC(i.parentNode)},i4=i=>{let o=sC(i);o==null||o.markDirty()};co.setTextNodeValue=(i,o)=>{typeof o!="string"&&(o=String(o)),i.nodeValue=o,i4(i)}});var th=Ke((dV,aC)=>{"use strict";aC.exports={BINARY_TYPES:["nodebuffer","arraybuffer","fragments"],GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),EMPTY_BUFFER:Buffer.alloc(0),NOOP:()=>{}}});var rg=Ke((pV,uw)=>{"use strict";var{EMPTY_BUFFER:Fb}=th();function fC(i,o){if(i.length===0)return Fb;if(i.length===1)return i[0];let a=Buffer.allocUnsafe(o),c=0;for(let _=0;_{"use strict";var vC=Symbol("kDone"),ow=Symbol("kRun"),mC=class{constructor(o){this[vC]=()=>{this.pending--,this[ow]()},this.concurrency=o||Infinity,this.jobs=[],this.pending=0}add(o){this.jobs.push(o),this[ow]()}[ow](){if(this.pending!==this.concurrency&&this.jobs.length){let o=this.jobs.shift();this.pending++,o(this[vC])}}};hC.exports=mC});var og=Ke((vV,gC)=>{"use strict";var ig=require("zlib"),_C=rg(),Pb=yC(),{kStatusCode:EC,NOOP:Ib}=th(),bb=Buffer.from([0,0,255,255]),o4=Symbol("permessage-deflate"),X1=Symbol("total-length"),ug=Symbol("callback"),h2=Symbol("buffers"),lw=Symbol("error"),l4,DC=class{constructor(o,a,c){if(this._maxPayload=c|0,this._options=o||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._isServer=!!a,this._deflate=null,this._inflate=null,this.params=null,!l4){let _=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;l4=new Pb(_)}}static get extensionName(){return"permessage-deflate"}offer(){let o={};return this._options.serverNoContextTakeover&&(o.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(o.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(o.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?o.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits==null&&(o.client_max_window_bits=!0),o}accept(o){return o=this.normalizeParams(o),this.params=this._isServer?this.acceptAsServer(o):this.acceptAsClient(o),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){let o=this._deflate[ug];this._deflate.close(),this._deflate=null,o&&o(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(o){let a=this._options,c=o.find(_=>!(a.serverNoContextTakeover===!1&&_.server_no_context_takeover||_.server_max_window_bits&&(a.serverMaxWindowBits===!1||typeof a.serverMaxWindowBits=="number"&&a.serverMaxWindowBits>_.server_max_window_bits)||typeof a.clientMaxWindowBits=="number"&&!_.client_max_window_bits));if(!c)throw new Error("None of the extension offers can be accepted");return a.serverNoContextTakeover&&(c.server_no_context_takeover=!0),a.clientNoContextTakeover&&(c.client_no_context_takeover=!0),typeof a.serverMaxWindowBits=="number"&&(c.server_max_window_bits=a.serverMaxWindowBits),typeof a.clientMaxWindowBits=="number"?c.client_max_window_bits=a.clientMaxWindowBits:(c.client_max_window_bits===!0||a.clientMaxWindowBits===!1)&&delete c.client_max_window_bits,c}acceptAsClient(o){let a=o[0];if(this._options.clientNoContextTakeover===!1&&a.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(!a.client_max_window_bits)typeof this._options.clientMaxWindowBits=="number"&&(a.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits=="number"&&a.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"');return a}normalizeParams(o){return o.forEach(a=>{Object.keys(a).forEach(c=>{let _=a[c];if(_.length>1)throw new Error(`Parameter "${c}" must have only a single value`);if(_=_[0],c==="client_max_window_bits"){if(_!==!0){let t=+_;if(!Number.isInteger(t)||t<8||t>15)throw new TypeError(`Invalid value for parameter "${c}": ${_}`);_=t}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${c}": ${_}`)}else if(c==="server_max_window_bits"){let t=+_;if(!Number.isInteger(t)||t<8||t>15)throw new TypeError(`Invalid value for parameter "${c}": ${_}`);_=t}else if(c==="client_no_context_takeover"||c==="server_no_context_takeover"){if(_!==!0)throw new TypeError(`Invalid value for parameter "${c}": ${_}`)}else throw new Error(`Unknown parameter "${c}"`);a[c]=_})}),o}decompress(o,a,c){l4.add(_=>{this._decompress(o,a,(t,M)=>{_(),c(t,M)})})}compress(o,a,c){l4.add(_=>{this._compress(o,a,(t,M)=>{_(),c(t,M)})})}_decompress(o,a,c){let _=this._isServer?"client":"server";if(!this._inflate){let t=`${_}_max_window_bits`,M=typeof this.params[t]!="number"?ig.Z_DEFAULT_WINDOWBITS:this.params[t];this._inflate=ig.createInflateRaw(Zr(qt({},this._options.zlibInflateOptions),{windowBits:M})),this._inflate[o4]=this,this._inflate[X1]=0,this._inflate[h2]=[],this._inflate.on("error",Ub),this._inflate.on("data",wC)}this._inflate[ug]=c,this._inflate.write(o),a&&this._inflate.write(bb),this._inflate.flush(()=>{let t=this._inflate[lw];if(t){this._inflate.close(),this._inflate=null,c(t);return}let M=_C.concat(this._inflate[h2],this._inflate[X1]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[X1]=0,this._inflate[h2]=[],a&&this.params[`${_}_no_context_takeover`]&&this._inflate.reset()),c(null,M)})}_compress(o,a,c){let _=this._isServer?"server":"client";if(!this._deflate){let t=`${_}_max_window_bits`,M=typeof this.params[t]!="number"?ig.Z_DEFAULT_WINDOWBITS:this.params[t];this._deflate=ig.createDeflateRaw(Zr(qt({},this._options.zlibDeflateOptions),{windowBits:M})),this._deflate[X1]=0,this._deflate[h2]=[],this._deflate.on("error",Ib),this._deflate.on("data",Bb)}this._deflate[ug]=c,this._deflate.write(o),this._deflate.flush(ig.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let t=_C.concat(this._deflate[h2],this._deflate[X1]);a&&(t=t.slice(0,t.length-4)),this._deflate[ug]=null,this._deflate[X1]=0,this._deflate[h2]=[],a&&this.params[`${_}_no_context_takeover`]&&this._deflate.reset(),c(null,t)})}};gC.exports=DC;function Bb(i){this[h2].push(i),this[X1]+=i.length}function wC(i){if(this[X1]+=i.length,this[o4]._maxPayload<1||this[X1]<=this[o4]._maxPayload){this[h2].push(i);return}this[lw]=new RangeError("Max payload size exceeded"),this[lw][EC]=1009,this.removeListener("data",wC),this.reset()}function Ub(i){this[o4]._inflate=null,i[EC]=1007,this[ug](i)}});var aw=Ke((mV,sw)=>{"use strict";function SC(i){return i>=1e3&&i<=1014&&i!==1004&&i!==1005&&i!==1006||i>=3e3&&i<=4999}function TC(i){let o=i.length,a=0;for(;a=o||(i[a+1]&192)!=128||(i[a+2]&192)!=128||i[a]===224&&(i[a+1]&224)==128||i[a]===237&&(i[a+1]&224)==160)return!1;a+=3}else if((i[a]&248)==240){if(a+3>=o||(i[a+1]&192)!=128||(i[a+2]&192)!=128||(i[a+3]&192)!=128||i[a]===240&&(i[a+1]&240)==128||i[a]===244&&i[a+1]>143||i[a]>244)return!1;a+=4}else return!1;return!0}try{let i=require("utf-8-validate");typeof i=="object"&&(i=i.Validation.isValidUTF8),sw.exports={isValidStatusCode:SC,isValidUTF8(o){return o.length<150?TC(o):i(o)}}}catch(i){sw.exports={isValidStatusCode:SC,isValidUTF8:TC}}});var dw=Ke((yV,CC)=>{"use strict";var{Writable:jb}=require("stream"),xC=og(),{BINARY_TYPES:zb,EMPTY_BUFFER:Hb,kStatusCode:qb,kWebSocket:Wb}=th(),{concat:fw,toArrayBuffer:Vb,unmask:Gb}=rg(),{isValidStatusCode:Yb,isValidUTF8:RC}=aw(),lg=0,AC=1,OC=2,MC=3,cw=4,Kb=5,kC=class extends jb{constructor(o,a,c,_){super();this._binaryType=o||zb[0],this[Wb]=void 0,this._extensions=a||{},this._isServer=!!c,this._maxPayload=_|0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._state=lg,this._loop=!1}_write(o,a,c){if(this._opcode===8&&this._state==lg)return c();this._bufferedBytes+=o.length,this._buffers.push(o),this.startLoop(c)}consume(o){if(this._bufferedBytes-=o,o===this._buffers[0].length)return this._buffers.shift();if(o=c.length?a.set(this._buffers.shift(),_):(a.set(new Uint8Array(c.buffer,c.byteOffset,o),_),this._buffers[0]=c.slice(o)),o-=c.length}while(o>0);return a}startLoop(o){let a;this._loop=!0;do switch(this._state){case lg:a=this.getInfo();break;case AC:a=this.getPayloadLength16();break;case OC:a=this.getPayloadLength64();break;case MC:this.getMask();break;case cw:a=this.getData(o);break;default:this._loop=!1;return}while(this._loop);o(a)}getInfo(){if(this._bufferedBytes<2){this._loop=!1;return}let o=this.consume(2);if((o[0]&48)!=0)return this._loop=!1,K0(RangeError,"RSV2 and RSV3 must be clear",!0,1002);let a=(o[0]&64)==64;if(a&&!this._extensions[xC.extensionName])return this._loop=!1,K0(RangeError,"RSV1 must be clear",!0,1002);if(this._fin=(o[0]&128)==128,this._opcode=o[0]&15,this._payloadLength=o[1]&127,this._opcode===0){if(a)return this._loop=!1,K0(RangeError,"RSV1 must be clear",!0,1002);if(!this._fragmented)return this._loop=!1,K0(RangeError,"invalid opcode 0",!0,1002);this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented)return this._loop=!1,K0(RangeError,`invalid opcode ${this._opcode}`,!0,1002);this._compressed=a}else if(this._opcode>7&&this._opcode<11){if(!this._fin)return this._loop=!1,K0(RangeError,"FIN must be set",!0,1002);if(a)return this._loop=!1,K0(RangeError,"RSV1 must be clear",!0,1002);if(this._payloadLength>125)return this._loop=!1,K0(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002)}else return this._loop=!1,K0(RangeError,`invalid opcode ${this._opcode}`,!0,1002);if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(o[1]&128)==128,this._isServer){if(!this._masked)return this._loop=!1,K0(RangeError,"MASK must be set",!0,1002)}else if(this._masked)return this._loop=!1,K0(RangeError,"MASK must be clear",!0,1002);if(this._payloadLength===126)this._state=AC;else if(this._payloadLength===127)this._state=OC;else return this.haveLength()}getPayloadLength16(){if(this._bufferedBytes<2){this._loop=!1;return}return this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength()}getPayloadLength64(){if(this._bufferedBytes<8){this._loop=!1;return}let o=this.consume(8),a=o.readUInt32BE(0);return a>Math.pow(2,53-32)-1?(this._loop=!1,K0(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009)):(this._payloadLength=a*Math.pow(2,32)+o.readUInt32BE(4),this.haveLength())}haveLength(){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0))return this._loop=!1,K0(RangeError,"Max payload size exceeded",!1,1009);this._masked?this._state=MC:this._state=cw}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=cw}getData(o){let a=Hb;if(this._payloadLength){if(this._bufferedBytes7)return this.controlMessage(a);if(this._compressed){this._state=Kb,this.decompress(a,o);return}return a.length&&(this._messageLength=this._totalPayloadLength,this._fragments.push(a)),this.dataMessage()}decompress(o,a){this._extensions[xC.extensionName].decompress(o,this._fin,(_,t)=>{if(_)return a(_);if(t.length){if(this._messageLength+=t.length,this._messageLength>this._maxPayload&&this._maxPayload>0)return a(K0(RangeError,"Max payload size exceeded",!1,1009));this._fragments.push(t)}let M=this.dataMessage();if(M)return a(M);this.startLoop(a)})}dataMessage(){if(this._fin){let o=this._messageLength,a=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],this._opcode===2){let c;this._binaryType==="nodebuffer"?c=fw(a,o):this._binaryType==="arraybuffer"?c=Vb(fw(a,o)):c=a,this.emit("message",c)}else{let c=fw(a,o);if(!RC(c))return this._loop=!1,K0(Error,"invalid UTF-8 sequence",!0,1007);this.emit("message",c.toString())}}this._state=lg}controlMessage(o){if(this._opcode===8)if(this._loop=!1,o.length===0)this.emit("conclude",1005,""),this.end();else{if(o.length===1)return K0(RangeError,"invalid payload length 1",!0,1002);{let a=o.readUInt16BE(0);if(!Yb(a))return K0(RangeError,`invalid status code ${a}`,!0,1002);let c=o.slice(2);if(!RC(c))return K0(Error,"invalid UTF-8 sequence",!0,1007);this.emit("conclude",a,c.toString()),this.end()}}else this._opcode===9?this.emit("ping",o):this.emit("pong",o);this._state=lg}};CC.exports=kC;function K0(i,o,a,c){let _=new i(a?`Invalid WebSocket frame: ${o}`:o);return Error.captureStackTrace(_,K0),_[qb]=c,_}});var pw=Ke((gV,LC)=>{"use strict";var{randomFillSync:Xb}=require("crypto"),NC=og(),{EMPTY_BUFFER:Qb}=th(),{isValidStatusCode:Jb}=aw(),{mask:FC,toBuffer:Q1}=rg(),nh=Buffer.alloc(4),J1=class{constructor(o,a){this._extensions=a||{},this._socket=o,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._deflating=!1,this._queue=[]}static frame(o,a){let c=a.mask&&a.readOnly,_=a.mask?6:2,t=o.length;o.length>=65536?(_+=8,t=127):o.length>125&&(_+=2,t=126);let M=Buffer.allocUnsafe(c?o.length+_:_);return M[0]=a.fin?a.opcode|128:a.opcode,a.rsv1&&(M[0]|=64),M[1]=t,t===126?M.writeUInt16BE(o.length,2):t===127&&(M.writeUInt32BE(0,2),M.writeUInt32BE(o.length,6)),a.mask?(Xb(nh,0,4),M[1]|=128,M[_-4]=nh[0],M[_-3]=nh[1],M[_-2]=nh[2],M[_-1]=nh[3],c?(FC(o,nh,M,_,o.length),[M]):(FC(o,nh,o,0,o.length),[M,o])):[M,o]}close(o,a,c,_){let t;if(o===void 0)t=Qb;else{if(typeof o!="number"||!Jb(o))throw new TypeError("First argument must be a valid error code number");if(a===void 0||a==="")t=Buffer.allocUnsafe(2),t.writeUInt16BE(o,0);else{let M=Buffer.byteLength(a);if(M>123)throw new RangeError("The message must not be greater than 123 bytes");t=Buffer.allocUnsafe(2+M),t.writeUInt16BE(o,0),t.write(a,2)}}this._deflating?this.enqueue([this.doClose,t,c,_]):this.doClose(t,c,_)}doClose(o,a,c){this.sendFrame(J1.frame(o,{fin:!0,rsv1:!1,opcode:8,mask:a,readOnly:!1}),c)}ping(o,a,c){let _=Q1(o);if(_.length>125)throw new RangeError("The data size must not be greater than 125 bytes");this._deflating?this.enqueue([this.doPing,_,a,Q1.readOnly,c]):this.doPing(_,a,Q1.readOnly,c)}doPing(o,a,c,_){this.sendFrame(J1.frame(o,{fin:!0,rsv1:!1,opcode:9,mask:a,readOnly:c}),_)}pong(o,a,c){let _=Q1(o);if(_.length>125)throw new RangeError("The data size must not be greater than 125 bytes");this._deflating?this.enqueue([this.doPong,_,a,Q1.readOnly,c]):this.doPong(_,a,Q1.readOnly,c)}doPong(o,a,c,_){this.sendFrame(J1.frame(o,{fin:!0,rsv1:!1,opcode:10,mask:a,readOnly:c}),_)}send(o,a,c){let _=Q1(o),t=this._extensions[NC.extensionName],M=a.binary?2:1,N=a.compress;if(this._firstFragment?(this._firstFragment=!1,N&&t&&(N=_.length>=t._threshold),this._compress=N):(N=!1,M=0),a.fin&&(this._firstFragment=!0),t){let O={fin:a.fin,rsv1:N,opcode:M,mask:a.mask,readOnly:Q1.readOnly};this._deflating?this.enqueue([this.dispatch,_,this._compress,O,c]):this.dispatch(_,this._compress,O,c)}else this.sendFrame(J1.frame(_,{fin:a.fin,rsv1:!1,opcode:M,mask:a.mask,readOnly:Q1.readOnly}),c)}dispatch(o,a,c,_){if(!a){this.sendFrame(J1.frame(o,c),_);return}let t=this._extensions[NC.extensionName];this._bufferedBytes+=o.length,this._deflating=!0,t.compress(o,c.fin,(M,N)=>{if(this._socket.destroyed){let O=new Error("The socket was closed while data was being compressed");typeof _=="function"&&_(O);for(let T=0;T{"use strict";var sg=class{constructor(o,a){this.target=a,this.type=o}},IC=class extends sg{constructor(o,a){super("message",a);this.data=o}},bC=class extends sg{constructor(o,a,c){super("close",c);this.wasClean=c._closeFrameReceived&&c._closeFrameSent,this.reason=a,this.code=o}},BC=class extends sg{constructor(o){super("open",o)}},UC=class extends sg{constructor(o,a){super("error",a);this.message=o.message,this.error=o}},Zb={addEventListener(i,o,a){if(typeof o!="function")return;function c(O){o.call(this,new IC(O,this))}function _(O,T){o.call(this,new bC(O,T,this))}function t(O){o.call(this,new UC(O,this))}function M(){o.call(this,new BC(this))}let N=a&&a.once?"once":"on";i==="message"?(c._listener=o,this[N](i,c)):i==="close"?(_._listener=o,this[N](i,_)):i==="error"?(t._listener=o,this[N](i,t)):i==="open"?(M._listener=o,this[N](i,M)):this[N](i,o)},removeEventListener(i,o){let a=this.listeners(i);for(let c=0;c{"use strict";var ag=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function zc(i,o,a){i[o]===void 0?i[o]=[a]:i[o].push(a)}function $b(i){let o=Object.create(null);if(i===void 0||i==="")return o;let a=Object.create(null),c=!1,_=!1,t=!1,M,N,O=-1,T=-1,B=0;for(;B{let a=i[o];return Array.isArray(a)||(a=[a]),a.map(c=>[o].concat(Object.keys(c).map(_=>{let t=c[_];return Array.isArray(t)||(t=[t]),t.map(M=>M===!0?_:`${_}=${M}`).join("; ")})).join("; ")).join(", ")}).join(", ")}zC.exports={format:eB,parse:$b}});var _w=Ke((DV,HC)=>{"use strict";var tB=require("events"),nB=require("https"),rB=require("http"),qC=require("net"),iB=require("tls"),{randomBytes:uB,createHash:oB}=require("crypto"),{URL:vw}=require("url"),v2=og(),lB=dw(),sB=pw(),{BINARY_TYPES:WC,EMPTY_BUFFER:mw,GUID:aB,kStatusCode:fB,kWebSocket:na,NOOP:VC}=th(),{addEventListener:cB,removeEventListener:dB}=jC(),{format:pB,parse:hB}=hw(),{toBuffer:vB}=rg(),GC=["CONNECTING","OPEN","CLOSING","CLOSED"],yw=[8,13],mB=30*1e3,Gi=class extends tB{constructor(o,a,c){super();this._binaryType=WC[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage="",this._closeTimer=null,this._extensions={},this._protocol="",this._readyState=Gi.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,o!==null?(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,Array.isArray(a)?a=a.join(", "):typeof a=="object"&&a!==null&&(c=a,a=void 0),YC(this,o,a,c)):this._isServer=!0}get binaryType(){return this._binaryType}set binaryType(o){!WC.includes(o)||(this._binaryType=o,this._receiver&&(this._receiver._binaryType=o))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(o,a,c){let _=new lB(this.binaryType,this._extensions,this._isServer,c);this._sender=new sB(o,this._extensions),this._receiver=_,this._socket=o,_[na]=this,o[na]=this,_.on("conclude",yB),_.on("drain",gB),_.on("error",_B),_.on("message",EB),_.on("ping",DB),_.on("pong",wB),o.setTimeout(0),o.setNoDelay(),a.length>0&&o.unshift(a),o.on("close",KC),o.on("data",s4),o.on("end",XC),o.on("error",QC),this._readyState=Gi.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=Gi.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}this._extensions[v2.extensionName]&&this._extensions[v2.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=Gi.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(o,a){if(this.readyState!==Gi.CLOSED){if(this.readyState===Gi.CONNECTING){let c="WebSocket was closed before the connection was established";return Z1(this,this._req,c)}if(this.readyState===Gi.CLOSING){this._closeFrameSent&&this._closeFrameReceived&&this._socket.end();return}this._readyState=Gi.CLOSING,this._sender.close(o,a,!this._isServer,c=>{c||(this._closeFrameSent=!0,this._closeFrameReceived&&this._socket.end())}),this._closeTimer=setTimeout(this._socket.destroy.bind(this._socket),mB)}}ping(o,a,c){if(this.readyState===Gi.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof o=="function"?(c=o,o=a=void 0):typeof a=="function"&&(c=a,a=void 0),typeof o=="number"&&(o=o.toString()),this.readyState!==Gi.OPEN){gw(this,o,c);return}a===void 0&&(a=!this._isServer),this._sender.ping(o||mw,a,c)}pong(o,a,c){if(this.readyState===Gi.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof o=="function"?(c=o,o=a=void 0):typeof a=="function"&&(c=a,a=void 0),typeof o=="number"&&(o=o.toString()),this.readyState!==Gi.OPEN){gw(this,o,c);return}a===void 0&&(a=!this._isServer),this._sender.pong(o||mw,a,c)}send(o,a,c){if(this.readyState===Gi.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof a=="function"&&(c=a,a={}),typeof o=="number"&&(o=o.toString()),this.readyState!==Gi.OPEN){gw(this,o,c);return}let _=qt({binary:typeof o!="string",mask:!this._isServer,compress:!0,fin:!0},a);this._extensions[v2.extensionName]||(_.compress=!1),this._sender.send(o||mw,_,c)}terminate(){if(this.readyState!==Gi.CLOSED){if(this.readyState===Gi.CONNECTING){let o="WebSocket was closed before the connection was established";return Z1(this,this._req,o)}this._socket&&(this._readyState=Gi.CLOSING,this._socket.destroy())}}};GC.forEach((i,o)=>{let a={enumerable:!0,value:o};Object.defineProperty(Gi.prototype,i,a),Object.defineProperty(Gi,i,a)});["binaryType","bufferedAmount","extensions","protocol","readyState","url"].forEach(i=>{Object.defineProperty(Gi.prototype,i,{enumerable:!0})});["open","error","close","message"].forEach(i=>{Object.defineProperty(Gi.prototype,`on${i}`,{configurable:!0,enumerable:!0,get(){let o=this.listeners(i);for(let a=0;a{Z1(i,q,"Opening handshake has timed out")}),q.on("error",ne=>{q===null||q.aborted||(q=i._req=null,i._readyState=Gi.CLOSING,i.emit("error",ne),i.emitClose())}),q.on("response",ne=>{let m=ne.headers.location,pe=ne.statusCode;if(m&&_.followRedirects&&pe>=300&&pe<400){if(++i._redirects>_.maxRedirects){Z1(i,q,"Maximum redirects exceeded");return}q.abort();let ge=new vw(m,o);YC(i,ge,a,c)}else i.emit("unexpected-response",q,ne)||Z1(i,q,`Unexpected server response: ${ne.statusCode}`)}),q.on("upgrade",(ne,m,pe)=>{if(i.emit("upgrade",ne),i.readyState!==Gi.CONNECTING)return;q=i._req=null;let ge=oB("sha1").update(T+aB).digest("base64");if(ne.headers["sec-websocket-accept"]!==ge){Z1(i,m,"Invalid Sec-WebSocket-Accept header");return}let ve=ne.headers["sec-websocket-protocol"],ue=(a||"").split(/, */),_e;if(!a&&ve?_e="Server sent a subprotocol but none was requested":a&&!ve?_e="Server sent no subprotocol":ve&&!ue.includes(ve)&&(_e="Server sent an invalid subprotocol"),_e){Z1(i,m,_e);return}if(ve&&(i._protocol=ve),H)try{let ce=hB(ne.headers["sec-websocket-extensions"]);ce[v2.extensionName]&&(H.accept(ce[v2.extensionName]),i._extensions[v2.extensionName]=H)}catch(ce){Z1(i,m,"Invalid Sec-WebSocket-Extensions header");return}i.setSocket(m,pe,_.maxPayload)})}function SB(i){return i.path=i.socketPath,qC.connect(i)}function TB(i){return i.path=void 0,!i.servername&&i.servername!==""&&(i.servername=qC.isIP(i.host)?"":i.host),iB.connect(i)}function Z1(i,o,a){i._readyState=Gi.CLOSING;let c=new Error(a);Error.captureStackTrace(c,Z1),o.setHeader?(o.abort(),o.socket&&!o.socket.destroyed&&o.socket.destroy(),o.once("abort",i.emitClose.bind(i)),i.emit("error",c)):(o.destroy(c),o.once("error",i.emit.bind(i,"error")),o.once("close",i.emitClose.bind(i)))}function gw(i,o,a){if(o){let c=vB(o).length;i._socket?i._sender._bufferedBytes+=c:i._bufferedAmount+=c}if(a){let c=new Error(`WebSocket is not open: readyState ${i.readyState} (${GC[i.readyState]})`);a(c)}}function yB(i,o){let a=this[na];a._socket.removeListener("data",s4),a._socket.resume(),a._closeFrameReceived=!0,a._closeMessage=o,a._closeCode=i,i===1005?a.close():a.close(i,o)}function gB(){this[na]._socket.resume()}function _B(i){let o=this[na];o._socket.removeListener("data",s4),o._readyState=Gi.CLOSING,o._closeCode=i[fB],o.emit("error",i),o._socket.destroy()}function JC(){this[na].emitClose()}function EB(i){this[na].emit("message",i)}function DB(i){let o=this[na];o.pong(i,!o._isServer,VC),o.emit("ping",i)}function wB(i){this[na].emit("pong",i)}function KC(){let i=this[na];this.removeListener("close",KC),this.removeListener("end",XC),i._readyState=Gi.CLOSING,i._socket.read(),i._receiver.end(),this.removeListener("data",s4),this[na]=void 0,clearTimeout(i._closeTimer),i._receiver._writableState.finished||i._receiver._writableState.errorEmitted?i.emitClose():(i._receiver.on("error",JC),i._receiver.on("finish",JC))}function s4(i){this[na]._receiver.write(i)||this.pause()}function XC(){let i=this[na];i._readyState=Gi.CLOSING,i._receiver.end(),this.end()}function QC(){let i=this[na];this.removeListener("error",QC),this.on("error",VC),i&&(i._readyState=Gi.CLOSING,this.destroy())}});var t6=Ke((wV,ZC)=>{"use strict";var{Duplex:CB}=require("stream");function $C(i){i.emit("close")}function xB(){!this.destroyed&&this._writableState.finished&&this.destroy()}function e6(i){this.removeListener("error",e6),this.destroy(),this.listenerCount("error")===0&&this.emit("error",i)}function RB(i,o){let a=!0;function c(){a&&i._socket.resume()}i.readyState===i.CONNECTING?i.once("open",function(){i._receiver.removeAllListeners("drain"),i._receiver.on("drain",c)}):(i._receiver.removeAllListeners("drain"),i._receiver.on("drain",c));let _=new CB(Zr(qt({},o),{autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1}));return i.on("message",function(M){_.push(M)||(a=!1,i._socket.pause())}),i.once("error",function(M){_.destroyed||_.destroy(M)}),i.once("close",function(){_.destroyed||_.push(null)}),_._destroy=function(t,M){if(i.readyState===i.CLOSED){M(t),process.nextTick($C,_);return}let N=!1;i.once("error",function(T){N=!0,M(T)}),i.once("close",function(){N||M(t),process.nextTick($C,_)}),i.terminate()},_._final=function(t){if(i.readyState===i.CONNECTING){i.once("open",function(){_._final(t)});return}i._socket!==null&&(i._socket._writableState.finished?(t(),_._readableState.endEmitted&&_.destroy()):(i._socket.once("finish",function(){t()}),i.close()))},_._read=function(){i.readyState===i.OPEN&&!a&&(a=!0,i._receiver._writableState.needDrain||i._socket.resume())},_._write=function(t,M,N){if(i.readyState===i.CONNECTING){i.once("open",function(){_._write(t,M,N)});return}i.send(t,N)},_.on("end",xB),_.on("error",e6),_}ZC.exports=RB});var i6=Ke((SV,n6)=>{"use strict";var AB=require("events"),{createHash:OB}=require("crypto"),{createServer:MB,STATUS_CODES:Ew}=require("http"),rh=og(),kB=_w(),{format:LB,parse:NB}=hw(),{GUID:FB,kWebSocket:PB}=th(),IB=/^[+/0-9A-Za-z]{22}==$/,r6=class extends AB{constructor(o,a){super();if(o=qt({maxPayload:100*1024*1024,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null},o),o.port==null&&!o.server&&!o.noServer)throw new TypeError('One of the "port", "server", or "noServer" options must be specified');if(o.port!=null?(this._server=MB((c,_)=>{let t=Ew[426];_.writeHead(426,{"Content-Length":t.length,"Content-Type":"text/plain"}),_.end(t)}),this._server.listen(o.port,o.host,o.backlog,a)):o.server&&(this._server=o.server),this._server){let c=this.emit.bind(this,"connection");this._removeListeners=bB(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(_,t,M)=>{this.handleUpgrade(_,t,M,c)}})}o.perMessageDeflate===!0&&(o.perMessageDeflate={}),o.clientTracking&&(this.clients=new Set),this.options=o}address(){if(this.options.noServer)throw new Error('The server is operating in "noServer" mode');return this._server?this._server.address():null}close(o){if(o&&this.once("close",o),this.clients)for(let c of this.clients)c.terminate();let a=this._server;if(a&&(this._removeListeners(),this._removeListeners=this._server=null,this.options.port!=null)){a.close(()=>this.emit("close"));return}process.nextTick(BB,this)}shouldHandle(o){if(this.options.path){let a=o.url.indexOf("?");if((a!==-1?o.url.slice(0,a):o.url)!==this.options.path)return!1}return!0}handleUpgrade(o,a,c,_){a.on("error",Dw);let t=o.headers["sec-websocket-key"]!==void 0?o.headers["sec-websocket-key"].trim():!1,M=+o.headers["sec-websocket-version"],N={};if(o.method!=="GET"||o.headers.upgrade.toLowerCase()!=="websocket"||!t||!IB.test(t)||M!==8&&M!==13||!this.shouldHandle(o))return a4(a,400);if(this.options.perMessageDeflate){let O=new rh(this.options.perMessageDeflate,!0,this.options.maxPayload);try{let T=NB(o.headers["sec-websocket-extensions"]);T[rh.extensionName]&&(O.accept(T[rh.extensionName]),N[rh.extensionName]=O)}catch(T){return a4(a,400)}}if(this.options.verifyClient){let O={origin:o.headers[`${M===8?"sec-websocket-origin":"origin"}`],secure:!!(o.socket.authorized||o.socket.encrypted),req:o};if(this.options.verifyClient.length===2){this.options.verifyClient(O,(T,B,H,q)=>{if(!T)return a4(a,B||401,H,q);this.completeUpgrade(t,N,o,a,c,_)});return}if(!this.options.verifyClient(O))return a4(a,401)}this.completeUpgrade(t,N,o,a,c,_)}completeUpgrade(o,a,c,_,t,M){if(!_.readable||!_.writable)return _.destroy();if(_[PB])throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");let N=OB("sha1").update(o+FB).digest("base64"),O=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${N}`],T=new kB(null),B=c.headers["sec-websocket-protocol"];if(B&&(B=B.split(",").map(UB),this.options.handleProtocols?B=this.options.handleProtocols(B,c):B=B[0],B&&(O.push(`Sec-WebSocket-Protocol: ${B}`),T._protocol=B)),a[rh.extensionName]){let H=a[rh.extensionName].params,q=LB({[rh.extensionName]:[H]});O.push(`Sec-WebSocket-Extensions: ${q}`),T._extensions=a}this.emit("headers",O,c),_.write(O.concat(`\r -`).join(`\r -`)),_.removeListener("error",Dw),T.setSocket(_,t,this.options.maxPayload),this.clients&&(this.clients.add(T),T.on("close",()=>this.clients.delete(T))),M(T,c)}};n6.exports=r6;function bB(i,o){for(let a of Object.keys(o))i.on(a,o[a]);return function(){for(let c of Object.keys(o))i.removeListener(c,o[c])}}function BB(i){i.emit("close")}function Dw(){this.destroy()}function a4(i,o,a,c){i.writable&&(a=a||Ew[o],c=qt({Connection:"close","Content-Type":"text/html","Content-Length":Buffer.byteLength(a)},c),i.write(`HTTP/1.1 ${o} ${Ew[o]}\r -`+Object.keys(c).map(_=>`${_}: ${c[_]}`).join(`\r -`)+`\r -\r -`+a)),i.removeListener("error",Dw),i.destroy()}function UB(i){return i.trim()}});var o6=Ke((TV,u6)=>{"use strict";var fg=_w();fg.createWebSocketStream=t6();fg.Server=i6();fg.Receiver=dw();fg.Sender=pw();u6.exports=fg});var l6=Ke(f4=>{"use strict";var jB=f4&&f4.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(f4,"__esModule",{value:!0});var zB=jB(o6()),cg=global;cg.WebSocket||(cg.WebSocket=zB.default);cg.window||(cg.window=global);cg.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__=[{type:1,value:7,isEnabled:!0},{type:2,value:"InternalApp",isEnabled:!0,isValid:!0},{type:2,value:"InternalAppContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStdoutContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStderrContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStdinContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalFocusContext",isEnabled:!0,isValid:!0}]});var s6=Ke((c4,ww)=>{(function(i,o){typeof c4=="object"&&typeof ww=="object"?ww.exports=o():typeof define=="function"&&define.amd?define([],o):typeof c4=="object"?c4.ReactDevToolsBackend=o():i.ReactDevToolsBackend=o()})(window,function(){return function(i){var o={};function a(c){if(o[c])return o[c].exports;var _=o[c]={i:c,l:!1,exports:{}};return i[c].call(_.exports,_,_.exports,a),_.l=!0,_.exports}return a.m=i,a.c=o,a.d=function(c,_,t){a.o(c,_)||Object.defineProperty(c,_,{enumerable:!0,get:t})},a.r=function(c){typeof Symbol!="undefined"&&Symbol.toStringTag&&Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(c,"__esModule",{value:!0})},a.t=function(c,_){if(1&_&&(c=a(c)),8&_||4&_&&typeof c=="object"&&c&&c.__esModule)return c;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:c}),2&_&&typeof c!="string")for(var M in c)a.d(t,M,function(N){return c[N]}.bind(null,M));return t},a.n=function(c){var _=c&&c.__esModule?function(){return c.default}:function(){return c};return a.d(_,"a",_),_},a.o=function(c,_){return Object.prototype.hasOwnProperty.call(c,_)},a.p="",a(a.s=20)}([function(i,o,a){"use strict";i.exports=a(12)},function(i,o,a){"use strict";var c=Object.getOwnPropertySymbols,_=Object.prototype.hasOwnProperty,t=Object.prototype.propertyIsEnumerable;function M(N){if(N==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(N)}i.exports=function(){try{if(!Object.assign)return!1;var N=new String("abc");if(N[5]="de",Object.getOwnPropertyNames(N)[0]==="5")return!1;for(var O={},T=0;T<10;T++)O["_"+String.fromCharCode(T)]=T;if(Object.getOwnPropertyNames(O).map(function(H){return O[H]}).join("")!=="0123456789")return!1;var B={};return"abcdefghijklmnopqrst".split("").forEach(function(H){B[H]=H}),Object.keys(Object.assign({},B)).join("")==="abcdefghijklmnopqrst"}catch(H){return!1}}()?Object.assign:function(N,O){for(var T,B,H=M(N),q=1;q=re||nn<0||zt&&Rt-He>=ct}function le(){var Rt=ge();if(xe(Rt))return qe(Rt);Xe=setTimeout(le,function(nn){var an=re-(nn-tt);return zt?pe(an,ct-(nn-He)):an}(Rt))}function qe(Rt){return Xe=void 0,nt&&Ie?X(Rt):(Ie=je=void 0,pt)}function dt(){var Rt=ge(),nn=xe(Rt);if(Ie=arguments,je=this,tt=Rt,nn){if(Xe===void 0)return fe(tt);if(zt)return Xe=setTimeout(le,re),X(tt)}return Xe===void 0&&(Xe=setTimeout(le,re)),pt}return re=ce(re)||0,ue(we)&&(kt=!!we.leading,ct=(zt="maxWait"in we)?m(ce(we.maxWait)||0,re):ct,nt="trailing"in we?!!we.trailing:nt),dt.cancel=function(){Xe!==void 0&&clearTimeout(Xe),He=0,Ie=tt=je=Xe=void 0},dt.flush=function(){return Xe===void 0?pt:qe(ge())},dt}function ue(me){var re=_(me);return!!me&&(re=="object"||re=="function")}function _e(me){return _(me)=="symbol"||function(re){return!!re&&_(re)=="object"}(me)&&ne.call(me)=="[object Symbol]"}function ce(me){if(typeof me=="number")return me;if(_e(me))return NaN;if(ue(me)){var re=typeof me.valueOf=="function"?me.valueOf():me;me=ue(re)?re+"":re}if(typeof me!="string")return me===0?me:+me;me=me.replace(t,"");var we=N.test(me);return we||O.test(me)?T(me.slice(2),we?2:8):M.test(me)?NaN:+me}i.exports=function(me,re,we){var Ie=!0,je=!0;if(typeof me!="function")throw new TypeError("Expected a function");return ue(we)&&(Ie="leading"in we?!!we.leading:Ie,je="trailing"in we?!!we.trailing:je),ve(me,re,{leading:Ie,maxWait:re,trailing:je})}}).call(this,a(4))},function(i,o,a){(function(c){function _(X){return(_=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(fe){return typeof fe}:function(fe){return fe&&typeof Symbol=="function"&&fe.constructor===Symbol&&fe!==Symbol.prototype?"symbol":typeof fe})(X)}var t;o=i.exports=m,t=(c===void 0?"undefined":_(c))==="object"&&c.env&&c.env.NODE_DEBUG&&/\bsemver\b/i.test(c.env.NODE_DEBUG)?function(){var X=Array.prototype.slice.call(arguments,0);X.unshift("SEMVER"),console.log.apply(console,X)}:function(){},o.SEMVER_SPEC_VERSION="2.0.0";var M=Number.MAX_SAFE_INTEGER||9007199254740991,N=o.re=[],O=o.src=[],T=o.tokens={},B=0;function H(X){T[X]=B++}H("NUMERICIDENTIFIER"),O[T.NUMERICIDENTIFIER]="0|[1-9]\\d*",H("NUMERICIDENTIFIERLOOSE"),O[T.NUMERICIDENTIFIERLOOSE]="[0-9]+",H("NONNUMERICIDENTIFIER"),O[T.NONNUMERICIDENTIFIER]="\\d*[a-zA-Z-][a-zA-Z0-9-]*",H("MAINVERSION"),O[T.MAINVERSION]="("+O[T.NUMERICIDENTIFIER]+")\\.("+O[T.NUMERICIDENTIFIER]+")\\.("+O[T.NUMERICIDENTIFIER]+")",H("MAINVERSIONLOOSE"),O[T.MAINVERSIONLOOSE]="("+O[T.NUMERICIDENTIFIERLOOSE]+")\\.("+O[T.NUMERICIDENTIFIERLOOSE]+")\\.("+O[T.NUMERICIDENTIFIERLOOSE]+")",H("PRERELEASEIDENTIFIER"),O[T.PRERELEASEIDENTIFIER]="(?:"+O[T.NUMERICIDENTIFIER]+"|"+O[T.NONNUMERICIDENTIFIER]+")",H("PRERELEASEIDENTIFIERLOOSE"),O[T.PRERELEASEIDENTIFIERLOOSE]="(?:"+O[T.NUMERICIDENTIFIERLOOSE]+"|"+O[T.NONNUMERICIDENTIFIER]+")",H("PRERELEASE"),O[T.PRERELEASE]="(?:-("+O[T.PRERELEASEIDENTIFIER]+"(?:\\."+O[T.PRERELEASEIDENTIFIER]+")*))",H("PRERELEASELOOSE"),O[T.PRERELEASELOOSE]="(?:-?("+O[T.PRERELEASEIDENTIFIERLOOSE]+"(?:\\."+O[T.PRERELEASEIDENTIFIERLOOSE]+")*))",H("BUILDIDENTIFIER"),O[T.BUILDIDENTIFIER]="[0-9A-Za-z-]+",H("BUILD"),O[T.BUILD]="(?:\\+("+O[T.BUILDIDENTIFIER]+"(?:\\."+O[T.BUILDIDENTIFIER]+")*))",H("FULL"),H("FULLPLAIN"),O[T.FULLPLAIN]="v?"+O[T.MAINVERSION]+O[T.PRERELEASE]+"?"+O[T.BUILD]+"?",O[T.FULL]="^"+O[T.FULLPLAIN]+"$",H("LOOSEPLAIN"),O[T.LOOSEPLAIN]="[v=\\s]*"+O[T.MAINVERSIONLOOSE]+O[T.PRERELEASELOOSE]+"?"+O[T.BUILD]+"?",H("LOOSE"),O[T.LOOSE]="^"+O[T.LOOSEPLAIN]+"$",H("GTLT"),O[T.GTLT]="((?:<|>)?=?)",H("XRANGEIDENTIFIERLOOSE"),O[T.XRANGEIDENTIFIERLOOSE]=O[T.NUMERICIDENTIFIERLOOSE]+"|x|X|\\*",H("XRANGEIDENTIFIER"),O[T.XRANGEIDENTIFIER]=O[T.NUMERICIDENTIFIER]+"|x|X|\\*",H("XRANGEPLAIN"),O[T.XRANGEPLAIN]="[v=\\s]*("+O[T.XRANGEIDENTIFIER]+")(?:\\.("+O[T.XRANGEIDENTIFIER]+")(?:\\.("+O[T.XRANGEIDENTIFIER]+")(?:"+O[T.PRERELEASE]+")?"+O[T.BUILD]+"?)?)?",H("XRANGEPLAINLOOSE"),O[T.XRANGEPLAINLOOSE]="[v=\\s]*("+O[T.XRANGEIDENTIFIERLOOSE]+")(?:\\.("+O[T.XRANGEIDENTIFIERLOOSE]+")(?:\\.("+O[T.XRANGEIDENTIFIERLOOSE]+")(?:"+O[T.PRERELEASELOOSE]+")?"+O[T.BUILD]+"?)?)?",H("XRANGE"),O[T.XRANGE]="^"+O[T.GTLT]+"\\s*"+O[T.XRANGEPLAIN]+"$",H("XRANGELOOSE"),O[T.XRANGELOOSE]="^"+O[T.GTLT]+"\\s*"+O[T.XRANGEPLAINLOOSE]+"$",H("COERCE"),O[T.COERCE]="(^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])",H("COERCERTL"),N[T.COERCERTL]=new RegExp(O[T.COERCE],"g"),H("LONETILDE"),O[T.LONETILDE]="(?:~>?)",H("TILDETRIM"),O[T.TILDETRIM]="(\\s*)"+O[T.LONETILDE]+"\\s+",N[T.TILDETRIM]=new RegExp(O[T.TILDETRIM],"g"),H("TILDE"),O[T.TILDE]="^"+O[T.LONETILDE]+O[T.XRANGEPLAIN]+"$",H("TILDELOOSE"),O[T.TILDELOOSE]="^"+O[T.LONETILDE]+O[T.XRANGEPLAINLOOSE]+"$",H("LONECARET"),O[T.LONECARET]="(?:\\^)",H("CARETTRIM"),O[T.CARETTRIM]="(\\s*)"+O[T.LONECARET]+"\\s+",N[T.CARETTRIM]=new RegExp(O[T.CARETTRIM],"g"),H("CARET"),O[T.CARET]="^"+O[T.LONECARET]+O[T.XRANGEPLAIN]+"$",H("CARETLOOSE"),O[T.CARETLOOSE]="^"+O[T.LONECARET]+O[T.XRANGEPLAINLOOSE]+"$",H("COMPARATORLOOSE"),O[T.COMPARATORLOOSE]="^"+O[T.GTLT]+"\\s*("+O[T.LOOSEPLAIN]+")$|^$",H("COMPARATOR"),O[T.COMPARATOR]="^"+O[T.GTLT]+"\\s*("+O[T.FULLPLAIN]+")$|^$",H("COMPARATORTRIM"),O[T.COMPARATORTRIM]="(\\s*)"+O[T.GTLT]+"\\s*("+O[T.LOOSEPLAIN]+"|"+O[T.XRANGEPLAIN]+")",N[T.COMPARATORTRIM]=new RegExp(O[T.COMPARATORTRIM],"g"),H("HYPHENRANGE"),O[T.HYPHENRANGE]="^\\s*("+O[T.XRANGEPLAIN]+")\\s+-\\s+("+O[T.XRANGEPLAIN]+")\\s*$",H("HYPHENRANGELOOSE"),O[T.HYPHENRANGELOOSE]="^\\s*("+O[T.XRANGEPLAINLOOSE]+")\\s+-\\s+("+O[T.XRANGEPLAINLOOSE]+")\\s*$",H("STAR"),O[T.STAR]="(<|>)?=?\\s*\\*";for(var q=0;q256||!(fe.loose?N[T.LOOSE]:N[T.FULL]).test(X))return null;try{return new m(X,fe)}catch(xe){return null}}function m(X,fe){if(fe&&_(fe)==="object"||(fe={loose:!!fe,includePrerelease:!1}),X instanceof m){if(X.loose===fe.loose)return X;X=X.version}else if(typeof X!="string")throw new TypeError("Invalid Version: "+X);if(X.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof m))return new m(X,fe);t("SemVer",X,fe),this.options=fe,this.loose=!!fe.loose;var xe=X.trim().match(fe.loose?N[T.LOOSE]:N[T.FULL]);if(!xe)throw new TypeError("Invalid Version: "+X);if(this.raw=X,this.major=+xe[1],this.minor=+xe[2],this.patch=+xe[3],this.major>M||this.major<0)throw new TypeError("Invalid major version");if(this.minor>M||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>M||this.patch<0)throw new TypeError("Invalid patch version");xe[4]?this.prerelease=xe[4].split(".").map(function(le){if(/^[0-9]+$/.test(le)){var qe=+le;if(qe>=0&&qe=0;)typeof this.prerelease[xe]=="number"&&(this.prerelease[xe]++,xe=-2);xe===-1&&this.prerelease.push(0)}fe&&(this.prerelease[0]===fe?isNaN(this.prerelease[1])&&(this.prerelease=[fe,0]):this.prerelease=[fe,0]);break;default:throw new Error("invalid increment argument: "+X)}return this.format(),this.raw=this.version,this},o.inc=function(X,fe,xe,le){typeof xe=="string"&&(le=xe,xe=void 0);try{return new m(X,xe).inc(fe,le).version}catch(qe){return null}},o.diff=function(X,fe){if(ce(X,fe))return null;var xe=ne(X),le=ne(fe),qe="";if(xe.prerelease.length||le.prerelease.length){qe="pre";var dt="prerelease"}for(var Rt in xe)if((Rt==="major"||Rt==="minor"||Rt==="patch")&&xe[Rt]!==le[Rt])return qe+Rt;return dt},o.compareIdentifiers=ge;var pe=/^[0-9]+$/;function ge(X,fe){var xe=pe.test(X),le=pe.test(fe);return xe&&le&&(X=+X,fe=+fe),X===fe?0:xe&&!le?-1:le&&!xe?1:X0}function _e(X,fe,xe){return ve(X,fe,xe)<0}function ce(X,fe,xe){return ve(X,fe,xe)===0}function me(X,fe,xe){return ve(X,fe,xe)!==0}function re(X,fe,xe){return ve(X,fe,xe)>=0}function we(X,fe,xe){return ve(X,fe,xe)<=0}function Ie(X,fe,xe,le){switch(fe){case"===":return _(X)==="object"&&(X=X.version),_(xe)==="object"&&(xe=xe.version),X===xe;case"!==":return _(X)==="object"&&(X=X.version),_(xe)==="object"&&(xe=xe.version),X!==xe;case"":case"=":case"==":return ce(X,xe,le);case"!=":return me(X,xe,le);case">":return ue(X,xe,le);case">=":return re(X,xe,le);case"<":return _e(X,xe,le);case"<=":return we(X,xe,le);default:throw new TypeError("Invalid operator: "+fe)}}function je(X,fe){if(fe&&_(fe)==="object"||(fe={loose:!!fe,includePrerelease:!1}),X instanceof je){if(X.loose===!!fe.loose)return X;X=X.value}if(!(this instanceof je))return new je(X,fe);t("comparator",X,fe),this.options=fe,this.loose=!!fe.loose,this.parse(X),this.semver===ct?this.value="":this.value=this.operator+this.semver.version,t("comp",this)}o.rcompareIdentifiers=function(X,fe){return ge(fe,X)},o.major=function(X,fe){return new m(X,fe).major},o.minor=function(X,fe){return new m(X,fe).minor},o.patch=function(X,fe){return new m(X,fe).patch},o.compare=ve,o.compareLoose=function(X,fe){return ve(X,fe,!0)},o.compareBuild=function(X,fe,xe){var le=new m(X,xe),qe=new m(fe,xe);return le.compare(qe)||le.compareBuild(qe)},o.rcompare=function(X,fe,xe){return ve(fe,X,xe)},o.sort=function(X,fe){return X.sort(function(xe,le){return o.compareBuild(xe,le,fe)})},o.rsort=function(X,fe){return X.sort(function(xe,le){return o.compareBuild(le,xe,fe)})},o.gt=ue,o.lt=_e,o.eq=ce,o.neq=me,o.gte=re,o.lte=we,o.cmp=Ie,o.Comparator=je;var ct={};function pt(X,fe){if(fe&&_(fe)==="object"||(fe={loose:!!fe,includePrerelease:!1}),X instanceof pt)return X.loose===!!fe.loose&&X.includePrerelease===!!fe.includePrerelease?X:new pt(X.raw,fe);if(X instanceof je)return new pt(X.value,fe);if(!(this instanceof pt))return new pt(X,fe);if(this.options=fe,this.loose=!!fe.loose,this.includePrerelease=!!fe.includePrerelease,this.raw=X,this.set=X.split(/\s*\|\|\s*/).map(function(xe){return this.parseRange(xe.trim())},this).filter(function(xe){return xe.length}),!this.set.length)throw new TypeError("Invalid SemVer Range: "+X);this.format()}function Xe(X,fe){for(var xe=!0,le=X.slice(),qe=le.pop();xe&&le.length;)xe=le.every(function(dt){return qe.intersects(dt,fe)}),qe=le.pop();return xe}function tt(X){return!X||X.toLowerCase()==="x"||X==="*"}function He(X,fe,xe,le,qe,dt,Rt,nn,an,Mn,lr,ln,Gt){return((fe=tt(xe)?"":tt(le)?">="+xe+".0.0":tt(qe)?">="+xe+"."+le+".0":">="+fe)+" "+(nn=tt(an)?"":tt(Mn)?"<"+(+an+1)+".0.0":tt(lr)?"<"+an+"."+(+Mn+1)+".0":ln?"<="+an+"."+Mn+"."+lr+"-"+ln:"<="+nn)).trim()}function kt(X,fe,xe){for(var le=0;le0){var qe=X[le].semver;if(qe.major===fe.major&&qe.minor===fe.minor&&qe.patch===fe.patch)return!0}return!1}return!0}function zt(X,fe,xe){try{fe=new pt(fe,xe)}catch(le){return!1}return fe.test(X)}function nt(X,fe,xe,le){var qe,dt,Rt,nn,an;switch(X=new m(X,le),fe=new pt(fe,le),xe){case">":qe=ue,dt=we,Rt=_e,nn=">",an=">=";break;case"<":qe=_e,dt=re,Rt=ue,nn="<",an="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(zt(X,fe,le))return!1;for(var Mn=0;Mn=0.0.0")),ln=ln||Er,Gt=Gt||Er,qe(Er.semver,ln.semver,le)?ln=Er:Rt(Er.semver,Gt.semver,le)&&(Gt=Er)}),ln.operator===nn||ln.operator===an||(!Gt.operator||Gt.operator===nn)&&dt(X,Gt.semver)||Gt.operator===an&&Rt(X,Gt.semver))return!1}return!0}je.prototype.parse=function(X){var fe=this.options.loose?N[T.COMPARATORLOOSE]:N[T.COMPARATOR],xe=X.match(fe);if(!xe)throw new TypeError("Invalid comparator: "+X);this.operator=xe[1]!==void 0?xe[1]:"",this.operator==="="&&(this.operator=""),xe[2]?this.semver=new m(xe[2],this.options.loose):this.semver=ct},je.prototype.toString=function(){return this.value},je.prototype.test=function(X){if(t("Comparator.test",X,this.options.loose),this.semver===ct||X===ct)return!0;if(typeof X=="string")try{X=new m(X,this.options)}catch(fe){return!1}return Ie(X,this.operator,this.semver,this.options)},je.prototype.intersects=function(X,fe){if(!(X instanceof je))throw new TypeError("a Comparator is required");var xe;if(fe&&_(fe)==="object"||(fe={loose:!!fe,includePrerelease:!1}),this.operator==="")return this.value===""||(xe=new pt(X.value,fe),zt(this.value,xe,fe));if(X.operator==="")return X.value===""||(xe=new pt(this.value,fe),zt(X.semver,xe,fe));var le=!(this.operator!==">="&&this.operator!==">"||X.operator!==">="&&X.operator!==">"),qe=!(this.operator!=="<="&&this.operator!=="<"||X.operator!=="<="&&X.operator!=="<"),dt=this.semver.version===X.semver.version,Rt=!(this.operator!==">="&&this.operator!=="<="||X.operator!==">="&&X.operator!=="<="),nn=Ie(this.semver,"<",X.semver,fe)&&(this.operator===">="||this.operator===">")&&(X.operator==="<="||X.operator==="<"),an=Ie(this.semver,">",X.semver,fe)&&(this.operator==="<="||this.operator==="<")&&(X.operator===">="||X.operator===">");return le||qe||dt&&Rt||nn||an},o.Range=pt,pt.prototype.format=function(){return this.range=this.set.map(function(X){return X.join(" ").trim()}).join("||").trim(),this.range},pt.prototype.toString=function(){return this.range},pt.prototype.parseRange=function(X){var fe=this.options.loose;X=X.trim();var xe=fe?N[T.HYPHENRANGELOOSE]:N[T.HYPHENRANGE];X=X.replace(xe,He),t("hyphen replace",X),X=X.replace(N[T.COMPARATORTRIM],"$1$2$3"),t("comparator trim",X,N[T.COMPARATORTRIM]),X=(X=(X=X.replace(N[T.TILDETRIM],"$1~")).replace(N[T.CARETTRIM],"$1^")).split(/\s+/).join(" ");var le=fe?N[T.COMPARATORLOOSE]:N[T.COMPARATOR],qe=X.split(" ").map(function(dt){return function(Rt,nn){return t("comp",Rt,nn),Rt=function(an,Mn){return an.trim().split(/\s+/).map(function(lr){return function(ln,Gt){t("caret",ln,Gt);var Er=Gt.loose?N[T.CARETLOOSE]:N[T.CARET];return ln.replace(Er,function(w,jt,Xn,vr,jr){var fr;return t("caret",ln,w,jt,Xn,vr,jr),tt(jt)?fr="":tt(Xn)?fr=">="+jt+".0.0 <"+(+jt+1)+".0.0":tt(vr)?fr=jt==="0"?">="+jt+"."+Xn+".0 <"+jt+"."+(+Xn+1)+".0":">="+jt+"."+Xn+".0 <"+(+jt+1)+".0.0":jr?(t("replaceCaret pr",jr),fr=jt==="0"?Xn==="0"?">="+jt+"."+Xn+"."+vr+"-"+jr+" <"+jt+"."+Xn+"."+(+vr+1):">="+jt+"."+Xn+"."+vr+"-"+jr+" <"+jt+"."+(+Xn+1)+".0":">="+jt+"."+Xn+"."+vr+"-"+jr+" <"+(+jt+1)+".0.0"):(t("no pr"),fr=jt==="0"?Xn==="0"?">="+jt+"."+Xn+"."+vr+" <"+jt+"."+Xn+"."+(+vr+1):">="+jt+"."+Xn+"."+vr+" <"+jt+"."+(+Xn+1)+".0":">="+jt+"."+Xn+"."+vr+" <"+(+jt+1)+".0.0"),t("caret return",fr),fr})}(lr,Mn)}).join(" ")}(Rt,nn),t("caret",Rt),Rt=function(an,Mn){return an.trim().split(/\s+/).map(function(lr){return function(ln,Gt){var Er=Gt.loose?N[T.TILDELOOSE]:N[T.TILDE];return ln.replace(Er,function(w,jt,Xn,vr,jr){var fr;return t("tilde",ln,w,jt,Xn,vr,jr),tt(jt)?fr="":tt(Xn)?fr=">="+jt+".0.0 <"+(+jt+1)+".0.0":tt(vr)?fr=">="+jt+"."+Xn+".0 <"+jt+"."+(+Xn+1)+".0":jr?(t("replaceTilde pr",jr),fr=">="+jt+"."+Xn+"."+vr+"-"+jr+" <"+jt+"."+(+Xn+1)+".0"):fr=">="+jt+"."+Xn+"."+vr+" <"+jt+"."+(+Xn+1)+".0",t("tilde return",fr),fr})}(lr,Mn)}).join(" ")}(Rt,nn),t("tildes",Rt),Rt=function(an,Mn){return t("replaceXRanges",an,Mn),an.split(/\s+/).map(function(lr){return function(ln,Gt){ln=ln.trim();var Er=Gt.loose?N[T.XRANGELOOSE]:N[T.XRANGE];return ln.replace(Er,function(w,jt,Xn,vr,jr,fr){t("xRange",ln,w,jt,Xn,vr,jr,fr);var zr=tt(Xn),Qt=zr||tt(vr),wu=Qt||tt(jr),po=wu;return jt==="="&&po&&(jt=""),fr=Gt.includePrerelease?"-0":"",zr?w=jt===">"||jt==="<"?"<0.0.0-0":"*":jt&&po?(Qt&&(vr=0),jr=0,jt===">"?(jt=">=",Qt?(Xn=+Xn+1,vr=0,jr=0):(vr=+vr+1,jr=0)):jt==="<="&&(jt="<",Qt?Xn=+Xn+1:vr=+vr+1),w=jt+Xn+"."+vr+"."+jr+fr):Qt?w=">="+Xn+".0.0"+fr+" <"+(+Xn+1)+".0.0"+fr:wu&&(w=">="+Xn+"."+vr+".0"+fr+" <"+Xn+"."+(+vr+1)+".0"+fr),t("xRange return",w),w})}(lr,Mn)}).join(" ")}(Rt,nn),t("xrange",Rt),Rt=function(an,Mn){return t("replaceStars",an,Mn),an.trim().replace(N[T.STAR],"")}(Rt,nn),t("stars",Rt),Rt}(dt,this.options)},this).join(" ").split(/\s+/);return this.options.loose&&(qe=qe.filter(function(dt){return!!dt.match(le)})),qe=qe.map(function(dt){return new je(dt,this.options)},this)},pt.prototype.intersects=function(X,fe){if(!(X instanceof pt))throw new TypeError("a Range is required");return this.set.some(function(xe){return Xe(xe,fe)&&X.set.some(function(le){return Xe(le,fe)&&xe.every(function(qe){return le.every(function(dt){return qe.intersects(dt,fe)})})})})},o.toComparators=function(X,fe){return new pt(X,fe).set.map(function(xe){return xe.map(function(le){return le.value}).join(" ").trim().split(" ")})},pt.prototype.test=function(X){if(!X)return!1;if(typeof X=="string")try{X=new m(X,this.options)}catch(xe){return!1}for(var fe=0;fe":dt.prerelease.length===0?dt.patch++:dt.prerelease.push(0),dt.raw=dt.format();case"":case">=":xe&&!ue(xe,dt)||(xe=dt);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+qe.operator)}});return xe&&X.test(xe)?xe:null},o.validRange=function(X,fe){try{return new pt(X,fe).range||"*"}catch(xe){return null}},o.ltr=function(X,fe,xe){return nt(X,fe,"<",xe)},o.gtr=function(X,fe,xe){return nt(X,fe,">",xe)},o.outside=nt,o.prerelease=function(X,fe){var xe=ne(X,fe);return xe&&xe.prerelease.length?xe.prerelease:null},o.intersects=function(X,fe,xe){return X=new pt(X,xe),fe=new pt(fe,xe),X.intersects(fe)},o.coerce=function(X,fe){if(X instanceof m)return X;if(typeof X=="number"&&(X=String(X)),typeof X!="string")return null;var xe=null;if((fe=fe||{}).rtl){for(var le;(le=N[T.COERCERTL].exec(X))&&(!xe||xe.index+xe[0].length!==X.length);)xe&&le.index+le[0].length===xe.index+xe[0].length||(xe=le),N[T.COERCERTL].lastIndex=le.index+le[1].length+le[2].length;N[T.COERCERTL].lastIndex=-1}else xe=X.match(N[T.COERCE]);return xe===null?null:ne(xe[2]+"."+(xe[3]||"0")+"."+(xe[4]||"0"),fe)}}).call(this,a(5))},function(i,o){function a(_){return(a=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(_)}var c;c=function(){return this}();try{c=c||new Function("return this")()}catch(_){(typeof window=="undefined"?"undefined":a(window))==="object"&&(c=window)}i.exports=c},function(i,o){var a,c,_=i.exports={};function t(){throw new Error("setTimeout has not been defined")}function M(){throw new Error("clearTimeout has not been defined")}function N(ge){if(a===setTimeout)return setTimeout(ge,0);if((a===t||!a)&&setTimeout)return a=setTimeout,setTimeout(ge,0);try{return a(ge,0)}catch(ve){try{return a.call(null,ge,0)}catch(ue){return a.call(this,ge,0)}}}(function(){try{a=typeof setTimeout=="function"?setTimeout:t}catch(ge){a=t}try{c=typeof clearTimeout=="function"?clearTimeout:M}catch(ge){c=M}})();var O,T=[],B=!1,H=-1;function q(){B&&O&&(B=!1,O.length?T=O.concat(T):H=-1,T.length&&ne())}function ne(){if(!B){var ge=N(q);B=!0;for(var ve=T.length;ve;){for(O=T,T=[];++H1)for(var ue=1;uethis[M])return me(this,this[m].get(Xe)),!1;var nt=this[m].get(Xe).value;return this[H]&&(this[q]||this[H](Xe,nt.value)),nt.now=kt,nt.maxAge=He,nt.value=tt,this[N]+=zt-nt.length,nt.length=zt,this.get(Xe),ce(this),!0}var X=new re(Xe,tt,zt,kt,He);return X.length>this[M]?(this[H]&&this[H](Xe,tt),!1):(this[N]+=X.length,this[ne].unshift(X),this[m].set(Xe,this[ne].head),ce(this),!0)}},{key:"has",value:function(Xe){if(!this[m].has(Xe))return!1;var tt=this[m].get(Xe).value;return!_e(this,tt)}},{key:"get",value:function(Xe){return ue(this,Xe,!0)}},{key:"peek",value:function(Xe){return ue(this,Xe,!1)}},{key:"pop",value:function(){var Xe=this[ne].tail;return Xe?(me(this,Xe),Xe.value):null}},{key:"del",value:function(Xe){me(this,this[m].get(Xe))}},{key:"load",value:function(Xe){this.reset();for(var tt=Date.now(),He=Xe.length-1;He>=0;He--){var kt=Xe[He],zt=kt.e||0;if(zt===0)this.set(kt.k,kt.v);else{var nt=zt-tt;nt>0&&this.set(kt.k,kt.v,nt)}}}},{key:"prune",value:function(){var Xe=this;this[m].forEach(function(tt,He){return ue(Xe,He,!1)})}},{key:"max",set:function(Xe){if(typeof Xe!="number"||Xe<0)throw new TypeError("max must be a non-negative number");this[M]=Xe||1/0,ce(this)},get:function(){return this[M]}},{key:"allowStale",set:function(Xe){this[T]=!!Xe},get:function(){return this[T]}},{key:"maxAge",set:function(Xe){if(typeof Xe!="number")throw new TypeError("maxAge must be a non-negative number");this[B]=Xe,ce(this)},get:function(){return this[B]}},{key:"lengthCalculator",set:function(Xe){var tt=this;typeof Xe!="function"&&(Xe=ge),Xe!==this[O]&&(this[O]=Xe,this[N]=0,this[ne].forEach(function(He){He.length=tt[O](He.value,He.key),tt[N]+=He.length})),ce(this)},get:function(){return this[O]}},{key:"length",get:function(){return this[N]}},{key:"itemCount",get:function(){return this[ne].length}}])&&_(je.prototype,ct),pt&&_(je,pt),Ie}(),ue=function(Ie,je,ct){var pt=Ie[m].get(je);if(pt){var Xe=pt.value;if(_e(Ie,Xe)){if(me(Ie,pt),!Ie[T])return}else ct&&(Ie[pe]&&(pt.value.now=Date.now()),Ie[ne].unshiftNode(pt));return Xe.value}},_e=function(Ie,je){if(!je||!je.maxAge&&!Ie[B])return!1;var ct=Date.now()-je.now;return je.maxAge?ct>je.maxAge:Ie[B]&&ct>Ie[B]},ce=function(Ie){if(Ie[N]>Ie[M])for(var je=Ie[ne].tail;Ie[N]>Ie[M]&&je!==null;){var ct=je.prev;me(Ie,je),je=ct}},me=function(Ie,je){if(je){var ct=je.value;Ie[H]&&Ie[H](ct.key,ct.value),Ie[N]-=ct.length,Ie[m].delete(ct.key),Ie[ne].removeNode(je)}},re=function Ie(je,ct,pt,Xe,tt){c(this,Ie),this.key=je,this.value=ct,this.length=pt,this.now=Xe,this.maxAge=tt||0},we=function(Ie,je,ct,pt){var Xe=ct.value;_e(Ie,Xe)&&(me(Ie,ct),Ie[T]||(Xe=void 0)),Xe&&je.call(pt,Xe.value,Xe.key,Ie)};i.exports=ve},function(i,o,a){(function(c){function _(t){return(_=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(M){return typeof M}:function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M})(t)}i.exports=function(){if(typeof document=="undefined"||!document.addEventListener)return null;var t,M,N,O={};return O.copy=function(){var T=!1,B=null,H=!1;function q(){T=!1,B=null,H&&window.getSelection().removeAllRanges(),H=!1}return document.addEventListener("copy",function(ne){if(T){for(var m in B)ne.clipboardData.setData(m,B[m]);ne.preventDefault()}}),function(ne){return new Promise(function(m,pe){T=!0,typeof ne=="string"?B={"text/plain":ne}:ne instanceof Node?B={"text/html":new XMLSerializer().serializeToString(ne)}:ne instanceof Object?B=ne:pe("Invalid data type. Must be string, DOM node, or an object mapping MIME types to strings."),function ge(ve){try{if(document.execCommand("copy"))q(),m();else{if(ve)throw q(),new Error("Unable to copy. Perhaps it's not available in your browser?");(function(){var ue=document.getSelection();if(!document.queryCommandEnabled("copy")&&ue.isCollapsed){var _e=document.createRange();_e.selectNodeContents(document.body),ue.removeAllRanges(),ue.addRange(_e),H=!0}})(),ge(!0)}}catch(ue){q(),pe(ue)}}(!1)})}}(),O.paste=(N=!1,document.addEventListener("paste",function(T){if(N){N=!1,T.preventDefault();var B=t;t=null,B(T.clipboardData.getData(M))}}),function(T){return new Promise(function(B,H){N=!0,t=B,M=T||"text/plain";try{document.execCommand("paste")||(N=!1,H(new Error("Unable to paste. Pasting only works in Internet Explorer at the moment.")))}catch(q){N=!1,H(new Error(q))}})}),typeof ClipboardEvent=="undefined"&&window.clipboardData!==void 0&&window.clipboardData.setData!==void 0&&(function(T){function B(ce,me){return function(){ce.apply(me,arguments)}}function H(ce){if(_(this)!="object")throw new TypeError("Promises must be constructed via new");if(typeof ce!="function")throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],ve(ce,B(ne,this),B(m,this))}function q(ce){var me=this;return this._state===null?void this._deferreds.push(ce):void ue(function(){var re=me._state?ce.onFulfilled:ce.onRejected;if(re!==null){var we;try{we=re(me._value)}catch(Ie){return void ce.reject(Ie)}ce.resolve(we)}else(me._state?ce.resolve:ce.reject)(me._value)})}function ne(ce){try{if(ce===this)throw new TypeError("A promise cannot be resolved with itself.");if(ce&&(_(ce)=="object"||typeof ce=="function")){var me=ce.then;if(typeof me=="function")return void ve(B(me,ce),B(ne,this),B(m,this))}this._state=!0,this._value=ce,pe.call(this)}catch(re){m.call(this,re)}}function m(ce){this._state=!1,this._value=ce,pe.call(this)}function pe(){for(var ce=0,me=this._deferreds.length;me>ce;ce++)q.call(this,this._deferreds[ce]);this._deferreds=null}function ge(ce,me,re,we){this.onFulfilled=typeof ce=="function"?ce:null,this.onRejected=typeof me=="function"?me:null,this.resolve=re,this.reject=we}function ve(ce,me,re){var we=!1;try{ce(function(Ie){we||(we=!0,me(Ie))},function(Ie){we||(we=!0,re(Ie))})}catch(Ie){if(we)return;we=!0,re(Ie)}}var ue=H.immediateFn||typeof c=="function"&&c||function(ce){setTimeout(ce,1)},_e=Array.isArray||function(ce){return Object.prototype.toString.call(ce)==="[object Array]"};H.prototype.catch=function(ce){return this.then(null,ce)},H.prototype.then=function(ce,me){var re=this;return new H(function(we,Ie){q.call(re,new ge(ce,me,we,Ie))})},H.all=function(){var ce=Array.prototype.slice.call(arguments.length===1&&_e(arguments[0])?arguments[0]:arguments);return new H(function(me,re){function we(ct,pt){try{if(pt&&(_(pt)=="object"||typeof pt=="function")){var Xe=pt.then;if(typeof Xe=="function")return void Xe.call(pt,function(tt){we(ct,tt)},re)}ce[ct]=pt,--Ie==0&&me(ce)}catch(tt){re(tt)}}if(ce.length===0)return me([]);for(var Ie=ce.length,je=0;jewe;we++)ce[we].then(me,re)})},i.exports?i.exports=H:T.Promise||(T.Promise=H)}(this),O.copy=function(T){return new Promise(function(B,H){if(typeof T!="string"&&!("text/plain"in T))throw new Error("You must provide a text/plain type.");var q=typeof T=="string"?T:T["text/plain"];window.clipboardData.setData("Text",q)?B():H(new Error("Copying was rejected."))})},O.paste=function(){return new Promise(function(T,B){var H=window.clipboardData.getData("Text");H?T(H):B(new Error("Pasting was rejected."))})}),O}()}).call(this,a(13).setImmediate)},function(i,o,a){"use strict";i.exports=a(15)},function(i,o,a){"use strict";a.r(o),o.default=`:root { - /** - * IMPORTANT: When new theme variables are added below\u2013 also add them to SettingsContext updateThemeVariables() - */ - - /* Light theme */ - --light-color-attribute-name: #ef6632; - --light-color-attribute-name-not-editable: #23272f; - --light-color-attribute-name-inverted: rgba(255, 255, 255, 0.7); - --light-color-attribute-value: #1a1aa6; - --light-color-attribute-value-inverted: #ffffff; - --light-color-attribute-editable-value: #1a1aa6; - --light-color-background: #ffffff; - --light-color-background-hover: rgba(0, 136, 250, 0.1); - --light-color-background-inactive: #e5e5e5; - --light-color-background-invalid: #fff0f0; - --light-color-background-selected: #0088fa; - --light-color-button-background: #ffffff; - --light-color-button-background-focus: #ededed; - --light-color-button: #5f6673; - --light-color-button-disabled: #cfd1d5; - --light-color-button-active: #0088fa; - --light-color-button-focus: #23272f; - --light-color-button-hover: #23272f; - --light-color-border: #eeeeee; - --light-color-commit-did-not-render-fill: #cfd1d5; - --light-color-commit-did-not-render-fill-text: #000000; - --light-color-commit-did-not-render-pattern: #cfd1d5; - --light-color-commit-did-not-render-pattern-text: #333333; - --light-color-commit-gradient-0: #37afa9; - --light-color-commit-gradient-1: #63b19e; - --light-color-commit-gradient-2: #80b393; - --light-color-commit-gradient-3: #97b488; - --light-color-commit-gradient-4: #abb67d; - --light-color-commit-gradient-5: #beb771; - --light-color-commit-gradient-6: #cfb965; - --light-color-commit-gradient-7: #dfba57; - --light-color-commit-gradient-8: #efbb49; - --light-color-commit-gradient-9: #febc38; - --light-color-commit-gradient-text: #000000; - --light-color-component-name: #6a51b2; - --light-color-component-name-inverted: #ffffff; - --light-color-component-badge-background: rgba(0, 0, 0, 0.1); - --light-color-component-badge-background-inverted: rgba(255, 255, 255, 0.25); - --light-color-component-badge-count: #777d88; - --light-color-component-badge-count-inverted: rgba(255, 255, 255, 0.7); - --light-color-context-background: rgba(0,0,0,.9); - --light-color-context-background-hover: rgba(255, 255, 255, 0.1); - --light-color-context-background-selected: #178fb9; - --light-color-context-border: #3d424a; - --light-color-context-text: #ffffff; - --light-color-context-text-selected: #ffffff; - --light-color-dim: #777d88; - --light-color-dimmer: #cfd1d5; - --light-color-dimmest: #eff0f1; - --light-color-error-background: hsl(0, 100%, 97%); - --light-color-error-border: hsl(0, 100%, 92%); - --light-color-error-text: #ff0000; - --light-color-expand-collapse-toggle: #777d88; - --light-color-link: #0000ff; - --light-color-modal-background: rgba(255, 255, 255, 0.75); - --light-color-record-active: #fc3a4b; - --light-color-record-hover: #3578e5; - --light-color-record-inactive: #0088fa; - --light-color-scroll-thumb: #c2c2c2; - --light-color-scroll-track: #fafafa; - --light-color-search-match: yellow; - --light-color-search-match-current: #f7923b; - --light-color-selected-tree-highlight-active: rgba(0, 136, 250, 0.1); - --light-color-selected-tree-highlight-inactive: rgba(0, 0, 0, 0.05); - --light-color-shadow: rgba(0, 0, 0, 0.25); - --light-color-tab-selected-border: #0088fa; - --light-color-text: #000000; - --light-color-text-invalid: #ff0000; - --light-color-text-selected: #ffffff; - --light-color-toggle-background-invalid: #fc3a4b; - --light-color-toggle-background-on: #0088fa; - --light-color-toggle-background-off: #cfd1d5; - --light-color-toggle-text: #ffffff; - --light-color-tooltip-background: rgba(0, 0, 0, 0.9); - --light-color-tooltip-text: #ffffff; - - /* Dark theme */ - --dark-color-attribute-name: #9d87d2; - --dark-color-attribute-name-not-editable: #ededed; - --dark-color-attribute-name-inverted: #282828; - --dark-color-attribute-value: #cedae0; - --dark-color-attribute-value-inverted: #ffffff; - --dark-color-attribute-editable-value: yellow; - --dark-color-background: #282c34; - --dark-color-background-hover: rgba(255, 255, 255, 0.1); - --dark-color-background-inactive: #3d424a; - --dark-color-background-invalid: #5c0000; - --dark-color-background-selected: #178fb9; - --dark-color-button-background: #282c34; - --dark-color-button-background-focus: #3d424a; - --dark-color-button: #afb3b9; - --dark-color-button-active: #61dafb; - --dark-color-button-disabled: #4f5766; - --dark-color-button-focus: #a2e9fc; - --dark-color-button-hover: #ededed; - --dark-color-border: #3d424a; - --dark-color-commit-did-not-render-fill: #777d88; - --dark-color-commit-did-not-render-fill-text: #000000; - --dark-color-commit-did-not-render-pattern: #666c77; - --dark-color-commit-did-not-render-pattern-text: #ffffff; - --dark-color-commit-gradient-0: #37afa9; - --dark-color-commit-gradient-1: #63b19e; - --dark-color-commit-gradient-2: #80b393; - --dark-color-commit-gradient-3: #97b488; - --dark-color-commit-gradient-4: #abb67d; - --dark-color-commit-gradient-5: #beb771; - --dark-color-commit-gradient-6: #cfb965; - --dark-color-commit-gradient-7: #dfba57; - --dark-color-commit-gradient-8: #efbb49; - --dark-color-commit-gradient-9: #febc38; - --dark-color-commit-gradient-text: #000000; - --dark-color-component-name: #61dafb; - --dark-color-component-name-inverted: #282828; - --dark-color-component-badge-background: rgba(255, 255, 255, 0.25); - --dark-color-component-badge-background-inverted: rgba(0, 0, 0, 0.25); - --dark-color-component-badge-count: #8f949d; - --dark-color-component-badge-count-inverted: rgba(255, 255, 255, 0.7); - --dark-color-context-background: rgba(255,255,255,.9); - --dark-color-context-background-hover: rgba(0, 136, 250, 0.1); - --dark-color-context-background-selected: #0088fa; - --dark-color-context-border: #eeeeee; - --dark-color-context-text: #000000; - --dark-color-context-text-selected: #ffffff; - --dark-color-dim: #8f949d; - --dark-color-dimmer: #777d88; - --dark-color-dimmest: #4f5766; - --dark-color-error-background: #200; - --dark-color-error-border: #900; - --dark-color-error-text: #f55; - --dark-color-expand-collapse-toggle: #8f949d; - --dark-color-link: #61dafb; - --dark-color-modal-background: rgba(0, 0, 0, 0.75); - --dark-color-record-active: #fc3a4b; - --dark-color-record-hover: #a2e9fc; - --dark-color-record-inactive: #61dafb; - --dark-color-scroll-thumb: #afb3b9; - --dark-color-scroll-track: #313640; - --dark-color-search-match: yellow; - --dark-color-search-match-current: #f7923b; - --dark-color-selected-tree-highlight-active: rgba(23, 143, 185, 0.15); - --dark-color-selected-tree-highlight-inactive: rgba(255, 255, 255, 0.05); - --dark-color-shadow: rgba(0, 0, 0, 0.5); - --dark-color-tab-selected-border: #178fb9; - --dark-color-text: #ffffff; - --dark-color-text-invalid: #ff8080; - --dark-color-text-selected: #ffffff; - --dark-color-toggle-background-invalid: #fc3a4b; - --dark-color-toggle-background-on: #178fb9; - --dark-color-toggle-background-off: #777d88; - --dark-color-toggle-text: #ffffff; - --dark-color-tooltip-background: rgba(255, 255, 255, 0.9); - --dark-color-tooltip-text: #000000; - - /* Font smoothing */ - --light-font-smoothing: auto; - --dark-font-smoothing: antialiased; - --font-smoothing: auto; - - /* Compact density */ - --compact-font-size-monospace-small: 9px; - --compact-font-size-monospace-normal: 11px; - --compact-font-size-monospace-large: 15px; - --compact-font-size-sans-small: 10px; - --compact-font-size-sans-normal: 12px; - --compact-font-size-sans-large: 14px; - --compact-line-height-data: 18px; - --compact-root-font-size: 16px; - - /* Comfortable density */ - --comfortable-font-size-monospace-small: 10px; - --comfortable-font-size-monospace-normal: 13px; - --comfortable-font-size-monospace-large: 17px; - --comfortable-font-size-sans-small: 12px; - --comfortable-font-size-sans-normal: 14px; - --comfortable-font-size-sans-large: 16px; - --comfortable-line-height-data: 22px; - --comfortable-root-font-size: 20px; - - /* GitHub.com system fonts */ - --font-family-monospace: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, - Courier, monospace; - --font-family-sans: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, - Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol; - - /* Constant values shared between JS and CSS */ - --interaction-commit-size: 10px; - --interaction-label-width: 200px; -} -`},function(i,o,a){"use strict";function c(O){var T=this;if(T instanceof c||(T=new c),T.tail=null,T.head=null,T.length=0,O&&typeof O.forEach=="function")O.forEach(function(q){T.push(q)});else if(arguments.length>0)for(var B=0,H=arguments.length;B1)B=T;else{if(!this.head)throw new TypeError("Reduce of empty list with no initial value");H=this.head.next,B=this.head.value}for(var q=0;H!==null;q++)B=O(B,H.value,q),H=H.next;return B},c.prototype.reduceReverse=function(O,T){var B,H=this.tail;if(arguments.length>1)B=T;else{if(!this.tail)throw new TypeError("Reduce of empty list with no initial value");H=this.tail.prev,B=this.tail.value}for(var q=this.length-1;H!==null;q--)B=O(B,H.value,q),H=H.prev;return B},c.prototype.toArray=function(){for(var O=new Array(this.length),T=0,B=this.head;B!==null;T++)O[T]=B.value,B=B.next;return O},c.prototype.toArrayReverse=function(){for(var O=new Array(this.length),T=0,B=this.tail;B!==null;T++)O[T]=B.value,B=B.prev;return O},c.prototype.slice=function(O,T){(T=T||this.length)<0&&(T+=this.length),(O=O||0)<0&&(O+=this.length);var B=new c;if(Tthis.length&&(T=this.length);for(var H=0,q=this.head;q!==null&&Hthis.length&&(T=this.length);for(var H=this.length,q=this.tail;q!==null&&H>T;H--)q=q.prev;for(;q!==null&&H>O;H--,q=q.prev)B.push(q.value);return B},c.prototype.splice=function(O,T){O>this.length&&(O=this.length-1),O<0&&(O=this.length+O);for(var B=0,H=this.head;H!==null&&B=0&&(N._idleTimeoutId=setTimeout(function(){N._onTimeout&&N._onTimeout()},O))},a(14),o.setImmediate=typeof self!="undefined"&&self.setImmediate||c!==void 0&&c.setImmediate||this&&this.setImmediate,o.clearImmediate=typeof self!="undefined"&&self.clearImmediate||c!==void 0&&c.clearImmediate||this&&this.clearImmediate}).call(this,a(4))},function(i,o,a){(function(c,_){(function(t,M){"use strict";if(!t.setImmediate){var N,O,T,B,H,q=1,ne={},m=!1,pe=t.document,ge=Object.getPrototypeOf&&Object.getPrototypeOf(t);ge=ge&&ge.setTimeout?ge:t,{}.toString.call(t.process)==="[object process]"?N=function(_e){_.nextTick(function(){ue(_e)})}:function(){if(t.postMessage&&!t.importScripts){var _e=!0,ce=t.onmessage;return t.onmessage=function(){_e=!1},t.postMessage("","*"),t.onmessage=ce,_e}}()?(B="setImmediate$"+Math.random()+"$",H=function(_e){_e.source===t&&typeof _e.data=="string"&&_e.data.indexOf(B)===0&&ue(+_e.data.slice(B.length))},t.addEventListener?t.addEventListener("message",H,!1):t.attachEvent("onmessage",H),N=function(_e){t.postMessage(B+_e,"*")}):t.MessageChannel?((T=new MessageChannel).port1.onmessage=function(_e){ue(_e.data)},N=function(_e){T.port2.postMessage(_e)}):pe&&"onreadystatechange"in pe.createElement("script")?(O=pe.documentElement,N=function(_e){var ce=pe.createElement("script");ce.onreadystatechange=function(){ue(_e),ce.onreadystatechange=null,O.removeChild(ce),ce=null},O.appendChild(ce)}):N=function(_e){setTimeout(ue,0,_e)},ge.setImmediate=function(_e){typeof _e!="function"&&(_e=new Function(""+_e));for(var ce=new Array(arguments.length-1),me=0;mefe;fe++)if((X=ve(nt,kt,fe))!==-1){ge=fe,kt=X;break e}kt=-1}}e:{if(nt=zt,(X=q().get(He.primitive))!==void 0){for(fe=0;fekt-nt?null:zt.slice(nt,kt-1))!==null){if(kt=0,je!==null){for(;ktkt;je--)ct=Xe.pop()}for(je=zt.length-kt-1;1<=je;je--)kt=[],ct.push({id:null,isStateEditable:!1,name:_e(zt[je-1].functionName),value:void 0,subHooks:kt}),Xe.push(ct),ct=kt;je=zt}kt=(zt=He.primitive)==="Context"||zt==="DebugValue"?null:pt++,ct.push({id:kt,isStateEditable:zt==="Reducer"||zt==="State",name:zt,value:He.value,subHooks:[]})}return function xe(le,qe){for(var dt=[],Rt=0;Rt-1&&(ne=ne.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(\),.*$)/g,""));var m=ne.replace(/^\s+/,"").replace(/\(eval code/g,"("),pe=m.match(/ (\((.+):(\d+):(\d+)\)$)/),ge=(m=pe?m.replace(pe[0],""):m).split(/\s+/).slice(1),ve=this.extractLocation(pe?pe[1]:ge.pop()),ue=ge.join(" ")||void 0,_e=["eval",""].indexOf(ve[0])>-1?void 0:ve[0];return new O({functionName:ue,fileName:_e,lineNumber:ve[1],columnNumber:ve[2],source:ne})},this)},parseFFOrSafari:function(q){return q.stack.split(` -`).filter(function(ne){return!ne.match(H)},this).map(function(ne){if(ne.indexOf(" > eval")>-1&&(ne=ne.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),ne.indexOf("@")===-1&&ne.indexOf(":")===-1)return new O({functionName:ne});var m=/((.*".+"[^@]*)?[^@]*)(?:@)/,pe=ne.match(m),ge=pe&&pe[1]?pe[1]:void 0,ve=this.extractLocation(ne.replace(m,""));return new O({functionName:ge,fileName:ve[0],lineNumber:ve[1],columnNumber:ve[2],source:ne})},this)},parseOpera:function(q){return!q.stacktrace||q.message.indexOf(` -`)>-1&&q.message.split(` -`).length>q.stacktrace.split(` -`).length?this.parseOpera9(q):q.stack?this.parseOpera11(q):this.parseOpera10(q)},parseOpera9:function(q){for(var ne=/Line (\d+).*script (?:in )?(\S+)/i,m=q.message.split(` -`),pe=[],ge=2,ve=m.length;ge/,"$2").replace(/\([^)]*\)/g,"")||void 0;ve.match(/\(([^)]*)\)/)&&(m=ve.replace(/^[^(]+\(([^)]*)\)$/,"$1"));var _e=m===void 0||m==="[arguments not available]"?void 0:m.split(",");return new O({functionName:ue,args:_e,fileName:ge[0],lineNumber:ge[1],columnNumber:ge[2],source:ne})},this)}}})=="function"?c.apply(o,_):c)===void 0||(i.exports=t)})()},function(i,o,a){var c,_,t;(function(M,N){"use strict";_=[],(t=typeof(c=function(){function O(ue){return ue.charAt(0).toUpperCase()+ue.substring(1)}function T(ue){return function(){return this[ue]}}var B=["isConstructor","isEval","isNative","isToplevel"],H=["columnNumber","lineNumber"],q=["fileName","functionName","source"],ne=B.concat(H,q,["args"]);function m(ue){if(ue)for(var _e=0;_e1?Ae-1:0),ke=1;ke=0&&Ae.splice(Z,1)}}}])&&c(z.prototype,G),$&&c(z,$),U}(),t=a(2),M=a.n(t);try{var N=a(9).default,O=function(U){var z=new RegExp("".concat(U,": ([0-9]+)")),G=N.match(z);return parseInt(G[1],10)};O("comfortable-line-height-data"),O("compact-line-height-data")}catch(U){}function T(U){try{return sessionStorage.getItem(U)}catch(z){return null}}function B(U){try{sessionStorage.removeItem(U)}catch(z){}}function H(U,z){try{return sessionStorage.setItem(U,z)}catch(G){}}var q=function(U,z){return U===z},ne=a(1),m=a.n(ne);function pe(U){return U.ownerDocument?U.ownerDocument.defaultView:null}function ge(U){var z=pe(U);return z?z.frameElement:null}function ve(U){var z=ce(U);return ue([U.getBoundingClientRect(),{top:z.borderTop,left:z.borderLeft,bottom:z.borderBottom,right:z.borderRight,width:0,height:0}])}function ue(U){return U.reduce(function(z,G){return z==null?G:{top:z.top+G.top,left:z.left+G.left,width:z.width,height:z.height,bottom:z.bottom+G.bottom,right:z.right+G.right}})}function _e(U,z){var G=ge(U);if(G&&G!==z){for(var $=[U.getBoundingClientRect()],Ce=G,Ee=!1;Ce;){var Ae=ve(Ce);if($.push(Ae),Ce=ge(Ce),Ee)break;Ce&&pe(Ce)===z&&(Ee=!0)}return ue($)}return U.getBoundingClientRect()}function ce(U){var z=window.getComputedStyle(U);return{borderLeft:parseInt(z.borderLeftWidth,10),borderRight:parseInt(z.borderRightWidth,10),borderTop:parseInt(z.borderTopWidth,10),borderBottom:parseInt(z.borderBottomWidth,10),marginLeft:parseInt(z.marginLeft,10),marginRight:parseInt(z.marginRight,10),marginTop:parseInt(z.marginTop,10),marginBottom:parseInt(z.marginBottom,10),paddingLeft:parseInt(z.paddingLeft,10),paddingRight:parseInt(z.paddingRight,10),paddingTop:parseInt(z.paddingTop,10),paddingBottom:parseInt(z.paddingBottom,10)}}function me(U,z){var G;if(typeof Symbol=="undefined"||U[Symbol.iterator]==null){if(Array.isArray(U)||(G=function(ke,Je){if(!!ke){if(typeof ke=="string")return re(ke,Je);var mt=Object.prototype.toString.call(ke).slice(8,-1);if(mt==="Object"&&ke.constructor&&(mt=ke.constructor.name),mt==="Map"||mt==="Set")return Array.from(ke);if(mt==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(mt))return re(ke,Je)}}(U))||z&&U&&typeof U.length=="number"){G&&(U=G);var $=0,Ce=function(){};return{s:Ce,n:function(){return $>=U.length?{done:!0}:{done:!1,value:U[$++]}},e:function(ke){throw ke},f:Ce}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var Ee,Ae=!0,Z=!1;return{s:function(){G=U[Symbol.iterator]()},n:function(){var ke=G.next();return Ae=ke.done,ke},e:function(ke){Z=!0,Ee=ke},f:function(){try{Ae||G.return==null||G.return()}finally{if(Z)throw Ee}}}}function re(U,z){(z==null||z>U.length)&&(z=U.length);for(var G=0,$=new Array(z);GAe.left+Ae.width&&(oe=Ae.left+Ae.width-mt-5),{style:{top:ke+="px",left:oe+="px"}}}(z,G,{width:$.width,height:$.height});m()(this.tip.style,Ce.style)}}]),U}(),Xe=function(){function U(){we(this,U);var z=window.__REACT_DEVTOOLS_TARGET_WINDOW__||window;this.window=z;var G=window.__REACT_DEVTOOLS_TARGET_WINDOW__||window;this.tipBoundsWindow=G;var $=z.document;this.container=$.createElement("div"),this.container.style.zIndex="10000000",this.tip=new pt($,this.container),this.rects=[],$.body.appendChild(this.container)}return je(U,[{key:"remove",value:function(){this.tip.remove(),this.rects.forEach(function(z){z.remove()}),this.rects.length=0,this.container.parentNode&&this.container.parentNode.removeChild(this.container)}},{key:"inspect",value:function(z,G){for(var $=this,Ce=z.filter(function(Ct){return Ct.nodeType===Node.ELEMENT_NODE});this.rects.length>Ce.length;)this.rects.pop().remove();if(Ce.length!==0){for(;this.rects.length1&&arguments[1]!==void 0?arguments[1]:q,it=void 0,Ct=[],Mt=void 0,It=!1,sn=function(Ft,Dn){return We(Ft,Ct[Dn])},rn=function(){for(var Ft=arguments.length,Dn=Array(Ft),dr=0;dr5&&arguments[5]!==void 0?arguments[5]:0,Z=M0(U);switch(Z){case"html_element":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:U.tagName,type:Z};case"function":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:typeof U.name!="function"&&U.name?U.name:"function",type:Z};case"string":return U.length<=500?U:U.slice(0,500)+"...";case"bigint":case"symbol":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:U.toString(),type:Z};case"react_element":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:Po(U)||"Unknown",type:Z};case"array_buffer":case"data_view":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:Z==="data_view"?"DataView":"ArrayBuffer",size:U.byteLength,type:Z};case"array":return Ee=Ce($),Ae>=2&&!Ee?po(Z,!0,U,z,$):U.map(function(mt,oe){return A0(mt,z,G,$.concat([oe]),Ce,Ee?1:Ae+1)});case"html_all_collection":case"typed_array":case"iterator":if(Ee=Ce($),Ae>=2&&!Ee)return po(Z,!0,U,z,$);var ke={unserializable:!0,type:Z,readonly:!0,size:Z==="typed_array"?U.length:void 0,preview_short:ki(U,!1),preview_long:ki(U,!0),name:U.constructor&&U.constructor.name!=="Object"?U.constructor.name:""};return Qt(U[Symbol.iterator])&&Array.from(U).forEach(function(mt,oe){return ke[oe]=A0(mt,z,G,$.concat([oe]),Ce,Ee?1:Ae+1)}),G.push($),ke;case"opaque_iterator":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:U[Symbol.toStringTag],type:Z};case"date":case"regexp":return z.push($),{inspectable:!1,preview_short:ki(U,!1),preview_long:ki(U,!0),name:U.toString(),type:Z};case"object":if(Ee=Ce($),Ae>=2&&!Ee)return po(Z,!0,U,z,$);var Je={};return su(U).forEach(function(mt){var oe=mt.toString();Je[oe]=A0(U[mt],z,G,$.concat([oe]),Ce,Ee?1:Ae+1)}),Je;case"infinity":case"nan":case"undefined":return z.push($),{type:Z};default:return U}}function J0(U){return(J0=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(z){return typeof z}:function(z){return z&&typeof Symbol=="function"&&z.constructor===Symbol&&z!==Symbol.prototype?"symbol":typeof z})(U)}function Ps(U){return function(z){if(Array.isArray(z))return Z0(z)}(U)||function(z){if(typeof Symbol!="undefined"&&Symbol.iterator in Object(z))return Array.from(z)}(U)||function(z,G){if(!!z){if(typeof z=="string")return Z0(z,G);var $=Object.prototype.toString.call(z).slice(8,-1);if($==="Object"&&z.constructor&&($=z.constructor.name),$==="Map"||$==="Set")return Array.from(z);if($==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test($))return Z0(z,G)}}(U)||function(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}()}function Z0(U,z){(z==null||z>U.length)&&(z=U.length);for(var G=0,$=new Array(z);Gz.toString()?1:z.toString()>U.toString()?-1:0}function su(U){for(var z=[],G=U,$=function(){var Ce=[].concat(Ps(Object.keys(G)),Ps(Object.getOwnPropertySymbols(G))),Ee=Object.getOwnPropertyDescriptors(G);Ce.forEach(function(Ae){Ee[Ae].enumerable&&z.push(Ae)}),G=Object.getPrototypeOf(G)};G!=null;)$();return z}function mi(U){var z=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"Anonymous",G=$0.get(U);if(G!=null)return G;var $=z;return typeof U.displayName=="string"?$=U.displayName:typeof U.name=="string"&&U.name!==""&&($=U.name),$0.set(U,$),$}var Dr=0;function el(){return++Dr}function Ko(U){var z=Wt.get(U);if(z!==void 0)return z;for(var G=new Array(U.length),$=0;$1&&arguments[1]!==void 0?arguments[1]:50;return U.length>z?U.substr(0,z)+"\u2026":U}function ki(U,z){if(U!=null&&hasOwnProperty.call(U,wu.type))return z?U[wu.preview_long]:U[wu.preview_short];switch(M0(U)){case"html_element":return"<".concat(au(U.tagName.toLowerCase())," />");case"function":return au("\u0192 ".concat(typeof U.name=="function"?"":U.name,"() {}"));case"string":return'"'.concat(U,'"');case"bigint":return au(U.toString()+"n");case"regexp":case"symbol":return au(U.toString());case"react_element":return"<".concat(au(Po(U)||"Unknown")," />");case"array_buffer":return"ArrayBuffer(".concat(U.byteLength,")");case"data_view":return"DataView(".concat(U.buffer.byteLength,")");case"array":if(z){for(var G="",$=0;$0&&(G+=", "),!((G+=ki(U[$],!1)).length>50));$++);return"[".concat(au(G),"]")}var Ce=hasOwnProperty.call(U,wu.size)?U[wu.size]:U.length;return"Array(".concat(Ce,")");case"typed_array":var Ee="".concat(U.constructor.name,"(").concat(U.length,")");if(z){for(var Ae="",Z=0;Z0&&(Ae+=", "),!((Ae+=U[Z]).length>50));Z++);return"".concat(Ee," [").concat(au(Ae),"]")}return Ee;case"iterator":var ke=U.constructor.name;if(z){for(var Je=Array.from(U),mt="",oe=0;oe0&&(mt+=", "),Array.isArray(We)){var it=ki(We[0],!0),Ct=ki(We[1],!1);mt+="".concat(it," => ").concat(Ct)}else mt+=ki(We,!1);if(mt.length>50)break}return"".concat(ke,"(").concat(U.size,") {").concat(au(mt),"}")}return"".concat(ke,"(").concat(U.size,")");case"opaque_iterator":return U[Symbol.toStringTag];case"date":return U.toString();case"object":if(z){for(var Mt=su(U).sort(xi),It="",sn=0;sn0&&(It+=", "),(It+="".concat(rn.toString(),": ").concat(ki(U[rn],!1))).length>50)break}return"{".concat(au(It),"}")}return"{\u2026}";case"boolean":case"number":case"infinity":case"nan":case"null":case"undefined":return U;default:try{return au(""+U)}catch(Ft){return"unserializable"}}}var Is=a(7);function Xl(U){return(Xl=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(z){return typeof z}:function(z){return z&&typeof Symbol=="function"&&z.constructor===Symbol&&z!==Symbol.prototype?"symbol":typeof z})(U)}function Io(U,z){var G=Object.keys(U);if(Object.getOwnPropertySymbols){var $=Object.getOwnPropertySymbols(U);z&&($=$.filter(function(Ce){return Object.getOwnPropertyDescriptor(U,Ce).enumerable})),G.push.apply(G,$)}return G}function ho(U){for(var z=1;z2&&arguments[2]!==void 0?arguments[2]:[];if(U!==null){var $=[],Ce=[],Ee=A0(U,$,Ce,G,z);return{data:Ee,cleaned:$,unserializable:Ce}}return null}function Qo(U){var z,G,$=(z=U,G=new Set,JSON.stringify(z,function(Ae,Z){if(Xl(Z)==="object"&&Z!==null){if(G.has(Z))return;G.add(Z)}return typeof Z=="bigint"?Z.toString()+"n":Z})),Ce=$===void 0?"undefined":$,Ee=window.__REACT_DEVTOOLS_GLOBAL_HOOK__.clipboardCopyText;typeof Ee=="function"?Ee(Ce).catch(function(Ae){}):Object(Is.copy)(Ce)}function yi(U,z){var G=arguments.length>2&&arguments[2]!==void 0?arguments[2]:0,$=z[G],Ce=Array.isArray(U)?U.slice():ho({},U);return G+1===z.length?Array.isArray(Ce)?Ce.splice($,1):delete Ce[$]:Ce[$]=yi(U[$],z,G+1),Ce}function en(U,z,G){var $=arguments.length>3&&arguments[3]!==void 0?arguments[3]:0,Ce=z[$],Ee=Array.isArray(U)?U.slice():ho({},U);if($+1===z.length){var Ae=G[$];Ee[Ae]=Ee[Ce],Array.isArray(Ee)?Ee.splice(Ce,1):delete Ee[Ce]}else Ee[Ce]=en(U[Ce],z,G,$+1);return Ee}function bn(U,z,G){var $=arguments.length>3&&arguments[3]!==void 0?arguments[3]:0;if($>=z.length)return G;var Ce=z[$],Ee=Array.isArray(U)?U.slice():ho({},U);return Ee[Ce]=bn(U[Ce],z,G,$+1),Ee}var Ai=a(8);function gi(U,z){var G=Object.keys(U);if(Object.getOwnPropertySymbols){var $=Object.getOwnPropertySymbols(U);z&&($=$.filter(function(Ce){return Object.getOwnPropertyDescriptor(U,Ce).enumerable})),G.push.apply(G,$)}return G}function Vt(U){for(var z=1;z=U.length?{done:!0}:{done:!1,value:U[$++]}},e:function(ke){throw ke},f:Ce}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var Ee,Ae=!0,Z=!1;return{s:function(){G=U[Symbol.iterator]()},n:function(){var ke=G.next();return Ae=ke.done,ke},e:function(ke){Z=!0,Ee=ke},f:function(){try{Ae||G.return==null||G.return()}finally{if(Z)throw Ee}}}}function Ql(U,z){if(U){if(typeof U=="string")return k0(U,z);var G=Object.prototype.toString.call(U).slice(8,-1);return G==="Object"&&U.constructor&&(G=U.constructor.name),G==="Map"||G==="Set"?Array.from(U):G==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(G)?k0(U,z):void 0}}function k0(U,z){(z==null||z>U.length)&&(z=U.length);for(var G=0,$=new Array(z);G0){var yt=Ee(ae);if(yt!=null){var Jt,On=Yi(I0);try{for(On.s();!(Jt=On.n()).done;)if(Jt.value.test(yt))return!0}catch(ir){On.e(ir)}finally{On.f()}}}if(ie!=null&&gs.size>0){var Sn,_n=ie.fileName,Tn=Yi(gs);try{for(Tn.s();!(Sn=Tn.n()).done;)if(Sn.value.test(_n))return!0}catch(ir){Tn.e(ir)}finally{Tn.f()}}return!1}function Tu(ae){var ie=ae.type;switch(ae.tag){case Ct:case Cr:return 1;case it:case An:return 5;case rn:return 6;case Ft:return 11;case dr:return 7;case Dn:case er:case sn:return 9;case Lr:case Nr:return 8;case ut:return 12;case Dt:return 13;default:switch(Ae(ie)){case 60111:case"Symbol(react.concurrent_mode)":case"Symbol(react.async_mode)":return 9;case 60109:case"Symbol(react.provider)":return 2;case 60110:case"Symbol(react.context)":return 2;case 60108:case"Symbol(react.strict_mode)":return 9;case 60114:case"Symbol(react.profiler)":return 10;default:return 9}}}function Ei(ae){if(U0.has(ae))return ae;var ie=ae.alternate;return ie!=null&&U0.has(ie)?ie:(U0.add(ae),ae)}window.__REACT_DEVTOOLS_COMPONENT_FILTERS__!=null?_s(window.__REACT_DEVTOOLS_COMPONENT_FILTERS__):_s([{type:1,value:7,isEnabled:!0}]);var xo=new Map,e0=new Map,U0=new Set,sa=new Map,es=new Map,tu=-1;function ei(ae){if(!xo.has(ae)){var ie=el();xo.set(ae,ie),e0.set(ie,ae)}return xo.get(ae)}function h0(ae){switch(Tu(ae)){case 1:if(Uo!==null){var ie=ei(Ei(ae)),Fe=Ci(ae);Fe!==null&&Uo.set(ie,Fe)}}}var Bi={};function Ci(ae){switch(Tu(ae)){case 1:var ie=ae.stateNode,Fe=Bi,Oe=Bi;return ie!=null&&(ie.constructor&&ie.constructor.contextType!=null?Oe=ie.context:(Fe=ie.context)&&Object.keys(Fe).length===0&&(Fe=Bi)),[Fe,Oe];default:return null}}function yf(ae){switch(Tu(ae)){case 1:if(Uo!==null){var ie=ei(Ei(ae)),Fe=Uo.has(ie)?Uo.get(ie):null,Oe=Ci(ae);if(Fe==null||Oe==null)return null;var st=Jo(Fe,2),yt=st[0],Jt=st[1],On=Jo(Oe,2),Sn=On[0],_n=On[1];if(Sn!==Bi)return t0(yt,Sn);if(_n!==Bi)return Jt!==_n}}return null}function gf(ae,ie){if(ae==null||ie==null)return!1;if(ie.hasOwnProperty("baseState")&&ie.hasOwnProperty("memoizedState")&&ie.hasOwnProperty("next")&&ie.hasOwnProperty("queue"))for(;ie!==null;){if(ie.memoizedState!==ae.memoizedState)return!0;ie=ie.next,ae=ae.next}return!1}function t0(ae,ie){if(ae==null||ie==null||ie.hasOwnProperty("baseState")&&ie.hasOwnProperty("memoizedState")&&ie.hasOwnProperty("next")&&ie.hasOwnProperty("queue"))return null;var Fe,Oe=[],st=Yi(new Set([].concat(eu(Object.keys(ae)),eu(Object.keys(ie)))));try{for(st.s();!(Fe=st.n()).done;){var yt=Fe.value;ae[yt]!==ie[yt]&&Oe.push(yt)}}catch(Jt){st.e(Jt)}finally{st.f()}return Oe}function n0(ae,ie){switch(ie.tag){case Ct:case it:case Mt:case Lr:case Nr:return(f0(ie)&oe)===oe;default:return ae.memoizedProps!==ie.memoizedProps||ae.memoizedState!==ie.memoizedState||ae.ref!==ie.ref}}var Re=[],rt=[],Ye=[],Kt=[],Xt=new Map,pr=0,Wr=null;function xn(ae){Re.push(ae)}function yu(ae){if(Re.length!==0||rt.length!==0||Ye.length!==0||Wr!==null||Pu){var ie=rt.length+Ye.length+(Wr===null?0:1),Fe=new Array(3+pr+(ie>0?2+ie:0)+Re.length),Oe=0;if(Fe[Oe++]=z,Fe[Oe++]=tu,Fe[Oe++]=pr,Xt.forEach(function(On,Sn){Fe[Oe++]=Sn.length;for(var _n=Ko(Sn),Tn=0;Tn<_n.length;Tn++)Fe[Oe+Tn]=_n[Tn];Oe+=Sn.length}),ie>0){Fe[Oe++]=2,Fe[Oe++]=ie;for(var st=rt.length-1;st>=0;st--)Fe[Oe++]=rt[st];for(var yt=0;yt0?ae.forEach(function(ie){U.emit("operations",ie)}):(Rr!==null&&(cu=!0),U.getFiberRoots(z).forEach(function(ie){eo(tu=ei(Ei(ie.current)),ie.current),Pu&&ie.memoizedInteractions!=null&&(il={changeDescriptions:ts?new Map:null,durations:[],commitTime:Jl()-Zu,interactions:Array.from(ie.memoizedInteractions).map(function(Fe){return Vt(Vt({},Fe),{},{timestamp:Fe.timestamp-Zu})}),maxActualDuration:0,priorityLevel:null}),Jr(ie.current,null,!1,!1),yu(),tu=-1}))},getBestMatchForTrackedPath:function(){if(Rr===null||r0===null)return null;for(var ae=r0;ae!==null&&Qu(ae);)ae=ae.return;return ae===null?null:{id:ei(Ei(ae)),isFullMatch:nu===Rr.length-1}},getDisplayNameForFiberID:function(ae){var ie=e0.get(ae);return ie!=null?Ee(ie):null},getFiberIDForNative:function(ae){var ie=arguments.length>1&&arguments[1]!==void 0&&arguments[1],Fe=G.findFiberByHostInstance(ae);if(Fe!=null){if(ie)for(;Fe!==null&&Qu(Fe);)Fe=Fe.return;return ei(Ei(Fe))}return null},getInstanceAndStyle:function(ae){var ie=null,Fe=null,Oe=Vu(ae);return Oe!==null&&(ie=Oe.stateNode,Oe.memoizedProps!==null&&(Fe=Oe.memoizedProps.style)),{instance:ie,style:Fe}},getOwnersList:function(ae){var ie=Vu(ae);if(ie==null)return null;var Fe=ie._debugOwner,Oe=[{displayName:Ee(ie)||"Anonymous",id:ae,type:Tu(ie)}];if(Fe)for(var st=Fe;st!==null;)Oe.unshift({displayName:Ee(st)||"Anonymous",id:ei(Ei(st)),type:Tu(st)}),st=st._debugOwner||null;return Oe},getPathForElement:function(ae){var ie=e0.get(ae);if(ie==null)return null;for(var Fe=[];ie!==null;)Fe.push(Do(ie)),ie=ie.return;return Fe.reverse(),Fe},getProfilingData:function(){var ae=[];if(Es===null)throw Error("getProfilingData() called before any profiling data was recorded");return Es.forEach(function(ie,Fe){var Oe=[],st=[],yt=new Map,Jt=new Map,On=xl!==null&&xl.get(Fe)||"Unknown";Mo!=null&&Mo.forEach(function(Sn,_n){v0!=null&&v0.get(_n)===Fe&&st.push([_n,Sn])}),ie.forEach(function(Sn,_n){var Tn=Sn.changeDescriptions,ir=Sn.durations,Bt=Sn.interactions,Fi=Sn.maxActualDuration,Ar=Sn.priorityLevel,mr=Sn.commitTime,Y=[];Bt.forEach(function(Di){yt.has(Di.id)||yt.set(Di.id,Di),Y.push(Di.id);var ru=Jt.get(Di.id);ru!=null?ru.push(_n):Jt.set(Di.id,[_n])});for(var ri=[],ii=[],Vr=0;Vr1?Kn.set(Tn,ir-1):Kn.delete(Tn),ni.delete(Sn)}(tu),ti(Fe,!1))}else eo(tu,Fe),Jr(Fe,null,!1,!1);if(Pu&&st){var On=Es.get(tu);On!=null?On.push(il):Es.set(tu,[il])}yu(),b0&&U.emit("traceUpdates",B0),tu=-1},handleCommitFiberUnmount:function(ae){ti(ae,!1)},inspectElement:function(ae,ie){if(zi(ae)){if(ie!=null){Oo(ie);var Fe=null;return ie[0]==="hooks"&&(Fe="hooks"),{id:ae,type:"hydrated-path",path:ie,value:Ri(Uu(Xi,ie),Hi(null,Fe),ie)}}return{id:ae,type:"no-change"}}if(qs=!1,Xi!==null&&Xi.id===ae||(Ao={}),(Xi=aa(ae))===null)return{id:ae,type:"not-found"};ie!=null&&Oo(ie),function(st){var yt=st.hooks,Jt=st.id,On=st.props,Sn=e0.get(Jt);if(Sn!=null){var _n=Sn.elementType,Tn=Sn.stateNode,ir=Sn.tag,Bt=Sn.type;switch(ir){case Ct:case Cr:case An:$.$r=Tn;break;case it:$.$r={hooks:yt,props:On,type:Bt};break;case rn:$.$r={props:On,type:Bt.render};break;case Lr:case Nr:$.$r={props:On,type:_n!=null&&_n.type!=null?_n.type:Bt};break;default:$.$r=null}}else console.warn('Could not find Fiber with id "'.concat(Jt,'"'))}(Xi);var Oe=Vt({},Xi);return Oe.context=Ri(Oe.context,Hi("context",null)),Oe.hooks=Ri(Oe.hooks,Hi("hooks","hooks")),Oe.props=Ri(Oe.props,Hi("props",null)),Oe.state=Ri(Oe.state,Hi("state",null)),{id:ae,type:"full-data",value:Oe}},logElementToConsole:function(ae){var ie=zi(ae)?Xi:aa(ae);if(ie!==null){var Fe=typeof console.groupCollapsed=="function";Fe&&console.groupCollapsed("[Click to expand] %c<".concat(ie.displayName||"Component"," />"),"color: var(--dom-tag-name-color); font-weight: normal;"),ie.props!==null&&console.log("Props:",ie.props),ie.state!==null&&console.log("State:",ie.state),ie.hooks!==null&&console.log("Hooks:",ie.hooks);var Oe=Cl(ae);Oe!==null&&console.log("Nodes:",Oe),ie.source!==null&&console.log("Location:",ie.source),(window.chrome||/firefox/i.test(navigator.userAgent))&&console.log("Right-click any value to save it as a global variable for further inspection."),Fe&&console.groupEnd()}else console.warn('Could not find Fiber with id "'.concat(ae,'"'))},prepareViewAttributeSource:function(ae,ie){zi(ae)&&(window.$attribute=Uu(Xi,ie))},prepareViewElementSource:function(ae){var ie=e0.get(ae);if(ie!=null){var Fe=ie.elementType,Oe=ie.tag,st=ie.type;switch(Oe){case Ct:case Cr:case An:case it:$.$type=st;break;case rn:$.$type=st.render;break;case Lr:case Nr:$.$type=Fe!=null&&Fe.type!=null?Fe.type:st;break;default:$.$type=null}}else console.warn('Could not find Fiber with id "'.concat(ae,'"'))},overrideSuspense:function(ae,ie){if(typeof P0!="function"||typeof rl!="function")throw new Error("Expected overrideSuspense() to not get called for earlier React versions.");ie?($u.add(ae),$u.size===1&&P0(Ds)):($u.delete(ae),$u.size===0&&P0(_f));var Fe=e0.get(ae);Fe!=null&&rl(Fe)},overrideValueAtPath:function(ae,ie,Fe,Oe,st){var yt=Vu(ie);if(yt!==null){var Jt=yt.stateNode;switch(ae){case"context":switch(Oe=Oe.slice(1),yt.tag){case Ct:Oe.length===0?Jt.context=st:O0(Jt.context,Oe,st),Jt.forceUpdate()}break;case"hooks":typeof fu=="function"&&fu(yt,Fe,Oe,st);break;case"props":switch(yt.tag){case Ct:yt.pendingProps=bn(Jt.props,Oe,st),Jt.forceUpdate();break;default:typeof $o=="function"&&$o(yt,Oe,st)}break;case"state":switch(yt.tag){case Ct:O0(Jt.state,Oe,st),Jt.forceUpdate()}}}},renamePath:function(ae,ie,Fe,Oe,st){var yt=Vu(ie);if(yt!==null){var Jt=yt.stateNode;switch(ae){case"context":switch(Oe=Oe.slice(1),st=st.slice(1),yt.tag){case Ct:Oe.length===0||Xr(Jt.context,Oe,st),Jt.forceUpdate()}break;case"hooks":typeof Co=="function"&&Co(yt,Fe,Oe,st);break;case"props":Jt===null?typeof _i=="function"&&_i(yt,Oe,st):(yt.pendingProps=en(Jt.props,Oe,st),Jt.forceUpdate());break;case"state":Xr(Jt.state,Oe,st),Jt.forceUpdate()}}},renderer:G,setTraceUpdatesEnabled:function(ae){b0=ae},setTrackedPath:Ni,startProfiling:fa,stopProfiling:function(){Pu=!1,ts=!1},storeAsGlobal:function(ae,ie,Fe){if(zi(ae)){var Oe=Uu(Xi,ie),st="$reactTemp".concat(Fe);window[st]=Oe,console.log(st),console.log(Oe)}},updateComponentFilters:function(ae){if(Pu)throw Error("Cannot modify filter preferences while profiling");U.getFiberRoots(z).forEach(function(ie){tu=ei(Ei(ie.current)),Wu(ie.current),ti(ie.current,!1),tu=-1}),_s(ae),Kn.clear(),U.getFiberRoots(z).forEach(function(ie){eo(tu=ei(Ei(ie.current)),ie.current),Jr(ie.current,null,!1,!1),yu(ie),tu=-1})}}}var $n;function tl(U){return(tl=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(z){return typeof z}:function(z){return z&&typeof Symbol=="function"&&z.constructor===Symbol&&z!==Symbol.prototype?"symbol":typeof z})(U)}function c0(U,z,G){if($n===void 0)try{throw Error()}catch(Ce){var $=Ce.stack.trim().match(/\n( *(at )?)/);$n=$&&$[1]||""}return` -`+$n+U}var bo=!1;function Sl(U,z,G){if(!U||bo)return"";var $,Ce=Error.prepareStackTrace;Error.prepareStackTrace=void 0,bo=!0;var Ee=G.current;G.current=null;try{if(z){var Ae=function(){throw Error()};if(Object.defineProperty(Ae.prototype,"props",{set:function(){throw Error()}}),(typeof Reflect=="undefined"?"undefined":tl(Reflect))==="object"&&Reflect.construct){try{Reflect.construct(Ae,[])}catch(We){$=We}Reflect.construct(U,[],Ae)}else{try{Ae.call()}catch(We){$=We}U.call(Ae.prototype)}}else{try{throw Error()}catch(We){$=We}U()}}catch(We){if(We&&$&&typeof We.stack=="string"){for(var Z=We.stack.split(` -`),ke=$.stack.split(` -`),Je=Z.length-1,mt=ke.length-1;Je>=1&&mt>=0&&Z[Je]!==ke[mt];)mt--;for(;Je>=1&&mt>=0;Je--,mt--)if(Z[Je]!==ke[mt]){if(Je!==1||mt!==1)do if(Je--,--mt<0||Z[Je]!==ke[mt])return` -`+Z[Je].replace(" at new "," at ");while(Je>=1&&mt>=0);break}}}finally{bo=!1,Error.prepareStackTrace=Ce,G.current=Ee}var oe=U?U.displayName||U.name:"";return oe?c0(oe):""}function N0(U,z,G,$){return Sl(U,!1,$)}function wt(U,z,G){var $=U.HostComponent,Ce=U.LazyComponent,Ee=U.SuspenseComponent,Ae=U.SuspenseListComponent,Z=U.FunctionComponent,ke=U.IndeterminateComponent,Je=U.SimpleMemoComponent,mt=U.ForwardRef,oe=U.Block,We=U.ClassComponent;switch(z.tag){case $:return c0(z.type);case Ce:return c0("Lazy");case Ee:return c0("Suspense");case Ae:return c0("SuspenseList");case Z:case ke:case Je:return N0(z.type,0,0,G);case mt:return N0(z.type.render,0,0,G);case oe:return N0(z.type._render,0,0,G);case We:return function(it,Ct,Mt,It){return Sl(it,!0,It)}(z.type,0,0,G);default:return""}}function bt(U,z,G){try{var $="",Ce=z;do $+=wt(U,Ce,G),Ce=Ce.return;while(Ce);return $}catch(Ee){return` -Error generating stack: `+Ee.message+` -`+Ee.stack}}function Hn(U,z){var G;if(typeof Symbol=="undefined"||U[Symbol.iterator]==null){if(Array.isArray(U)||(G=function(ke,Je){if(!!ke){if(typeof ke=="string")return qr(ke,Je);var mt=Object.prototype.toString.call(ke).slice(8,-1);if(mt==="Object"&&ke.constructor&&(mt=ke.constructor.name),mt==="Map"||mt==="Set")return Array.from(ke);if(mt==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(mt))return qr(ke,Je)}}(U))||z&&U&&typeof U.length=="number"){G&&(U=G);var $=0,Ce=function(){};return{s:Ce,n:function(){return $>=U.length?{done:!0}:{done:!1,value:U[$++]}},e:function(ke){throw ke},f:Ce}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var Ee,Ae=!0,Z=!1;return{s:function(){G=U[Symbol.iterator]()},n:function(){var ke=G.next();return Ae=ke.done,ke},e:function(ke){Z=!0,Ee=ke},f:function(){try{Ae||G.return==null||G.return()}finally{if(Z)throw Ee}}}}function qr(U,z){(z==null||z>U.length)&&(z=U.length);for(var G=0,$=new Array(z);G0?Je[Je.length-1]:null,We=oe!==null&&(Qr.test(oe)||Ou.test(oe));if(!We){var it,Ct=Hn(vo.values());try{for(Ct.s();!(it=Ct.n()).done;){var Mt=it.value,It=Mt.currentDispatcherRef,sn=Mt.getCurrentFiber,rn=Mt.workTagMap,Ft=sn();if(Ft!=null){var Dn=bt(rn,Ft,It);Dn!==""&&Je.push(Dn);break}}}catch(dr){Ct.e(dr)}finally{Ct.f()}}}catch(dr){}Ee.apply(void 0,Je)};Ae.__REACT_DEVTOOLS_ORIGINAL_METHOD__=Ee,Li[Ce]=Ae}catch(Z){}})}}function ju(U){return(ju=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(z){return typeof z}:function(z){return z&&typeof Symbol=="function"&&z.constructor===Symbol&&z!==Symbol.prototype?"symbol":typeof z})(U)}function ms(U,z){for(var G=0;GU.length)&&(z=U.length);for(var G=0,$=new Array(z);G1?Z-1:0),Je=1;Je0?oe[oe.length-1]:0),oe.push(un),Z.set(et,Je(Pt._topLevelWrapper));try{var fn=ut.apply(this,Dt);return oe.pop(),fn}catch(wr){throw oe=[],wr}finally{if(oe.length===0){var Jn=Z.get(et);if(Jn===void 0)throw new Error("Expected to find root ID.");dr(Jn)}}},performUpdateIfNecessary:function(ut,Dt){var et=Dt[0];if(To(et)===9)return ut.apply(this,Dt);var Pt=Je(et);oe.push(Pt);var un=Qn(et);try{var fn=ut.apply(this,Dt),Jn=Qn(et);return mt(un,Jn)||Ct(et,Pt,Jn),oe.pop(),fn}catch(fu){throw oe=[],fu}finally{if(oe.length===0){var wr=Z.get(et);if(wr===void 0)throw new Error("Expected to find root ID.");dr(wr)}}},receiveComponent:function(ut,Dt){var et=Dt[0];if(To(et)===9)return ut.apply(this,Dt);var Pt=Je(et);oe.push(Pt);var un=Qn(et);try{var fn=ut.apply(this,Dt),Jn=Qn(et);return mt(un,Jn)||Ct(et,Pt,Jn),oe.pop(),fn}catch(fu){throw oe=[],fu}finally{if(oe.length===0){var wr=Z.get(et);if(wr===void 0)throw new Error("Expected to find root ID.");dr(wr)}}},unmountComponent:function(ut,Dt){var et=Dt[0];if(To(et)===9)return ut.apply(this,Dt);var Pt=Je(et);oe.push(Pt);try{var un=ut.apply(this,Dt);return oe.pop(),function(Jn,wr){rn.push(wr),Ee.delete(wr)}(0,Pt),un}catch(Jn){throw oe=[],Jn}finally{if(oe.length===0){var fn=Z.get(et);if(fn===void 0)throw new Error("Expected to find root ID.");dr(fn)}}}}));var It=[],sn=new Map,rn=[],Ft=0,Dn=null;function dr(ut){if(It.length!==0||rn.length!==0||Dn!==null){var Dt=rn.length+(Dn===null?0:1),et=new Array(3+Ft+(Dt>0?2+Dt:0)+It.length),Pt=0;if(et[Pt++]=z,et[Pt++]=ut,et[Pt++]=Ft,sn.forEach(function(Jn,wr){et[Pt++]=wr.length;for(var fu=Ko(wr),Lu=0;Lu0){et[Pt++]=2,et[Pt++]=Dt;for(var un=0;un"),"color: var(--dom-tag-name-color); font-weight: normal;"),Dt.props!==null&&console.log("Props:",Dt.props),Dt.state!==null&&console.log("State:",Dt.state),Dt.context!==null&&console.log("Context:",Dt.context);var Pt=Ce(ut);Pt!==null&&console.log("Node:",Pt),(window.chrome||/firefox/i.test(navigator.userAgent))&&console.log("Right-click any value to save it as a global variable for further inspection."),et&&console.groupEnd()}else console.warn('Could not find element with id "'.concat(ut,'"'))},overrideSuspense:function(){throw new Error("overrideSuspense not supported by this renderer")},overrideValueAtPath:function(ut,Dt,et,Pt,un){var fn=Ee.get(Dt);if(fn!=null){var Jn=fn._instance;if(Jn!=null)switch(ut){case"context":O0(Jn.context,Pt,un),yo(Jn);break;case"hooks":throw new Error("Hooks not supported by this renderer");case"props":var wr=fn._currentElement;fn._currentElement=Zo(Zo({},wr),{},{props:bn(wr.props,Pt,un)}),yo(Jn);break;case"state":O0(Jn.state,Pt,un),yo(Jn)}}},renamePath:function(ut,Dt,et,Pt,un){var fn=Ee.get(Dt);if(fn!=null){var Jn=fn._instance;if(Jn!=null)switch(ut){case"context":Xr(Jn.context,Pt,un),yo(Jn);break;case"hooks":throw new Error("Hooks not supported by this renderer");case"props":var wr=fn._currentElement;fn._currentElement=Zo(Zo({},wr),{},{props:en(wr.props,Pt,un)}),yo(Jn);break;case"state":Xr(Jn.state,Pt,un),yo(Jn)}}},prepareViewAttributeSource:function(ut,Dt){var et=Nr(ut);et!==null&&(window.$attribute=Uu(et,Dt))},prepareViewElementSource:function(ut){var Dt=Ee.get(ut);if(Dt!=null){var et=Dt._currentElement;et!=null?$.$type=et.type:console.warn('Could not find element with id "'.concat(ut,'"'))}else console.warn('Could not find instance with id "'.concat(ut,'"'))},renderer:G,setTraceUpdatesEnabled:function(ut){},setTrackedPath:function(ut){},startProfiling:function(){},stopProfiling:function(){},storeAsGlobal:function(ut,Dt,et){var Pt=Nr(ut);if(Pt!==null){var un=Uu(Pt,Dt),fn="$reactTemp".concat(et);window[fn]=un,console.log(fn),console.log(un)}},updateComponentFilters:function(ut){}}}function fi(U,z){var G=!1,$={bottom:0,left:0,right:0,top:0},Ce=z[U];if(Ce!=null){for(var Ee=0,Ae=Object.keys($);Ee0?"development":"production";var It=Function.prototype.toString;if(Mt.Mount&&Mt.Mount._renderNewRootComponent){var sn=It.call(Mt.Mount._renderNewRootComponent);return sn.indexOf("function")!==0?"production":sn.indexOf("storedMeasure")!==-1?"development":sn.indexOf("should be a pure function")!==-1?sn.indexOf("NODE_ENV")!==-1||sn.indexOf("development")!==-1||sn.indexOf("true")!==-1?"development":sn.indexOf("nextElement")!==-1||sn.indexOf("nextComponent")!==-1?"unminified":"development":sn.indexOf("nextElement")!==-1||sn.indexOf("nextComponent")!==-1?"unminified":"outdated"}}catch(rn){}return"production"}(ke);try{var oe=window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__!==!1,We=window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__===!0;(oe||We)&&(d0(ke),Zl({appendComponentStack:oe,breakOnConsoleErrors:We}))}catch(Mt){}var it=U.__REACT_DEVTOOLS_ATTACH__;if(typeof it=="function"){var Ct=it(Z,Je,ke,U);Z.rendererInterfaces.set(Je,Ct)}return Z.emit("renderer",{id:Je,renderer:ke,reactBuildType:mt}),Je},on:function(ke,Je){Ee[ke]||(Ee[ke]=[]),Ee[ke].push(Je)},off:function(ke,Je){if(Ee[ke]){var mt=Ee[ke].indexOf(Je);mt!==-1&&Ee[ke].splice(mt,1),Ee[ke].length||delete Ee[ke]}},sub:function(ke,Je){return Z.on(ke,Je),function(){return Z.off(ke,Je)}},supportsFiber:!0,checkDCE:function(ke){try{Function.prototype.toString.call(ke).indexOf("^_^")>-1&&(G=!0,setTimeout(function(){throw new Error("React is running in production mode, but dead code elimination has not been applied. Read how to correctly configure React for production: https://reactjs.org/link/perf-use-production-build")}))}catch(Je){}},onCommitFiberUnmount:function(ke,Je){var mt=Ce.get(ke);mt!=null&&mt.handleCommitFiberUnmount(Je)},onCommitFiberRoot:function(ke,Je,mt){var oe=Z.getFiberRoots(ke),We=Je.current,it=oe.has(Je),Ct=We.memoizedState==null||We.memoizedState.element==null;it||Ct?it&&Ct&&oe.delete(Je):oe.add(Je);var Mt=Ce.get(ke);Mt!=null&&Mt.handleCommitFiberRoot(Je,mt)}};Object.defineProperty(U,"__REACT_DEVTOOLS_GLOBAL_HOOK__",{configurable:!1,enumerable:!1,get:function(){return Z}})})(window);var go=window.__REACT_DEVTOOLS_GLOBAL_HOOK__,js=[{type:1,value:7,isEnabled:!0}];function ji(U){if(go!=null){var z=U||{},G=z.host,$=G===void 0?"localhost":G,Ce=z.nativeStyleEditorValidAttributes,Ee=z.useHttps,Ae=Ee!==void 0&&Ee,Z=z.port,ke=Z===void 0?8097:Z,Je=z.websocket,mt=z.resolveRNStyle,oe=mt===void 0?null:mt,We=z.isAppActive,it=Ae?"wss":"ws",Ct=null;if((We===void 0?function(){return!0}:We)()){var Mt=null,It=[],sn=it+"://"+$+":"+ke,rn=Je||new window.WebSocket(sn);rn.onclose=function(){Mt!==null&&Mt.emit("shutdown"),Ft()},rn.onerror=function(){Ft()},rn.onmessage=function(Dn){var dr;try{if(typeof Dn.data!="string")throw Error();dr=JSON.parse(Dn.data)}catch(er){return void console.error("[React DevTools] Failed to parse JSON: "+Dn.data)}It.forEach(function(er){try{er(dr)}catch(Cr){throw console.log("[React DevTools] Error calling listener",dr),console.log("error:",Cr),Cr}})},rn.onopen=function(){(Mt=new p0({listen:function(An){return It.push(An),function(){var Lr=It.indexOf(An);Lr>=0&&It.splice(Lr,1)}},send:function(An,Lr,_o){rn.readyState===rn.OPEN?rn.send(JSON.stringify({event:An,payload:Lr})):(Mt!==null&&Mt.shutdown(),Ft())}})).addListener("inspectElement",function(An){var Lr=An.id,_o=An.rendererID,Nr=Dn.rendererInterfaces[_o];if(Nr!=null){var ut=Nr.findNativeNodesForFiberID(Lr);ut!=null&&ut[0]!=null&&Dn.emit("showNativeHighlight",ut[0])}}),Mt.addListener("updateComponentFilters",function(An){js=An}),window.__REACT_DEVTOOLS_COMPONENT_FILTERS__==null&&Mt.send("overrideComponentFilters",js);var Dn=new Yn(Mt);if(Dn.addListener("shutdown",function(){go.emit("shutdown")}),function(An,Lr,_o){if(An==null)return function(){};var Nr=[An.sub("renderer-attached",function(et){var Pt=et.id,un=(et.renderer,et.rendererInterface);Lr.setRendererInterface(Pt,un),un.flushInitialOperations()}),An.sub("unsupported-renderer-version",function(et){Lr.onUnsupportedRenderer(et)}),An.sub("operations",Lr.onHookOperations),An.sub("traceUpdates",Lr.onTraceUpdates)],ut=function(et,Pt){var un=An.rendererInterfaces.get(et);un==null&&(typeof Pt.findFiberByHostInstance=="function"?un=bs(An,et,Pt,_o):Pt.ComponentTree&&(un=fc(An,et,Pt,_o)),un!=null&&An.rendererInterfaces.set(et,un)),un!=null?An.emit("renderer-attached",{id:et,renderer:Pt,rendererInterface:un}):An.emit("unsupported-renderer-version",et)};An.renderers.forEach(function(et,Pt){ut(Pt,et)}),Nr.push(An.sub("renderer",function(et){var Pt=et.id,un=et.renderer;ut(Pt,un)})),An.emit("react-devtools",Lr),An.reactDevtoolsAgent=Lr;var Dt=function(){Nr.forEach(function(et){return et()}),An.rendererInterfaces.forEach(function(et){et.cleanup()}),An.reactDevtoolsAgent=null};Lr.addListener("shutdown",Dt),Nr.push(function(){Lr.removeListener("shutdown",Dt)})}(go,Dn,window),oe!=null||go.resolveRNStyle!=null)la(Mt,Dn,oe||go.resolveRNStyle,Ce||go.nativeStyleEditorValidAttributes||null);else{var dr,er,Cr=function(){Mt!==null&&la(Mt,Dn,dr,er)};go.hasOwnProperty("resolveRNStyle")||Object.defineProperty(go,"resolveRNStyle",{enumerable:!1,get:function(){return dr},set:function(An){dr=An,Cr()}}),go.hasOwnProperty("nativeStyleEditorValidAttributes")||Object.defineProperty(go,"nativeStyleEditorValidAttributes",{enumerable:!1,get:function(){return er},set:function(An){er=An,Cr()}})}}}else Ft()}function Ft(){Ct===null&&(Ct=setTimeout(function(){return ji(U)},2e3))}}}])})});var f6=Ke(a6=>{"use strict";Object.defineProperty(a6,"__esModule",{value:!0});l6();var HB=s6();HB.connectToDevTools()});var v6=Ke(dg=>{"use strict";var c6=dg&&dg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(dg,"__esModule",{value:!0});var d6=Q_(),qB=c6(vT()),p6=c6(eh()),hs=iw();process.env.DEV==="true"&&f6();var h6=i=>{i==null||i.unsetMeasureFunc(),i==null||i.freeRecursive()};dg.default=qB.default({schedulePassiveEffects:d6.unstable_scheduleCallback,cancelPassiveEffects:d6.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>{},resetAfterCommit:i=>{if(i.isStaticDirty){i.isStaticDirty=!1,typeof i.onImmediateRender=="function"&&i.onImmediateRender();return}typeof i.onRender=="function"&&i.onRender()},getChildHostContext:(i,o)=>{let a=i.isInsideText,c=o==="ink-text"||o==="ink-virtual-text";return a===c?i:{isInsideText:c}},shouldSetTextContent:()=>!1,createInstance:(i,o,a,c)=>{if(c.isInsideText&&i==="ink-box")throw new Error(" can\u2019t be nested inside component");let _=i==="ink-text"&&c.isInsideText?"ink-virtual-text":i,t=hs.createNode(_);for(let[M,N]of Object.entries(o))M!=="children"&&(M==="style"?hs.setStyle(t,N):M==="internal_transform"?t.internal_transform=N:M==="internal_static"?t.internal_static=!0:hs.setAttribute(t,M,N));return t},createTextInstance:(i,o,a)=>{if(!a.isInsideText)throw new Error(`Text string "${i}" must be rendered inside component`);return hs.createTextNode(i)},resetTextContent:()=>{},hideTextInstance:i=>{hs.setTextNodeValue(i,"")},unhideTextInstance:(i,o)=>{hs.setTextNodeValue(i,o)},getPublicInstance:i=>i,hideInstance:i=>{var o;(o=i.yogaNode)===null||o===void 0||o.setDisplay(p6.default.DISPLAY_NONE)},unhideInstance:i=>{var o;(o=i.yogaNode)===null||o===void 0||o.setDisplay(p6.default.DISPLAY_FLEX)},appendInitialChild:hs.appendChildNode,appendChild:hs.appendChildNode,insertBefore:hs.insertBeforeNode,finalizeInitialChildren:(i,o,a,c)=>(i.internal_static&&(c.isStaticDirty=!0,c.staticNode=i),!1),supportsMutation:!0,appendChildToContainer:hs.appendChildNode,insertInContainerBefore:hs.insertBeforeNode,removeChildFromContainer:(i,o)=>{hs.removeChildNode(i,o),h6(o.yogaNode)},prepareUpdate:(i,o,a,c,_)=>{i.internal_static&&(_.isStaticDirty=!0);let t={},M=Object.keys(c);for(let N of M)if(c[N]!==a[N]){if(N==="style"&&typeof c.style=="object"&&typeof a.style=="object"){let T=c.style,B=a.style,H=Object.keys(T);for(let q of H){if(q==="borderStyle"||q==="borderColor"){if(typeof t.style!="object"){let ne={};t.style=ne}t.style.borderStyle=T.borderStyle,t.style.borderColor=T.borderColor}if(T[q]!==B[q]){if(typeof t.style!="object"){let ne={};t.style=ne}t.style[q]=T[q]}}continue}t[N]=c[N]}return t},commitUpdate:(i,o)=>{for(let[a,c]of Object.entries(o))a!=="children"&&(a==="style"?hs.setStyle(i,c):a==="internal_transform"?i.internal_transform=c:a==="internal_static"?i.internal_static=!0:hs.setAttribute(i,a,c))},commitTextUpdate:(i,o,a)=>{hs.setTextNodeValue(i,a)},removeChild:(i,o)=>{hs.removeChildNode(i,o),h6(o.yogaNode)}})});var y6=Ke((AV,m6)=>{"use strict";m6.exports=(i,o=1,a)=>{if(a=qt({indent:" ",includeEmptyLines:!1},a),typeof i!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof i}\``);if(typeof o!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof o}\``);if(typeof a.indent!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof a.indent}\``);if(o===0)return i;let c=a.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return i.replace(c,a.indent.repeat(o))}});var g6=Ke(pg=>{"use strict";var WB=pg&&pg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(pg,"__esModule",{value:!0});var d4=WB(eh());pg.default=i=>i.getComputedWidth()-i.getComputedPadding(d4.default.EDGE_LEFT)-i.getComputedPadding(d4.default.EDGE_RIGHT)-i.getComputedBorder(d4.default.EDGE_LEFT)-i.getComputedBorder(d4.default.EDGE_RIGHT)});var E6=Ke((MV,_6)=>{_6.exports={single:{topLeft:"\u250C",topRight:"\u2510",bottomRight:"\u2518",bottomLeft:"\u2514",vertical:"\u2502",horizontal:"\u2500"},double:{topLeft:"\u2554",topRight:"\u2557",bottomRight:"\u255D",bottomLeft:"\u255A",vertical:"\u2551",horizontal:"\u2550"},round:{topLeft:"\u256D",topRight:"\u256E",bottomRight:"\u256F",bottomLeft:"\u2570",vertical:"\u2502",horizontal:"\u2500"},bold:{topLeft:"\u250F",topRight:"\u2513",bottomRight:"\u251B",bottomLeft:"\u2517",vertical:"\u2503",horizontal:"\u2501"},singleDouble:{topLeft:"\u2553",topRight:"\u2556",bottomRight:"\u255C",bottomLeft:"\u2559",vertical:"\u2551",horizontal:"\u2500"},doubleSingle:{topLeft:"\u2552",topRight:"\u2555",bottomRight:"\u255B",bottomLeft:"\u2558",vertical:"\u2502",horizontal:"\u2550"},classic:{topLeft:"+",topRight:"+",bottomRight:"+",bottomLeft:"+",vertical:"|",horizontal:"-"}}});var w6=Ke((kV,Sw)=>{"use strict";var D6=E6();Sw.exports=D6;Sw.exports.default=D6});var T6=Ke((LV,S6)=>{"use strict";S6.exports=(i,o=process.argv)=>{let a=i.startsWith("-")?"":i.length===1?"-":"--",c=o.indexOf(a+i),_=o.indexOf("--");return c!==-1&&(_===-1||c<_)}});var R6=Ke((NV,C6)=>{"use strict";var VB=require("os"),x6=require("tty"),pf=T6(),{env:X0}=process,m2;pf("no-color")||pf("no-colors")||pf("color=false")||pf("color=never")?m2=0:(pf("color")||pf("colors")||pf("color=true")||pf("color=always"))&&(m2=1);"FORCE_COLOR"in X0&&(X0.FORCE_COLOR==="true"?m2=1:X0.FORCE_COLOR==="false"?m2=0:m2=X0.FORCE_COLOR.length===0?1:Math.min(parseInt(X0.FORCE_COLOR,10),3));function Tw(i){return i===0?!1:{level:i,hasBasic:!0,has256:i>=2,has16m:i>=3}}function Cw(i,o){if(m2===0)return 0;if(pf("color=16m")||pf("color=full")||pf("color=truecolor"))return 3;if(pf("color=256"))return 2;if(i&&!o&&m2===void 0)return 0;let a=m2||0;if(X0.TERM==="dumb")return a;if(process.platform==="win32"){let c=VB.release().split(".");return Number(c[0])>=10&&Number(c[2])>=10586?Number(c[2])>=14931?3:2:1}if("CI"in X0)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some(c=>c in X0)||X0.CI_NAME==="codeship"?1:a;if("TEAMCITY_VERSION"in X0)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(X0.TEAMCITY_VERSION)?1:0;if("GITHUB_ACTIONS"in X0)return 1;if(X0.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in X0){let c=parseInt((X0.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(X0.TERM_PROGRAM){case"iTerm.app":return c>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(X0.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(X0.TERM)||"COLORTERM"in X0?1:a}function GB(i){let o=Cw(i,i&&i.isTTY);return Tw(o)}C6.exports={supportsColor:GB,stdout:Tw(Cw(!0,x6.isatty(1))),stderr:Tw(Cw(!0,x6.isatty(2)))}});var O6=Ke((FV,A6)=>{"use strict";var YB=(i,o,a)=>{let c=i.indexOf(o);if(c===-1)return i;let _=o.length,t=0,M="";do M+=i.substr(t,c-t)+o+a,t=c+_,c=i.indexOf(o,t);while(c!==-1);return M+=i.substr(t),M},KB=(i,o,a,c)=>{let _=0,t="";do{let M=i[c-1]==="\r";t+=i.substr(_,(M?c-1:c)-_)+o+(M?`\r -`:` -`)+a,_=c+1,c=i.indexOf(` -`,_)}while(c!==-1);return t+=i.substr(_),t};A6.exports={stringReplaceAll:YB,stringEncaseCRLFWithFirstIndex:KB}});var F6=Ke((PV,M6)=>{"use strict";var XB=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,k6=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,QB=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,JB=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,ZB=new Map([["n",` -`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e",""],["a","\x07"]]);function L6(i){let o=i[0]==="u",a=i[1]==="{";return o&&!a&&i.length===5||i[0]==="x"&&i.length===3?String.fromCharCode(parseInt(i.slice(1),16)):o&&a?String.fromCodePoint(parseInt(i.slice(2,-1),16)):ZB.get(i)||i}function $B(i,o){let a=[],c=o.trim().split(/\s*,\s*/g),_;for(let t of c){let M=Number(t);if(!Number.isNaN(M))a.push(M);else if(_=t.match(QB))a.push(_[2].replace(JB,(N,O,T)=>O?L6(O):T));else throw new Error(`Invalid Chalk template style argument: ${t} (in style '${i}')`)}return a}function eU(i){k6.lastIndex=0;let o=[],a;for(;(a=k6.exec(i))!==null;){let c=a[1];if(a[2]){let _=$B(c,a[2]);o.push([c].concat(_))}else o.push([c])}return o}function N6(i,o){let a={};for(let _ of o)for(let t of _.styles)a[t[0]]=_.inverse?null:t.slice(1);let c=i;for(let[_,t]of Object.entries(a))if(!!Array.isArray(t)){if(!(_ in c))throw new Error(`Unknown Chalk style: ${_}`);c=t.length>0?c[_](...t):c[_]}return c}M6.exports=(i,o)=>{let a=[],c=[],_=[];if(o.replace(XB,(t,M,N,O,T,B)=>{if(M)_.push(L6(M));else if(O){let H=_.join("");_=[],c.push(a.length===0?H:N6(i,a)(H)),a.push({inverse:N,styles:eU(O)})}else if(T){if(a.length===0)throw new Error("Found extraneous } in Chalk template literal");c.push(N6(i,a)(_.join(""))),_=[],a.pop()}else _.push(B)}),c.push(_.join("")),a.length>0){let t=`Chalk template literal is missing ${a.length} closing bracket${a.length===1?"":"s"} (\`}\`)`;throw new Error(t)}return c.join("")}});var y4=Ke((IV,P6)=>{"use strict";var hg=t4(),{stdout:xw,stderr:Rw}=R6(),{stringReplaceAll:tU,stringEncaseCRLFWithFirstIndex:nU}=O6(),{isArray:p4}=Array,I6=["ansi","ansi","ansi256","ansi16m"],$v=Object.create(null),rU=(i,o={})=>{if(o.level&&!(Number.isInteger(o.level)&&o.level>=0&&o.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let a=xw?xw.level:0;i.level=o.level===void 0?a:o.level},b6=class{constructor(o){return B6(o)}},B6=i=>{let o={};return rU(o,i),o.template=(...a)=>U6(o.template,...a),Object.setPrototypeOf(o,h4.prototype),Object.setPrototypeOf(o.template,o),o.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},o.template.Instance=b6,o.template};function h4(i){return B6(i)}for(let[i,o]of Object.entries(hg))$v[i]={get(){let a=v4(this,Aw(o.open,o.close,this._styler),this._isEmpty);return Object.defineProperty(this,i,{value:a}),a}};$v.visible={get(){let i=v4(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:i}),i}};var j6=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let i of j6)$v[i]={get(){let{level:o}=this;return function(...a){let c=Aw(hg.color[I6[o]][i](...a),hg.color.close,this._styler);return v4(this,c,this._isEmpty)}}};for(let i of j6){let o="bg"+i[0].toUpperCase()+i.slice(1);$v[o]={get(){let{level:a}=this;return function(...c){let _=Aw(hg.bgColor[I6[a]][i](...c),hg.bgColor.close,this._styler);return v4(this,_,this._isEmpty)}}}}var iU=Object.defineProperties(()=>{},Zr(qt({},$v),{level:{enumerable:!0,get(){return this._generator.level},set(i){this._generator.level=i}}})),Aw=(i,o,a)=>{let c,_;return a===void 0?(c=i,_=o):(c=a.openAll+i,_=o+a.closeAll),{open:i,close:o,openAll:c,closeAll:_,parent:a}},v4=(i,o,a)=>{let c=(..._)=>p4(_[0])&&p4(_[0].raw)?z6(c,U6(c,..._)):z6(c,_.length===1?""+_[0]:_.join(" "));return Object.setPrototypeOf(c,iU),c._generator=i,c._styler=o,c._isEmpty=a,c},z6=(i,o)=>{if(i.level<=0||!o)return i._isEmpty?"":o;let a=i._styler;if(a===void 0)return o;let{openAll:c,closeAll:_}=a;if(o.indexOf("")!==-1)for(;a!==void 0;)o=tU(o,a.close,a.open),a=a.parent;let t=o.indexOf(` -`);return t!==-1&&(o=nU(o,_,c,t)),c+o+_},Ow,U6=(i,...o)=>{let[a]=o;if(!p4(a)||!p4(a.raw))return o.join(" ");let c=o.slice(1),_=[a.raw[0]];for(let t=1;t{"use strict";var uU=vg&&vg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(vg,"__esModule",{value:!0});var mg=uU(y4()),oU=/^(rgb|hsl|hsv|hwb)\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/,lU=/^(ansi|ansi256)\(\s?(\d+)\s?\)$/,g4=(i,o)=>o==="foreground"?i:"bg"+i[0].toUpperCase()+i.slice(1);vg.default=(i,o,a)=>{if(!o)return i;if(o in mg.default){let _=g4(o,a);return mg.default[_](i)}if(o.startsWith("#")){let _=g4("hex",a);return mg.default[_](o)(i)}if(o.startsWith("ansi")){let _=lU.exec(o);if(!_)return i;let t=g4(_[1],a),M=Number(_[2]);return mg.default[t](M)(i)}if(o.startsWith("rgb")||o.startsWith("hsl")||o.startsWith("hsv")||o.startsWith("hwb")){let _=oU.exec(o);if(!_)return i;let t=g4(_[1],a),M=Number(_[2]),N=Number(_[3]),O=Number(_[4]);return mg.default[t](M,N,O)(i)}return i}});var q6=Ke(yg=>{"use strict";var H6=yg&&yg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(yg,"__esModule",{value:!0});var sU=H6(w6()),kw=H6(Mw());yg.default=(i,o,a,c)=>{if(typeof a.style.borderStyle=="string"){let _=a.yogaNode.getComputedWidth(),t=a.yogaNode.getComputedHeight(),M=a.style.borderColor,N=sU.default[a.style.borderStyle],O=kw.default(N.topLeft+N.horizontal.repeat(_-2)+N.topRight,M,"foreground"),T=(kw.default(N.vertical,M,"foreground")+` -`).repeat(t-2),B=kw.default(N.bottomLeft+N.horizontal.repeat(_-2)+N.bottomRight,M,"foreground");c.write(i,o,O,{transformers:[]}),c.write(i,o+1,T,{transformers:[]}),c.write(i+_-1,o+1,T,{transformers:[]}),c.write(i,o+t-1,B,{transformers:[]})}}});var V6=Ke(gg=>{"use strict";var ih=gg&&gg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(gg,"__esModule",{value:!0});var aU=ih(eh()),fU=ih(GD()),cU=ih(y6()),dU=ih(tw()),pU=ih(g6()),hU=ih(rw()),vU=ih(q6()),mU=(i,o)=>{var a;let c=(a=i.childNodes[0])===null||a===void 0?void 0:a.yogaNode;if(c){let _=c.getComputedLeft(),t=c.getComputedTop();o=` -`.repeat(t)+cU.default(o,_)}return o},W6=(i,o,a)=>{var c;let{offsetX:_=0,offsetY:t=0,transformers:M=[],skipStaticElements:N}=a;if(N&&i.internal_static)return;let{yogaNode:O}=i;if(O){if(O.getDisplay()===aU.default.DISPLAY_NONE)return;let T=_+O.getComputedLeft(),B=t+O.getComputedTop(),H=M;if(typeof i.internal_transform=="function"&&(H=[i.internal_transform,...M]),i.nodeName==="ink-text"){let q=hU.default(i);if(q.length>0){let ne=fU.default(q),m=pU.default(O);if(ne>m){let pe=(c=i.style.textWrap)!==null&&c!==void 0?c:"wrap";q=dU.default(q,m,pe)}q=mU(i,q),o.write(T,B,q,{transformers:H})}return}if(i.nodeName==="ink-box"&&vU.default(T,B,i,o),i.nodeName==="ink-root"||i.nodeName==="ink-box")for(let q of i.childNodes)W6(q,o,{offsetX:T,offsetY:B,transformers:H,skipStaticElements:N})}};gg.default=W6});var Y6=Ke((jV,G6)=>{"use strict";G6.exports=i=>{i=Object.assign({onlyFirst:!1},i);let o=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(o,i.onlyFirst?void 0:"g")}});var X6=Ke((zV,Lw)=>{"use strict";var yU=Y6(),K6=i=>typeof i=="string"?i.replace(yU(),""):i;Lw.exports=K6;Lw.exports.default=K6});var Z6=Ke((HV,Q6)=>{"use strict";var J6="[\uD800-\uDBFF][\uDC00-\uDFFF]";Q6.exports=i=>i&&i.exact?new RegExp(`^${J6}$`):new RegExp(J6,"g")});var ex=Ke((qV,Nw)=>{"use strict";var gU=X6(),_U=Z6(),$6=i=>gU(i).replace(_U()," ").length;Nw.exports=$6;Nw.exports.default=$6});var ix=Ke(_g=>{"use strict";var tx=_g&&_g.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(_g,"__esModule",{value:!0});var nx=tx($D()),EU=tx(ex()),rx=class{constructor(o){this.writes=[];let{width:a,height:c}=o;this.width=a,this.height=c}write(o,a,c,_){let{transformers:t}=_;!c||this.writes.push({x:o,y:a,text:c,transformers:t})}get(){let o=[];for(let c=0;cc.trimRight()).join(` -`),height:o.length}}};_g.default=rx});var lx=Ke(Eg=>{"use strict";var Fw=Eg&&Eg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Eg,"__esModule",{value:!0});var DU=Fw(eh()),ux=Fw(V6()),ox=Fw(ix());Eg.default=(i,o)=>{var a;if(i.yogaNode.setWidth(o),i.yogaNode){i.yogaNode.calculateLayout(void 0,void 0,DU.default.DIRECTION_LTR);let c=new ox.default({width:i.yogaNode.getComputedWidth(),height:i.yogaNode.getComputedHeight()});ux.default(i,c,{skipStaticElements:!0});let _;((a=i.staticNode)===null||a===void 0?void 0:a.yogaNode)&&(_=new ox.default({width:i.staticNode.yogaNode.getComputedWidth(),height:i.staticNode.yogaNode.getComputedHeight()}),ux.default(i.staticNode,_,{skipStaticElements:!1}));let{output:t,height:M}=c.get();return{output:t,outputHeight:M,staticOutput:_?`${_.get().output} -`:""}}return{output:"",outputHeight:0,staticOutput:""}}});var cx=Ke((GV,sx)=>{"use strict";var ax=require("stream"),fx=["assert","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"],Pw={},wU=i=>{let o=new ax.PassThrough,a=new ax.PassThrough;o.write=_=>i("stdout",_),a.write=_=>i("stderr",_);let c=new console.Console(o,a);for(let _ of fx)Pw[_]=console[_],console[_]=c[_];return()=>{for(let _ of fx)console[_]=Pw[_];Pw={}}};sx.exports=wU});var bw=Ke(Iw=>{"use strict";Object.defineProperty(Iw,"__esModule",{value:!0});Iw.default=new WeakMap});var Uw=Ke(Bw=>{"use strict";Object.defineProperty(Bw,"__esModule",{value:!0});var SU=Mi(),dx=SU.createContext({exit:()=>{}});dx.displayName="InternalAppContext";Bw.default=dx});var zw=Ke(jw=>{"use strict";Object.defineProperty(jw,"__esModule",{value:!0});var TU=Mi(),px=TU.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});px.displayName="InternalStdinContext";jw.default=px});var qw=Ke(Hw=>{"use strict";Object.defineProperty(Hw,"__esModule",{value:!0});var CU=Mi(),hx=CU.createContext({stdout:void 0,write:()=>{}});hx.displayName="InternalStdoutContext";Hw.default=hx});var Vw=Ke(Ww=>{"use strict";Object.defineProperty(Ww,"__esModule",{value:!0});var xU=Mi(),vx=xU.createContext({stderr:void 0,write:()=>{}});vx.displayName="InternalStderrContext";Ww.default=vx});var _4=Ke(Gw=>{"use strict";Object.defineProperty(Gw,"__esModule",{value:!0});var RU=Mi(),mx=RU.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{}});mx.displayName="InternalFocusContext";Gw.default=mx});var gx=Ke(($V,yx)=>{"use strict";var AU=/[|\\{}()[\]^$+*?.-]/g;yx.exports=i=>{if(typeof i!="string")throw new TypeError("Expected a string");return i.replace(AU,"\\$&")}});var wx=Ke((eG,_x)=>{"use strict";var OU=gx(),Ex=[].concat(require("module").builtinModules,"bootstrap_node","node").map(i=>new RegExp(`(?:\\(${i}\\.js:\\d+:\\d+\\)$|^\\s*at ${i}\\.js:\\d+:\\d+$)`));Ex.push(/\(internal\/[^:]+:\d+:\d+\)$/,/\s*at internal\/[^:]+:\d+:\d+$/,/\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/);var E4=class{constructor(o){o=qt({ignoredPackages:[]},o),"internals"in o||(o.internals=E4.nodeInternals()),"cwd"in o||(o.cwd=process.cwd()),this._cwd=o.cwd.replace(/\\/g,"/"),this._internals=[].concat(o.internals,MU(o.ignoredPackages)),this._wrapCallSite=o.wrapCallSite||!1}static nodeInternals(){return[...Ex]}clean(o,a=0){a=" ".repeat(a),Array.isArray(o)||(o=o.split(` -`)),!/^\s*at /.test(o[0])&&/^\s*at /.test(o[1])&&(o=o.slice(1));let c=!1,_=null,t=[];return o.forEach(M=>{if(M=M.replace(/\\/g,"/"),this._internals.some(O=>O.test(M)))return;let N=/^\s*at /.test(M);c?M=M.trimEnd().replace(/^(\s+)at /,"$1"):(M=M.trim(),N&&(M=M.slice(3))),M=M.replace(`${this._cwd}/`,""),M&&(N?(_&&(t.push(_),_=null),t.push(M)):(c=!0,_=M))}),t.map(M=>`${a}${M} -`).join("")}captureString(o,a=this.captureString){typeof o=="function"&&(a=o,o=Infinity);let{stackTraceLimit:c}=Error;o&&(Error.stackTraceLimit=o);let _={};Error.captureStackTrace(_,a);let{stack:t}=_;return Error.stackTraceLimit=c,this.clean(t)}capture(o,a=this.capture){typeof o=="function"&&(a=o,o=Infinity);let{prepareStackTrace:c,stackTraceLimit:_}=Error;Error.prepareStackTrace=(N,O)=>this._wrapCallSite?O.map(this._wrapCallSite):O,o&&(Error.stackTraceLimit=o);let t={};Error.captureStackTrace(t,a);let{stack:M}=t;return Object.assign(Error,{prepareStackTrace:c,stackTraceLimit:_}),M}at(o=this.at){let[a]=this.capture(1,o);if(!a)return{};let c={line:a.getLineNumber(),column:a.getColumnNumber()};Dx(c,a.getFileName(),this._cwd),a.isConstructor()&&(c.constructor=!0),a.isEval()&&(c.evalOrigin=a.getEvalOrigin()),a.isNative()&&(c.native=!0);let _;try{_=a.getTypeName()}catch(N){}_&&_!=="Object"&&_!=="[object Object]"&&(c.type=_);let t=a.getFunctionName();t&&(c.function=t);let M=a.getMethodName();return M&&t!==M&&(c.method=M),c}parseLine(o){let a=o&&o.match(kU);if(!a)return null;let c=a[1]==="new",_=a[2],t=a[3],M=a[4],N=Number(a[5]),O=Number(a[6]),T=a[7],B=a[8],H=a[9],q=a[10]==="native",ne=a[11]===")",m,pe={};if(B&&(pe.line=Number(B)),H&&(pe.column=Number(H)),ne&&T){let ge=0;for(let ve=T.length-1;ve>0;ve--)if(T.charAt(ve)===")")ge++;else if(T.charAt(ve)==="("&&T.charAt(ve-1)===" "&&(ge--,ge===-1&&T.charAt(ve-1)===" ")){let ue=T.slice(0,ve-1);T=T.slice(ve+1),_+=` (${ue}`;break}}if(_){let ge=_.match(LU);ge&&(_=ge[1],m=ge[2])}return Dx(pe,T,this._cwd),c&&(pe.constructor=!0),t&&(pe.evalOrigin=t,pe.evalLine=N,pe.evalColumn=O,pe.evalFile=M&&M.replace(/\\/g,"/")),q&&(pe.native=!0),_&&(pe.function=_),m&&_!==m&&(pe.method=m),pe}};function Dx(i,o,a){o&&(o=o.replace(/\\/g,"/"),o.startsWith(`${a}/`)&&(o=o.slice(a.length+1)),i.file=o)}function MU(i){if(i.length===0)return[];let o=i.map(a=>OU(a));return new RegExp(`[/\\\\]node_modules[/\\\\](?:${o.join("|")})[/\\\\][^:]+:\\d+:\\d+`)}var kU=new RegExp("^(?:\\s*at )?(?:(new) )?(?:(.*?) \\()?(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?(?:(.+?):(\\d+):(\\d+)|(native))(\\)?)$"),LU=/^(.*?) \[as (.*?)\]$/;_x.exports=E4});var Tx=Ke((tG,Sx)=>{"use strict";Sx.exports=(i,o)=>i.replace(/^\t+/gm,a=>" ".repeat(a.length*(o||2)))});var xx=Ke((nG,Cx)=>{"use strict";var NU=Tx(),FU=(i,o)=>{let a=[],c=i-o,_=i+o;for(let t=c;t<=_;t++)a.push(t);return a};Cx.exports=(i,o,a)=>{if(typeof i!="string")throw new TypeError("Source code is missing.");if(!o||o<1)throw new TypeError("Line number must start from `1`.");if(i=NU(i).split(/\r?\n/),!(o>i.length))return a=qt({around:3},a),FU(o,a.around).filter(c=>i[c-1]!==void 0).map(c=>({line:c,value:i[c-1]}))}});var D4=Ke(rc=>{"use strict";var PU=rc&&rc.__createBinding||(Object.create?function(i,o,a,c){c===void 0&&(c=a),Object.defineProperty(i,c,{enumerable:!0,get:function(){return o[a]}})}:function(i,o,a,c){c===void 0&&(c=a),i[c]=o[a]}),IU=rc&&rc.__setModuleDefault||(Object.create?function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}:function(i,o){i.default=o}),bU=rc&&rc.__importStar||function(i){if(i&&i.__esModule)return i;var o={};if(i!=null)for(var a in i)a!=="default"&&Object.hasOwnProperty.call(i,a)&&PU(o,i,a);return IU(o,i),o},BU=rc&&rc.__rest||function(i,o){var a={};for(var c in i)Object.prototype.hasOwnProperty.call(i,c)&&o.indexOf(c)<0&&(a[c]=i[c]);if(i!=null&&typeof Object.getOwnPropertySymbols=="function")for(var _=0,c=Object.getOwnPropertySymbols(i);_{var{children:a}=i,c=BU(i,["children"]);let _=Object.assign(Object.assign({},c),{marginLeft:c.marginLeft||c.marginX||c.margin||0,marginRight:c.marginRight||c.marginX||c.margin||0,marginTop:c.marginTop||c.marginY||c.margin||0,marginBottom:c.marginBottom||c.marginY||c.margin||0,paddingLeft:c.paddingLeft||c.paddingX||c.padding||0,paddingRight:c.paddingRight||c.paddingX||c.padding||0,paddingTop:c.paddingTop||c.paddingY||c.padding||0,paddingBottom:c.paddingBottom||c.paddingY||c.padding||0});return Rx.default.createElement("ink-box",{ref:o,style:_},a)});Yw.displayName="Box";Yw.defaultProps={flexDirection:"row",flexGrow:0,flexShrink:1};rc.default=Yw});var Qw=Ke(Dg=>{"use strict";var Kw=Dg&&Dg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Dg,"__esModule",{value:!0});var UU=Kw(Mi()),em=Kw(y4()),Ax=Kw(Mw()),Xw=({color:i,backgroundColor:o,dimColor:a,bold:c,italic:_,underline:t,strikethrough:M,inverse:N,wrap:O,children:T})=>{if(T==null)return null;let B=H=>(a&&(H=em.default.dim(H)),i&&(H=Ax.default(H,i,"foreground")),o&&(H=Ax.default(H,o,"background")),c&&(H=em.default.bold(H)),_&&(H=em.default.italic(H)),t&&(H=em.default.underline(H)),M&&(H=em.default.strikethrough(H)),N&&(H=em.default.inverse(H)),H);return UU.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row",textWrap:O},internal_transform:B},T)};Xw.displayName="Text";Xw.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:"wrap"};Dg.default=Xw});var Lx=Ke(ic=>{"use strict";var jU=ic&&ic.__createBinding||(Object.create?function(i,o,a,c){c===void 0&&(c=a),Object.defineProperty(i,c,{enumerable:!0,get:function(){return o[a]}})}:function(i,o,a,c){c===void 0&&(c=a),i[c]=o[a]}),zU=ic&&ic.__setModuleDefault||(Object.create?function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}:function(i,o){i.default=o}),HU=ic&&ic.__importStar||function(i){if(i&&i.__esModule)return i;var o={};if(i!=null)for(var a in i)a!=="default"&&Object.hasOwnProperty.call(i,a)&&jU(o,i,a);return zU(o,i),o},wg=ic&&ic.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(ic,"__esModule",{value:!0});var Ox=HU(require("fs")),Q0=wg(Mi()),Mx=wg(wx()),qU=wg(xx()),$1=wg(D4()),Hc=wg(Qw()),kx=new Mx.default({cwd:process.cwd(),internals:Mx.default.nodeInternals()}),WU=({error:i})=>{let o=i.stack?i.stack.split(` -`).slice(1):void 0,a=o?kx.parseLine(o[0]):void 0,c,_=0;if((a==null?void 0:a.file)&&(a==null?void 0:a.line)&&Ox.existsSync(a.file)){let t=Ox.readFileSync(a.file,"utf8");if(c=qU.default(t,a.line),c)for(let{line:M}of c)_=Math.max(_,String(M).length)}return Q0.default.createElement($1.default,{flexDirection:"column",padding:1},Q0.default.createElement($1.default,null,Q0.default.createElement(Hc.default,{backgroundColor:"red",color:"white"}," ","ERROR"," "),Q0.default.createElement(Hc.default,null," ",i.message)),a&&Q0.default.createElement($1.default,{marginTop:1},Q0.default.createElement(Hc.default,{dimColor:!0},a.file,":",a.line,":",a.column)),a&&c&&Q0.default.createElement($1.default,{marginTop:1,flexDirection:"column"},c.map(({line:t,value:M})=>Q0.default.createElement($1.default,{key:t},Q0.default.createElement($1.default,{width:_+1},Q0.default.createElement(Hc.default,{dimColor:t!==a.line,backgroundColor:t===a.line?"red":void 0,color:t===a.line?"white":void 0},String(t).padStart(_," "),":")),Q0.default.createElement(Hc.default,{key:t,backgroundColor:t===a.line?"red":void 0,color:t===a.line?"white":void 0}," "+M)))),i.stack&&Q0.default.createElement($1.default,{marginTop:1,flexDirection:"column"},i.stack.split(` -`).slice(1).map(t=>{let M=kx.parseLine(t);return M?Q0.default.createElement($1.default,{key:t},Q0.default.createElement(Hc.default,{dimColor:!0},"- "),Q0.default.createElement(Hc.default,{dimColor:!0,bold:!0},M.function),Q0.default.createElement(Hc.default,{dimColor:!0,color:"gray"}," ","(",M.file,":",M.line,":",M.column,")")):Q0.default.createElement($1.default,{key:t},Q0.default.createElement(Hc.default,{dimColor:!0},"- "),Q0.default.createElement(Hc.default,{dimColor:!0,bold:!0},t))})))};ic.default=WU});var Fx=Ke(uc=>{"use strict";var VU=uc&&uc.__createBinding||(Object.create?function(i,o,a,c){c===void 0&&(c=a),Object.defineProperty(i,c,{enumerable:!0,get:function(){return o[a]}})}:function(i,o,a,c){c===void 0&&(c=a),i[c]=o[a]}),GU=uc&&uc.__setModuleDefault||(Object.create?function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}:function(i,o){i.default=o}),YU=uc&&uc.__importStar||function(i){if(i&&i.__esModule)return i;var o={};if(i!=null)for(var a in i)a!=="default"&&Object.hasOwnProperty.call(i,a)&&VU(o,i,a);return GU(o,i),o},uh=uc&&uc.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(uc,"__esModule",{value:!0});var oh=YU(Mi()),Nx=uh(SD()),KU=uh(Uw()),XU=uh(zw()),QU=uh(qw()),JU=uh(Vw()),ZU=uh(_4()),$U=uh(Lx()),ej=" ",tj="",nj="",Jw=class extends oh.PureComponent{constructor(){super(...arguments);this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=o=>{let{stdin:a}=this.props;if(!this.isRawModeSupported())throw a===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default. -Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink. -Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(a.setEncoding("utf8"),o){this.rawModeEnabledCount===0&&(a.addListener("data",this.handleInput),a.resume(),a.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount==0&&(a.setRawMode(!1),a.removeListener("data",this.handleInput),a.pause())},this.handleInput=o=>{o===""&&this.props.exitOnCtrlC&&this.handleExit(),o===nj&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(o===ej&&this.focusNext(),o===tj&&this.focusPrevious())},this.handleExit=o=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(o)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focusNext=()=>{this.setState(o=>{let a=o.focusables[0].id;return{activeFocusId:this.findNextFocusable(o)||a}})},this.focusPrevious=()=>{this.setState(o=>{let a=o.focusables[o.focusables.length-1].id;return{activeFocusId:this.findPreviousFocusable(o)||a}})},this.addFocusable=(o,{autoFocus:a})=>{this.setState(c=>{let _=c.activeFocusId;return!_&&a&&(_=o),{activeFocusId:_,focusables:[...c.focusables,{id:o,isActive:!0}]}})},this.removeFocusable=o=>{this.setState(a=>({activeFocusId:a.activeFocusId===o?void 0:a.activeFocusId,focusables:a.focusables.filter(c=>c.id!==o)}))},this.activateFocusable=o=>{this.setState(a=>({focusables:a.focusables.map(c=>c.id!==o?c:{id:o,isActive:!0})}))},this.deactivateFocusable=o=>{this.setState(a=>({activeFocusId:a.activeFocusId===o?void 0:a.activeFocusId,focusables:a.focusables.map(c=>c.id!==o?c:{id:o,isActive:!1})}))},this.findNextFocusable=o=>{let a=o.focusables.findIndex(c=>c.id===o.activeFocusId);for(let c=a+1;c{let a=o.focusables.findIndex(c=>c.id===o.activeFocusId);for(let c=a-1;c>=0;c--)if(o.focusables[c].isActive)return o.focusables[c].id}}static getDerivedStateFromError(o){return{error:o}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return oh.default.createElement(KU.default.Provider,{value:{exit:this.handleExit}},oh.default.createElement(XU.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},oh.default.createElement(QU.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},oh.default.createElement(JU.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},oh.default.createElement(ZU.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious}},this.state.error?oh.default.createElement($U.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){Nx.default.hide(this.props.stdout)}componentWillUnmount(){Nx.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(o){this.handleExit(o)}};uc.default=Jw;Jw.displayName="InternalApp"});var Bx=Ke(oc=>{"use strict";var rj=oc&&oc.__createBinding||(Object.create?function(i,o,a,c){c===void 0&&(c=a),Object.defineProperty(i,c,{enumerable:!0,get:function(){return o[a]}})}:function(i,o,a,c){c===void 0&&(c=a),i[c]=o[a]}),ij=oc&&oc.__setModuleDefault||(Object.create?function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}:function(i,o){i.default=o}),uj=oc&&oc.__importStar||function(i){if(i&&i.__esModule)return i;var o={};if(i!=null)for(var a in i)a!=="default"&&Object.hasOwnProperty.call(i,a)&&rj(o,i,a);return ij(o,i),o},lc=oc&&oc.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(oc,"__esModule",{value:!0});var oj=lc(Mi()),Px=kS(),lj=lc(GS()),sj=lc(yD()),aj=lc($S()),fj=lc(tT()),w4=lc(v6()),cj=lc(lx()),dj=lc(wD()),pj=lc(cx()),hj=uj(iw()),vj=lc(bw()),mj=lc(Fx()),tm=process.env.CI==="false"?!1:aj.default,Ix=()=>{},bx=class{constructor(o){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:a,outputHeight:c,staticOutput:_}=cj.default(this.rootNode,this.options.stdout.columns||80),t=_&&_!==` -`;if(this.options.debug){t&&(this.fullStaticOutput+=_),this.options.stdout.write(this.fullStaticOutput+a);return}if(tm){t&&this.options.stdout.write(_),this.lastOutput=a;return}if(t&&(this.fullStaticOutput+=_),c>=this.options.stdout.rows){this.options.stdout.write(sj.default.clearTerminal+this.fullStaticOutput+a),this.lastOutput=a;return}t&&(this.log.clear(),this.options.stdout.write(_),this.log(a)),!t&&a!==this.lastOutput&&this.throttledLog(a),this.lastOutput=a},fj.default(this),this.options=o,this.rootNode=hj.createNode("ink-root"),this.rootNode.onRender=o.debug?this.onRender:Px.throttle(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=lj.default.create(o.stdout),this.throttledLog=o.debug?this.log:Px.throttle(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput="",this.fullStaticOutput="",this.container=w4.default.createContainer(this.rootNode,!1,!1),this.unsubscribeExit=dj.default(this.unmount,{alwaysLast:!1}),process.env.DEV==="true"&&w4.default.injectIntoDevTools({bundleType:0,version:"16.13.1",rendererPackageName:"ink"}),o.patchConsole&&this.patchConsole(),tm||(o.stdout.on("resize",this.onRender),this.unsubscribeResize=()=>{o.stdout.off("resize",this.onRender)})}render(o){let a=oj.default.createElement(mj.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},o);w4.default.updateContainer(a,this.container,null,Ix)}writeToStdout(o){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(o+this.fullStaticOutput+this.lastOutput);return}if(tm){this.options.stdout.write(o);return}this.log.clear(),this.options.stdout.write(o),this.log(this.lastOutput)}}writeToStderr(o){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(o),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(tm){this.options.stderr.write(o);return}this.log.clear(),this.options.stderr.write(o),this.log(this.lastOutput)}}unmount(o){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),tm?this.options.stdout.write(this.lastOutput+` -`):this.options.debug||this.log.done(),this.isUnmounted=!0,w4.default.updateContainer(null,this.container,null,Ix),vj.default.delete(this.options.stdout),o instanceof Error?this.rejectExitPromise(o):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((o,a)=>{this.resolveExitPromise=o,this.rejectExitPromise=a})),this.exitPromise}clear(){!tm&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=pj.default((o,a)=>{o==="stdout"&&this.writeToStdout(a),o==="stderr"&&(a.startsWith("The above error occurred")||this.writeToStderr(a))}))}};oc.default=bx});var jx=Ke(Sg=>{"use strict";var Ux=Sg&&Sg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Sg,"__esModule",{value:!0});var yj=Ux(Bx()),S4=Ux(bw()),gj=require("stream"),Dj=(i,o)=>{let a=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},_j(o)),c=Ej(a.stdout,()=>new yj.default(a));return c.render(i),{rerender:c.render,unmount:()=>c.unmount(),waitUntilExit:c.waitUntilExit,cleanup:()=>S4.default.delete(a.stdout),clear:c.clear}};Sg.default=Dj;var _j=(i={})=>i instanceof gj.Stream?{stdout:i,stdin:process.stdin}:i,Ej=(i,o)=>{let a;return S4.default.has(i)?a=S4.default.get(i):(a=o(),S4.default.set(i,a)),a}});var Hx=Ke(ed=>{"use strict";var wj=ed&&ed.__createBinding||(Object.create?function(i,o,a,c){c===void 0&&(c=a),Object.defineProperty(i,c,{enumerable:!0,get:function(){return o[a]}})}:function(i,o,a,c){c===void 0&&(c=a),i[c]=o[a]}),Sj=ed&&ed.__setModuleDefault||(Object.create?function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}:function(i,o){i.default=o}),Tj=ed&&ed.__importStar||function(i){if(i&&i.__esModule)return i;var o={};if(i!=null)for(var a in i)a!=="default"&&Object.hasOwnProperty.call(i,a)&&wj(o,i,a);return Sj(o,i),o};Object.defineProperty(ed,"__esModule",{value:!0});var Tg=Tj(Mi()),zx=i=>{let{items:o,children:a,style:c}=i,[_,t]=Tg.useState(0),M=Tg.useMemo(()=>o.slice(_),[o,_]);Tg.useLayoutEffect(()=>{t(o.length)},[o.length]);let N=M.map((T,B)=>a(T,_+B)),O=Tg.useMemo(()=>Object.assign({position:"absolute",flexDirection:"column"},c),[c]);return Tg.default.createElement("ink-box",{internal_static:!0,style:O},N)};zx.displayName="Static";ed.default=zx});var Wx=Ke(Cg=>{"use strict";var Cj=Cg&&Cg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Cg,"__esModule",{value:!0});var xj=Cj(Mi()),qx=({children:i,transform:o})=>i==null?null:xj.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row"},internal_transform:o},i);qx.displayName="Transform";Cg.default=qx});var Gx=Ke(xg=>{"use strict";var Rj=xg&&xg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(xg,"__esModule",{value:!0});var Aj=Rj(Mi()),Vx=({count:i=1})=>Aj.default.createElement("ink-text",null,` -`.repeat(i));Vx.displayName="Newline";xg.default=Vx});var Xx=Ke(Rg=>{"use strict";var Yx=Rg&&Rg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Rg,"__esModule",{value:!0});var Oj=Yx(Mi()),Mj=Yx(D4()),Kx=()=>Oj.default.createElement(Mj.default,{flexGrow:1});Kx.displayName="Spacer";Rg.default=Kx});var T4=Ke(Ag=>{"use strict";var kj=Ag&&Ag.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Ag,"__esModule",{value:!0});var Lj=Mi(),Nj=kj(zw()),Fj=()=>Lj.useContext(Nj.default);Ag.default=Fj});var Jx=Ke(Og=>{"use strict";var Pj=Og&&Og.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Og,"__esModule",{value:!0});var Qx=Mi(),Ij=Pj(T4()),bj=(i,o={})=>{let{stdin:a,setRawMode:c,internal_exitOnCtrlC:_}=Ij.default();Qx.useEffect(()=>{if(o.isActive!==!1)return c(!0),()=>{c(!1)}},[o.isActive,c]),Qx.useEffect(()=>{if(o.isActive===!1)return;let t=M=>{let N=String(M),O={upArrow:N==="",downArrow:N==="",leftArrow:N==="",rightArrow:N==="",pageDown:N==="[6~",pageUp:N==="[5~",return:N==="\r",escape:N==="",ctrl:!1,shift:!1,tab:N===" "||N==="",backspace:N==="\b",delete:N==="\x7F"||N==="[3~",meta:!1};N<=""&&!O.return&&(N=String.fromCharCode(N.charCodeAt(0)+"a".charCodeAt(0)-1),O.ctrl=!0),N.startsWith("")&&(N=N.slice(1),O.meta=!0);let T=N>="A"&&N<="Z",B=N>="\u0410"&&N<="\u042F";N.length===1&&(T||B)&&(O.shift=!0),O.tab&&N==="[Z"&&(O.shift=!0),(O.tab||O.backspace||O.delete)&&(N=""),(!(N==="c"&&O.ctrl)||!_)&&i(N,O)};return a==null||a.on("data",t),()=>{a==null||a.off("data",t)}},[o.isActive,a,_,i])};Og.default=bj});var Zx=Ke(Mg=>{"use strict";var Bj=Mg&&Mg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Mg,"__esModule",{value:!0});var Uj=Mi(),jj=Bj(Uw()),zj=()=>Uj.useContext(jj.default);Mg.default=zj});var $x=Ke(kg=>{"use strict";var Hj=kg&&kg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(kg,"__esModule",{value:!0});var qj=Mi(),Wj=Hj(qw()),Vj=()=>qj.useContext(Wj.default);kg.default=Vj});var e5=Ke(Lg=>{"use strict";var Gj=Lg&&Lg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Lg,"__esModule",{value:!0});var Yj=Mi(),Kj=Gj(Vw()),Xj=()=>Yj.useContext(Kj.default);Lg.default=Xj});var n5=Ke(Ng=>{"use strict";var t5=Ng&&Ng.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Ng,"__esModule",{value:!0});var Fg=Mi(),Qj=t5(_4()),Jj=t5(T4()),Zj=({isActive:i=!0,autoFocus:o=!1}={})=>{let{isRawModeSupported:a,setRawMode:c}=Jj.default(),{activeId:_,add:t,remove:M,activate:N,deactivate:O}=Fg.useContext(Qj.default),T=Fg.useMemo(()=>Math.random().toString().slice(2,7),[]);return Fg.useEffect(()=>(t(T,{autoFocus:o}),()=>{M(T)}),[T,o]),Fg.useEffect(()=>{i?N(T):O(T)},[i,T]),Fg.useEffect(()=>{if(!(!a||!i))return c(!0),()=>{c(!1)}},[i]),{isFocused:Boolean(T)&&_===T}};Ng.default=Zj});var r5=Ke(Pg=>{"use strict";var $j=Pg&&Pg.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(Pg,"__esModule",{value:!0});var ez=Mi(),tz=$j(_4()),nz=()=>{let i=ez.useContext(tz.default);return{enableFocus:i.enableFocus,disableFocus:i.disableFocus,focusNext:i.focusNext,focusPrevious:i.focusPrevious}};Pg.default=nz});var i5=Ke(Zw=>{"use strict";Object.defineProperty(Zw,"__esModule",{value:!0});Zw.default=i=>{var o,a,c,_;return{width:(a=(o=i.yogaNode)===null||o===void 0?void 0:o.getComputedWidth())!==null&&a!==void 0?a:0,height:(_=(c=i.yogaNode)===null||c===void 0?void 0:c.getComputedHeight())!==null&&_!==void 0?_:0}}});var sc=Ke(Kl=>{"use strict";Object.defineProperty(Kl,"__esModule",{value:!0});var rz=jx();Object.defineProperty(Kl,"render",{enumerable:!0,get:function(){return rz.default}});var iz=D4();Object.defineProperty(Kl,"Box",{enumerable:!0,get:function(){return iz.default}});var uz=Qw();Object.defineProperty(Kl,"Text",{enumerable:!0,get:function(){return uz.default}});var oz=Hx();Object.defineProperty(Kl,"Static",{enumerable:!0,get:function(){return oz.default}});var lz=Wx();Object.defineProperty(Kl,"Transform",{enumerable:!0,get:function(){return lz.default}});var sz=Gx();Object.defineProperty(Kl,"Newline",{enumerable:!0,get:function(){return sz.default}});var az=Xx();Object.defineProperty(Kl,"Spacer",{enumerable:!0,get:function(){return az.default}});var fz=Jx();Object.defineProperty(Kl,"useInput",{enumerable:!0,get:function(){return fz.default}});var cz=Zx();Object.defineProperty(Kl,"useApp",{enumerable:!0,get:function(){return cz.default}});var dz=T4();Object.defineProperty(Kl,"useStdin",{enumerable:!0,get:function(){return dz.default}});var pz=$x();Object.defineProperty(Kl,"useStdout",{enumerable:!0,get:function(){return pz.default}});var hz=e5();Object.defineProperty(Kl,"useStderr",{enumerable:!0,get:function(){return hz.default}});var vz=n5();Object.defineProperty(Kl,"useFocus",{enumerable:!0,get:function(){return vz.default}});var mz=r5();Object.defineProperty(Kl,"useFocusManager",{enumerable:!0,get:function(){return mz.default}});var yz=i5();Object.defineProperty(Kl,"measureElement",{enumerable:!0,get:function(){return yz.default}})});var h5=Ke(Ig=>{"use strict";Object.defineProperty(Ig,"__esModule",{value:!0});Ig.UncontrolledTextInput=void 0;var c5=Mi(),t3=Mi(),d5=sc(),ah=y4(),p5=({value:i,placeholder:o="",focus:a=!0,mask:c,highlightPastedText:_=!1,showCursor:t=!0,onChange:M,onSubmit:N})=>{let[{cursorOffset:O,cursorWidth:T},B]=t3.useState({cursorOffset:(i||"").length,cursorWidth:0});t3.useEffect(()=>{B(pe=>{if(!a||!t)return pe;let ge=i||"";return pe.cursorOffset>ge.length-1?{cursorOffset:ge.length,cursorWidth:0}:pe})},[i,a,t]);let H=_?T:0,q=c?c.repeat(i.length):i,ne=q,m=o?ah.grey(o):void 0;if(t&&a){m=o.length>0?ah.inverse(o[0])+ah.grey(o.slice(1)):ah.inverse(" "),ne=q.length>0?"":ah.inverse(" ");let pe=0;for(let ge of q)pe>=O-H&&pe<=O?ne+=ah.inverse(ge):ne+=ge,pe++;q.length>0&&O===q.length&&(ne+=ah.inverse(" "))}return d5.useInput((pe,ge)=>{if(ge.upArrow||ge.downArrow||ge.ctrl&&pe==="c"||ge.tab||ge.shift&&ge.tab)return;if(ge.return){N&&N(i);return}let ve=O,ue=i,_e=0;ge.leftArrow?t&&ve--:ge.rightArrow?t&&ve++:ge.backspace||ge.delete?O>0&&(ue=i.slice(0,O-1)+i.slice(O,i.length),ve--):(ue=i.slice(0,O)+pe+i.slice(O,i.length),ve+=pe.length,pe.length>1&&(_e=pe.length)),O<0&&(ve=0),O>i.length&&(ve=i.length),B({cursorOffset:ve,cursorWidth:_e}),ue!==i&&M(ue)},{isActive:a}),c5.createElement(d5.Text,null,o?q.length>0?ne:m:ne)};Ig.default=p5;Ig.UncontrolledTextInput=i=>{let[o,a]=t3.useState("");return c5.createElement(p5,Object.assign({},i,{value:o,onChange:a}))}});var m5=Ke(N4=>{"use strict";Object.defineProperty(N4,"__esModule",{value:!0});function bg(i){let o=[...i.caches],a=o.shift();return a===void 0?v5():{get(c,_,t={miss:()=>Promise.resolve()}){return a.get(c,_,t).catch(()=>bg({caches:o}).get(c,_,t))},set(c,_){return a.set(c,_).catch(()=>bg({caches:o}).set(c,_))},delete(c){return a.delete(c).catch(()=>bg({caches:o}).delete(c))},clear(){return a.clear().catch(()=>bg({caches:o}).clear())}}}function v5(){return{get(i,o,a={miss:()=>Promise.resolve()}){return o().then(_=>Promise.all([_,a.miss(_)])).then(([_])=>_)},set(i,o){return Promise.resolve(o)},delete(i){return Promise.resolve()},clear(){return Promise.resolve()}}}N4.createFallbackableCache=bg;N4.createNullCache=v5});var g5=Ke((jG,y5)=>{y5.exports=m5()});var _5=Ke(n3=>{"use strict";Object.defineProperty(n3,"__esModule",{value:!0});function gz(i={serializable:!0}){let o={};return{get(a,c,_={miss:()=>Promise.resolve()}){let t=JSON.stringify(a);if(t in o)return Promise.resolve(i.serializable?JSON.parse(o[t]):o[t]);let M=c(),N=_&&_.miss||(()=>Promise.resolve());return M.then(O=>N(O)).then(()=>M)},set(a,c){return o[JSON.stringify(a)]=i.serializable?JSON.stringify(c):c,Promise.resolve(c)},delete(a){return delete o[JSON.stringify(a)],Promise.resolve()},clear(){return o={},Promise.resolve()}}}n3.createInMemoryCache=gz});var D5=Ke((HG,E5)=>{E5.exports=_5()});var S5=Ke(ac=>{"use strict";Object.defineProperty(ac,"__esModule",{value:!0});function _z(i,o,a){let c={"x-algolia-api-key":a,"x-algolia-application-id":o};return{headers(){return i===r3.WithinHeaders?c:{}},queryParameters(){return i===r3.WithinQueryParameters?c:{}}}}function Ez(i){let o=0,a=()=>(o++,new Promise(c=>{setTimeout(()=>{c(i(a))},Math.min(100*o,1e3))}));return i(a)}function w5(i,o=(a,c)=>Promise.resolve()){return Object.assign(i,{wait(a){return w5(i.then(c=>Promise.all([o(c,a),c])).then(c=>c[1]))}})}function Dz(i){let o=i.length-1;for(o;o>0;o--){let a=Math.floor(Math.random()*(o+1)),c=i[o];i[o]=i[a],i[a]=c}return i}function wz(i,o){return Object.keys(o!==void 0?o:{}).forEach(a=>{i[a]=o[a](i)}),i}function Sz(i,...o){let a=0;return i.replace(/%s/g,()=>encodeURIComponent(o[a++]))}var Tz="4.2.0",Cz=i=>()=>i.transporter.requester.destroy(),r3={WithinQueryParameters:0,WithinHeaders:1};ac.AuthMode=r3;ac.addMethods=wz;ac.createAuth=_z;ac.createRetryablePromise=Ez;ac.createWaitablePromise=w5;ac.destroy=Cz;ac.encode=Sz;ac.shuffle=Dz;ac.version=Tz});var Bg=Ke((WG,T5)=>{T5.exports=S5()});var C5=Ke(i3=>{"use strict";Object.defineProperty(i3,"__esModule",{value:!0});var xz={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};i3.MethodEnum=xz});var Ug=Ke((GG,x5)=>{x5.exports=C5()});var z5=Ke(Go=>{"use strict";Object.defineProperty(Go,"__esModule",{value:!0});var R5=Ug();function u3(i,o){let a=i||{},c=a.data||{};return Object.keys(a).forEach(_=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(_)===-1&&(c[_]=a[_])}),{data:Object.entries(c).length>0?c:void 0,timeout:a.timeout||o,headers:a.headers||{},queryParameters:a.queryParameters||{},cacheable:a.cacheable}}var F4={Read:1,Write:2,Any:3},nm={Up:1,Down:2,Timeouted:3},A5=2*60*1e3;function o3(i,o=nm.Up){return Zr(qt({},i),{status:o,lastUpdate:Date.now()})}function O5(i){return i.status===nm.Up||Date.now()-i.lastUpdate>A5}function M5(i){return i.status===nm.Timeouted&&Date.now()-i.lastUpdate<=A5}function l3(i){return{protocol:i.protocol||"https",url:i.url,accept:i.accept||F4.Any}}function Rz(i,o){return Promise.all(o.map(a=>i.get(a,()=>Promise.resolve(o3(a))))).then(a=>{let c=a.filter(N=>O5(N)),_=a.filter(N=>M5(N)),t=[...c,..._],M=t.length>0?t.map(N=>l3(N)):o;return{getTimeout(N,O){return(_.length===0&&N===0?1:_.length+3+N)*O},statelessHosts:M}})}var Az=({isTimedOut:i,status:o})=>!i&&~~o==0,Oz=i=>{let o=i.status;return i.isTimedOut||Az(i)||~~(o/100)!=2&&~~(o/100)!=4},Mz=({status:i})=>~~(i/100)==2,kz=(i,o)=>Oz(i)?o.onRetry(i):Mz(i)?o.onSucess(i):o.onFail(i);function b5(i,o,a,c){let _=[],t=F5(a,c),M=P5(i,c),N=a.method,O=a.method!==R5.MethodEnum.Get?{}:qt(qt({},a.data),c.data),T=qt(qt(qt({"x-algolia-agent":i.userAgent.value},i.queryParameters),O),c.queryParameters),B=0,H=(q,ne)=>{let m=q.pop();if(m===void 0)throw I5(s3(_));let pe={data:t,headers:M,method:N,url:N5(m,a.path,T),connectTimeout:ne(B,i.timeouts.connect),responseTimeout:ne(B,c.timeout)},ge=ue=>{let _e={request:pe,response:ue,host:m,triesLeft:q.length};return _.push(_e),_e},ve={onSucess:ue=>k5(ue),onRetry(ue){let _e=ge(ue);return ue.isTimedOut&&B++,Promise.all([i.logger.info("Retryable failure",a3(_e)),i.hostsCache.set(m,o3(m,ue.isTimedOut?nm.Timeouted:nm.Down))]).then(()=>H(q,ne))},onFail(ue){throw ge(ue),L5(ue,s3(_))}};return i.requester.send(pe).then(ue=>kz(ue,ve))};return Rz(i.hostsCache,o).then(q=>H([...q.statelessHosts].reverse(),q.getTimeout))}function Lz(i){let{hostsCache:o,logger:a,requester:c,requestsCache:_,responsesCache:t,timeouts:M,userAgent:N,hosts:O,queryParameters:T,headers:B}=i,H={hostsCache:o,logger:a,requester:c,requestsCache:_,responsesCache:t,timeouts:M,userAgent:N,headers:B,queryParameters:T,hosts:O.map(q=>l3(q)),read(q,ne){let m=u3(ne,H.timeouts.read),pe=()=>b5(H,H.hosts.filter(ue=>(ue.accept&F4.Read)!=0),q,m);if((m.cacheable!==void 0?m.cacheable:q.cacheable)!==!0)return pe();let ve={request:q,mappedRequestOptions:m,transporter:{queryParameters:H.queryParameters,headers:H.headers}};return H.responsesCache.get(ve,()=>H.requestsCache.get(ve,()=>H.requestsCache.set(ve,pe()).then(ue=>Promise.all([H.requestsCache.delete(ve),ue]),ue=>Promise.all([H.requestsCache.delete(ve),Promise.reject(ue)])).then(([ue,_e])=>_e)),{miss:ue=>H.responsesCache.set(ve,ue)})},write(q,ne){return b5(H,H.hosts.filter(m=>(m.accept&F4.Write)!=0),q,u3(ne,H.timeouts.write))}};return H}function Nz(i){let o={value:`Algolia for JavaScript (${i})`,add(a){let c=`; ${a.segment}${a.version!==void 0?` (${a.version})`:""}`;return o.value.indexOf(c)===-1&&(o.value=`${o.value}${c}`),o}};return o}function k5(i){try{return JSON.parse(i.content)}catch(o){throw B5(o.message,i)}}function L5({content:i,status:o},a){let c=i;try{c=JSON.parse(i).message}catch(_){}return U5(c,o,a)}function Fz(i,...o){let a=0;return i.replace(/%s/g,()=>encodeURIComponent(o[a++]))}function N5(i,o,a){let c=j5(a),_=`${i.protocol}://${i.url}/${o.charAt(0)==="/"?o.substr(1):o}`;return c.length&&(_+=`?${c}`),_}function j5(i){let o=a=>Object.prototype.toString.call(a)==="[object Object]"||Object.prototype.toString.call(a)==="[object Array]";return Object.keys(i).map(a=>Fz("%s=%s",a,o(i[a])?JSON.stringify(i[a]):i[a])).join("&")}function F5(i,o){if(i.method===R5.MethodEnum.Get||i.data===void 0&&o.data===void 0)return;let a=Array.isArray(i.data)?i.data:qt(qt({},i.data),o.data);return JSON.stringify(a)}function P5(i,o){let a=qt(qt({},i.headers),o.headers),c={};return Object.keys(a).forEach(_=>{let t=a[_];c[_.toLowerCase()]=t}),c}function s3(i){return i.map(o=>a3(o))}function a3(i){let o=i.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return Zr(qt({},i),{request:Zr(qt({},i.request),{headers:qt(qt({},i.request.headers),o)})})}function U5(i,o,a){return{name:"ApiError",message:i,status:o,transporterStackTrace:a}}function B5(i,o){return{name:"DeserializationError",message:i,response:o}}function I5(i){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:i}}Go.CallEnum=F4;Go.HostStatusEnum=nm;Go.createApiError=U5;Go.createDeserializationError=B5;Go.createMappedRequestOptions=u3;Go.createRetryError=I5;Go.createStatefulHost=o3;Go.createStatelessHost=l3;Go.createTransporter=Lz;Go.createUserAgent=Nz;Go.deserializeFailure=L5;Go.deserializeSuccess=k5;Go.isStatefulHostTimeouted=M5;Go.isStatefulHostUp=O5;Go.serializeData=F5;Go.serializeHeaders=P5;Go.serializeQueryParameters=j5;Go.serializeUrl=N5;Go.stackFrameWithoutCredentials=a3;Go.stackTraceWithoutCredentials=s3});var jg=Ke((KG,H5)=>{H5.exports=z5()});var q5=Ke(_2=>{"use strict";Object.defineProperty(_2,"__esModule",{value:!0});var rm=Bg(),Pz=jg(),zg=Ug(),Iz=i=>{let o=i.region||"us",a=rm.createAuth(rm.AuthMode.WithinHeaders,i.appId,i.apiKey),c=Pz.createTransporter(Zr(qt({hosts:[{url:`analytics.${o}.algolia.com`}]},i),{headers:qt(Zr(qt({},a.headers()),{"content-type":"application/json"}),i.headers),queryParameters:qt(qt({},a.queryParameters()),i.queryParameters)})),_=i.appId;return rm.addMethods({appId:_,transporter:c},i.methods)},bz=i=>(o,a)=>i.transporter.write({method:zg.MethodEnum.Post,path:"2/abtests",data:o},a),Bz=i=>(o,a)=>i.transporter.write({method:zg.MethodEnum.Delete,path:rm.encode("2/abtests/%s",o)},a),Uz=i=>(o,a)=>i.transporter.read({method:zg.MethodEnum.Get,path:rm.encode("2/abtests/%s",o)},a),jz=i=>o=>i.transporter.read({method:zg.MethodEnum.Get,path:"2/abtests"},o),zz=i=>(o,a)=>i.transporter.write({method:zg.MethodEnum.Post,path:rm.encode("2/abtests/%s/stop",o)},a);_2.addABTest=bz;_2.createAnalyticsClient=Iz;_2.deleteABTest=Bz;_2.getABTest=Uz;_2.getABTests=jz;_2.stopABTest=zz});var V5=Ke((QG,W5)=>{W5.exports=q5()});var Y5=Ke(Hg=>{"use strict";Object.defineProperty(Hg,"__esModule",{value:!0});var f3=Bg(),Hz=jg(),G5=Ug(),qz=i=>{let o=i.region||"us",a=f3.createAuth(f3.AuthMode.WithinHeaders,i.appId,i.apiKey),c=Hz.createTransporter(Zr(qt({hosts:[{url:`recommendation.${o}.algolia.com`}]},i),{headers:qt(Zr(qt({},a.headers()),{"content-type":"application/json"}),i.headers),queryParameters:qt(qt({},a.queryParameters()),i.queryParameters)}));return f3.addMethods({appId:i.appId,transporter:c},i.methods)},Wz=i=>o=>i.transporter.read({method:G5.MethodEnum.Get,path:"1/strategies/personalization"},o),Vz=i=>(o,a)=>i.transporter.write({method:G5.MethodEnum.Post,path:"1/strategies/personalization",data:o},a);Hg.createRecommendationClient=qz;Hg.getPersonalizationStrategy=Wz;Hg.setPersonalizationStrategy=Vz});var X5=Ke((ZG,K5)=>{K5.exports=Y5()});var s9=Ke(tn=>{"use strict";Object.defineProperty(tn,"__esModule",{value:!0});var Nn=Bg(),ia=jg(),Ur=Ug(),Gz=require("crypto");function P4(i){let o=a=>i.request(a).then(c=>{if(i.batch!==void 0&&i.batch(c.hits),!i.shouldStop(c))return c.cursor?o({cursor:c.cursor}):o({page:(a.page||0)+1})});return o({})}var Yz=i=>{let o=i.appId,a=Nn.createAuth(i.authMode!==void 0?i.authMode:Nn.AuthMode.WithinHeaders,o,i.apiKey),c=ia.createTransporter(Zr(qt({hosts:[{url:`${o}-dsn.algolia.net`,accept:ia.CallEnum.Read},{url:`${o}.algolia.net`,accept:ia.CallEnum.Write}].concat(Nn.shuffle([{url:`${o}-1.algolianet.com`},{url:`${o}-2.algolianet.com`},{url:`${o}-3.algolianet.com`}]))},i),{headers:qt(Zr(qt({},a.headers()),{"content-type":"application/x-www-form-urlencoded"}),i.headers),queryParameters:qt(qt({},a.queryParameters()),i.queryParameters)})),_={transporter:c,appId:o,addAlgoliaAgent(t,M){c.userAgent.add({segment:t,version:M})},clearCache(){return Promise.all([c.requestsCache.clear(),c.responsesCache.clear()]).then(()=>{})}};return Nn.addMethods(_,i.methods)};function Q5(){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 J5(){return{name:"ObjectNotFoundError",message:"Object not found."}}function Z5(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Kz=i=>(o,a)=>{let N=a||{},{queryParameters:c}=N,_=wl(N,["queryParameters"]),t=qt({acl:o},c!==void 0?{queryParameters:c}:{}),M=(O,T)=>Nn.createRetryablePromise(B=>qg(i)(O.key,T).catch(H=>{if(H.status!==404)throw H;return B()}));return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:"1/keys",data:t},_),M)},Xz=i=>(o,a,c)=>{let _=ia.createMappedRequestOptions(c);return _.queryParameters["X-Algolia-User-ID"]=o,i.transporter.write({method:Ur.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:a}},_)},Qz=i=>(o,a,c)=>i.transporter.write({method:Ur.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:o,cluster:a}},c),I4=i=>(o,a,c)=>{let _=(t,M)=>Wg(i)(o,{methods:{waitTask:x0}}).waitTask(t.taskID,M);return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/operation",o),data:{operation:"copy",destination:a}},c),_)},Jz=i=>(o,a,c)=>I4(i)(o,a,Zr(qt({},c),{scope:[b4.Rules]})),Zz=i=>(o,a,c)=>I4(i)(o,a,Zr(qt({},c),{scope:[b4.Settings]})),$z=i=>(o,a,c)=>I4(i)(o,a,Zr(qt({},c),{scope:[b4.Synonyms]})),eH=i=>(o,a)=>{let c=(_,t)=>Nn.createRetryablePromise(M=>qg(i)(o,t).then(M).catch(N=>{if(N.status!==404)throw N}));return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Delete,path:Nn.encode("1/keys/%s",o)},a),c)},tH=()=>(i,o)=>{let a=ia.serializeQueryParameters(o),c=Gz.createHmac("sha256",i).update(a).digest("hex");return Buffer.from(c+a).toString("base64")},qg=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/keys/%s",o)},a),nH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/logs"},o),rH=()=>i=>{let o=Buffer.from(i,"base64").toString("ascii"),a=/validUntil=(\d+)/,c=o.match(a);if(c===null)throw Z5();return parseInt(c[1],10)-Math.round(new Date().getTime()/1e3)},iH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/clusters/mapping/top"},o),uH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/clusters/mapping/%s",o)},a),oH=i=>o=>{let _=o||{},{retrieveMappings:a}=_,c=wl(_,["retrieveMappings"]);return a===!0&&(c.getClusters=!0),i.transporter.read({method:Ur.MethodEnum.Get,path:"1/clusters/mapping/pending"},c)},Wg=i=>(o,a={})=>{let c={transporter:i.transporter,appId:i.appId,indexName:o};return Nn.addMethods(c,a.methods)},lH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/keys"},o),sH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/clusters"},o),aH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/indexes"},o),fH=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:"1/clusters/mapping"},o),cH=i=>(o,a,c)=>{let _=(t,M)=>Wg(i)(o,{methods:{waitTask:x0}}).waitTask(t.taskID,M);return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/operation",o),data:{operation:"move",destination:a}},c),_)},dH=i=>(o,a)=>{let c=(_,t)=>Promise.all(Object.keys(_.taskID).map(M=>Wg(i)(M,{methods:{waitTask:x0}}).waitTask(_.taskID[M],t)));return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:o}},a),c)},pH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:o}},a),hH=i=>(o,a)=>{let c=o.map(_=>Zr(qt({},_),{params:ia.serializeQueryParameters(_.params||{})}));return i.transporter.read({method:Ur.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:c},cacheable:!0},a)},vH=i=>(o,a)=>Promise.all(o.map(c=>{let N=c.params,{facetName:_,facetQuery:t}=N,M=wl(N,["facetName","facetQuery"]);return Wg(i)(c.indexName,{methods:{searchForFacetValues:$5}}).searchForFacetValues(_,t,qt(qt({},a),M))})),mH=i=>(o,a)=>{let c=ia.createMappedRequestOptions(a);return c.queryParameters["X-Algolia-User-ID"]=o,i.transporter.write({method:Ur.MethodEnum.Delete,path:"1/clusters/mapping"},c)},yH=i=>(o,a)=>{let c=(_,t)=>Nn.createRetryablePromise(M=>qg(i)(o,t).catch(N=>{if(N.status!==404)throw N;return M()}));return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/keys/%s/restore",o)},a),c)},gH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:o}},a),_H=i=>(o,a)=>{let c=Object.assign({},a),B=a||{},{queryParameters:_}=B,t=wl(B,["queryParameters"]),M=_?{queryParameters:_}:{},N=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],O=H=>Object.keys(c).filter(q=>N.indexOf(q)!==-1).every(q=>H[q]===c[q]),T=(H,q)=>Nn.createRetryablePromise(ne=>qg(i)(o,q).then(m=>O(m)?Promise.resolve():ne()));return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Put,path:Nn.encode("1/keys/%s",o),data:M},t),T)},e9=i=>(o,a)=>{let c=(_,t)=>x0(i)(_.taskID,t);return Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/batch",i.indexName),data:{requests:o}},a),c)},EH=i=>o=>P4(Zr(qt({},o),{shouldStop:a=>a.cursor===void 0,request:a=>i.transporter.read({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/browse",i.indexName),data:a},o)})),DH=i=>o=>{let a=qt({hitsPerPage:1e3},o);return P4(Zr(qt({},a),{shouldStop:c=>c.hits.lengthZr(qt({},_),{hits:_.hits.map(t=>(delete t._highlightResult,t))}))}}))},wH=i=>o=>{let a=qt({hitsPerPage:1e3},o);return P4(Zr(qt({},a),{shouldStop:c=>c.hits.lengthZr(qt({},_),{hits:_.hits.map(t=>(delete t._highlightResult,t))}))}}))},B4=i=>(o,a,c)=>{let O=c||{},{batchSize:_}=O,t=wl(O,["batchSize"]),M={taskIDs:[],objectIDs:[]},N=(T=0)=>{let B=[],H;for(H=T;H({action:a,body:q})),t).then(q=>(M.objectIDs=M.objectIDs.concat(q.objectIDs),M.taskIDs.push(q.taskID),H++,N(H)))};return Nn.createWaitablePromise(N(),(T,B)=>Promise.all(T.taskIDs.map(H=>x0(i)(H,B))))},SH=i=>o=>Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/clear",i.indexName)},o),(a,c)=>x0(i)(a.taskID,c)),TH=i=>o=>{let t=o||{},{forwardToReplicas:a}=t,c=wl(t,["forwardToReplicas"]),_=ia.createMappedRequestOptions(c);return a&&(_.queryParameters.forwardToReplicas=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/rules/clear",i.indexName)},_),(M,N)=>x0(i)(M.taskID,N))},CH=i=>o=>{let t=o||{},{forwardToReplicas:a}=t,c=wl(t,["forwardToReplicas"]),_=ia.createMappedRequestOptions(c);return a&&(_.queryParameters.forwardToReplicas=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/synonyms/clear",i.indexName)},_),(M,N)=>x0(i)(M.taskID,N))},xH=i=>(o,a)=>Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/deleteByQuery",i.indexName),data:o},a),(c,_)=>x0(i)(c.taskID,_)),RH=i=>o=>Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Delete,path:Nn.encode("1/indexes/%s",i.indexName)},o),(a,c)=>x0(i)(a.taskID,c)),AH=i=>(o,a)=>Nn.createWaitablePromise(r9(i)([o],a).then(c=>({taskID:c.taskIDs[0]})),(c,_)=>x0(i)(c.taskID,_)),r9=i=>(o,a)=>{let c=o.map(_=>({objectID:_}));return B4(i)(c,fh.DeleteObject,a)},OH=i=>(o,a)=>{let M=a||{},{forwardToReplicas:c}=M,_=wl(M,["forwardToReplicas"]),t=ia.createMappedRequestOptions(_);return c&&(t.queryParameters.forwardToReplicas=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Delete,path:Nn.encode("1/indexes/%s/rules/%s",i.indexName,o)},t),(N,O)=>x0(i)(N.taskID,O))},MH=i=>(o,a)=>{let M=a||{},{forwardToReplicas:c}=M,_=wl(M,["forwardToReplicas"]),t=ia.createMappedRequestOptions(_);return c&&(t.queryParameters.forwardToReplicas=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Delete,path:Nn.encode("1/indexes/%s/synonyms/%s",i.indexName,o)},t),(N,O)=>x0(i)(N.taskID,O))},kH=i=>o=>i9(i)(o).then(()=>!0).catch(a=>{if(a.status!==404)throw a;return!1}),LH=i=>(o,a)=>{let O=a||{},{query:c,paginate:_}=O,t=wl(O,["query","paginate"]),M=0,N=()=>u9(i)(c||"",Zr(qt({},t),{page:M})).then(T=>{for(let[B,H]of Object.entries(T.hits))if(o(H))return{object:H,position:parseInt(B,10),page:M};if(M++,_===!1||M>=T.nbPages)throw J5();return N()});return N()},NH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/indexes/%s/%s",i.indexName,o)},a),FH=()=>(i,o)=>{for(let[a,c]of Object.entries(i.hits))if(c.objectID===o)return parseInt(a,10);return-1},PH=i=>(o,a)=>{let M=a||{},{attributesToRetrieve:c}=M,_=wl(M,["attributesToRetrieve"]),t=o.map(N=>qt({indexName:i.indexName,objectID:N},c?{attributesToRetrieve:c}:{}));return i.transporter.read({method:Ur.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:t}},_)},IH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/indexes/%s/rules/%s",i.indexName,o)},a),i9=i=>o=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/indexes/%s/settings",i.indexName),data:{getVersion:2}},o),bH=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/indexes/%s/synonyms/%s",i.indexName,o)},a),o9=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Get,path:Nn.encode("1/indexes/%s/task/%s",i.indexName,o.toString())},a),BH=i=>(o,a)=>Nn.createWaitablePromise(l9(i)([o],a).then(c=>({objectID:c.objectIDs[0],taskID:c.taskIDs[0]})),(c,_)=>x0(i)(c.taskID,_)),l9=i=>(o,a)=>{let M=a||{},{createIfNotExists:c}=M,_=wl(M,["createIfNotExists"]),t=c?fh.PartialUpdateObject:fh.PartialUpdateObjectNoCreate;return B4(i)(o,t,_)},UH=i=>(o,a)=>{let m=a||{},{safe:c,autoGenerateObjectIDIfNotExist:_,batchSize:t}=m,M=wl(m,["safe","autoGenerateObjectIDIfNotExist","batchSize"]),N=(pe,ge,ve,ue)=>Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/operation",pe),data:{operation:ve,destination:ge}},ue),(_e,ce)=>x0(i)(_e.taskID,ce)),O=Math.random().toString(36).substring(7),T=`${i.indexName}_tmp_${O}`,B=c3({appId:i.appId,transporter:i.transporter,indexName:T}),H=[],q=N(i.indexName,T,"copy",Zr(qt({},M),{scope:["settings","synonyms","rules"]}));H.push(q);let ne=(c?q.wait(M):q).then(()=>{let pe=B(o,Zr(qt({},M),{autoGenerateObjectIDIfNotExist:_,batchSize:t}));return H.push(pe),c?pe.wait(M):pe}).then(()=>{let pe=N(T,i.indexName,"move",M);return H.push(pe),c?pe.wait(M):pe}).then(()=>Promise.all(H)).then(([pe,ge,ve])=>({objectIDs:ge.objectIDs,taskIDs:[pe.taskID,...ge.taskIDs,ve.taskID]}));return Nn.createWaitablePromise(ne,(pe,ge)=>Promise.all(H.map(ve=>ve.wait(ge))))},jH=i=>(o,a)=>d3(i)(o,Zr(qt({},a),{clearExistingRules:!0})),zH=i=>(o,a)=>p3(i)(o,Zr(qt({},a),{replaceExistingSynonyms:!0})),HH=i=>(o,a)=>Nn.createWaitablePromise(c3(i)([o],a).then(c=>({objectID:c.objectIDs[0],taskID:c.taskIDs[0]})),(c,_)=>x0(i)(c.taskID,_)),c3=i=>(o,a)=>{let M=a||{},{autoGenerateObjectIDIfNotExist:c}=M,_=wl(M,["autoGenerateObjectIDIfNotExist"]),t=c?fh.AddObject:fh.UpdateObject;if(t===fh.UpdateObject){for(let N of o)if(N.objectID===void 0)return Nn.createWaitablePromise(Promise.reject(Q5()))}return B4(i)(o,t,_)},qH=i=>(o,a)=>d3(i)([o],a),d3=i=>(o,a)=>{let N=a||{},{forwardToReplicas:c,clearExistingRules:_}=N,t=wl(N,["forwardToReplicas","clearExistingRules"]),M=ia.createMappedRequestOptions(t);return c&&(M.queryParameters.forwardToReplicas=1),_&&(M.queryParameters.clearExistingRules=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/rules/batch",i.indexName),data:o},M),(O,T)=>x0(i)(O.taskID,T))},WH=i=>(o,a)=>p3(i)([o],a),p3=i=>(o,a)=>{let N=a||{},{forwardToReplicas:c,replaceExistingSynonyms:_}=N,t=wl(N,["forwardToReplicas","replaceExistingSynonyms"]),M=ia.createMappedRequestOptions(t);return c&&(M.queryParameters.forwardToReplicas=1),_&&(M.queryParameters.replaceExistingSynonyms=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/synonyms/batch",i.indexName),data:o},M),(O,T)=>x0(i)(O.taskID,T))},u9=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/query",i.indexName),data:{query:o},cacheable:!0},a),$5=i=>(o,a,c)=>i.transporter.read({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/facets/%s/query",i.indexName,o),data:{facetQuery:a},cacheable:!0},c),t9=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/rules/search",i.indexName),data:{query:o}},a),n9=i=>(o,a)=>i.transporter.read({method:Ur.MethodEnum.Post,path:Nn.encode("1/indexes/%s/synonyms/search",i.indexName),data:{query:o}},a),VH=i=>(o,a)=>{let M=a||{},{forwardToReplicas:c}=M,_=wl(M,["forwardToReplicas"]),t=ia.createMappedRequestOptions(_);return c&&(t.queryParameters.forwardToReplicas=1),Nn.createWaitablePromise(i.transporter.write({method:Ur.MethodEnum.Put,path:Nn.encode("1/indexes/%s/settings",i.indexName),data:o},t),(N,O)=>x0(i)(N.taskID,O))},x0=i=>(o,a)=>Nn.createRetryablePromise(c=>o9(i)(o,a).then(_=>_.status!=="published"?c():void 0)),GH={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"},fh={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject"},b4={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},YH={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},KH={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};tn.ApiKeyACLEnum=GH;tn.BatchActionEnum=fh;tn.ScopeEnum=b4;tn.StrategyEnum=YH;tn.SynonymEnum=KH;tn.addApiKey=Kz;tn.assignUserID=Xz;tn.assignUserIDs=Qz;tn.batch=e9;tn.browseObjects=EH;tn.browseRules=DH;tn.browseSynonyms=wH;tn.chunkedBatch=B4;tn.clearObjects=SH;tn.clearRules=TH;tn.clearSynonyms=CH;tn.copyIndex=I4;tn.copyRules=Jz;tn.copySettings=Zz;tn.copySynonyms=$z;tn.createBrowsablePromise=P4;tn.createMissingObjectIDError=Q5;tn.createObjectNotFoundError=J5;tn.createSearchClient=Yz;tn.createValidUntilNotFoundError=Z5;tn.deleteApiKey=eH;tn.deleteBy=xH;tn.deleteIndex=RH;tn.deleteObject=AH;tn.deleteObjects=r9;tn.deleteRule=OH;tn.deleteSynonym=MH;tn.exists=kH;tn.findObject=LH;tn.generateSecuredApiKey=tH;tn.getApiKey=qg;tn.getLogs=nH;tn.getObject=NH;tn.getObjectPosition=FH;tn.getObjects=PH;tn.getRule=IH;tn.getSecuredApiKeyRemainingValidity=rH;tn.getSettings=i9;tn.getSynonym=bH;tn.getTask=o9;tn.getTopUserIDs=iH;tn.getUserID=uH;tn.hasPendingMappings=oH;tn.initIndex=Wg;tn.listApiKeys=lH;tn.listClusters=sH;tn.listIndices=aH;tn.listUserIDs=fH;tn.moveIndex=cH;tn.multipleBatch=dH;tn.multipleGetObjects=pH;tn.multipleQueries=hH;tn.multipleSearchForFacetValues=vH;tn.partialUpdateObject=BH;tn.partialUpdateObjects=l9;tn.removeUserID=mH;tn.replaceAllObjects=UH;tn.replaceAllRules=jH;tn.replaceAllSynonyms=zH;tn.restoreApiKey=yH;tn.saveObject=HH;tn.saveObjects=c3;tn.saveRule=qH;tn.saveRules=d3;tn.saveSynonym=WH;tn.saveSynonyms=p3;tn.search=u9;tn.searchForFacetValues=$5;tn.searchRules=t9;tn.searchSynonyms=n9;tn.searchUserIDs=gH;tn.setSettings=VH;tn.updateApiKey=_H;tn.waitTask=x0});var f9=Ke((eY,a9)=>{a9.exports=s9()});var c9=Ke(U4=>{"use strict";Object.defineProperty(U4,"__esModule",{value:!0});function XH(){return{debug(i,o){return Promise.resolve()},info(i,o){return Promise.resolve()},error(i,o){return Promise.resolve()}}}var QH={Debug:1,Info:2,Error:3};U4.LogLevelEnum=QH;U4.createNullLogger=XH});var p9=Ke((nY,d9)=>{d9.exports=c9()});var m9=Ke(h3=>{"use strict";Object.defineProperty(h3,"__esModule",{value:!0});var h9=require("http"),v9=require("https"),JH=require("url");function ZH(){let i={keepAlive:!0},o=new h9.Agent(i),a=new v9.Agent(i);return{send(c){return new Promise(_=>{let t=JH.parse(c.url),M=t.query===null?t.pathname:`${t.pathname}?${t.query}`,N=qt({agent:t.protocol==="https:"?a:o,hostname:t.hostname,path:M,method:c.method,headers:c.headers},t.port!==void 0?{port:t.port||""}:{}),O=(t.protocol==="https:"?v9:h9).request(N,q=>{let ne="";q.on("data",m=>ne+=m),q.on("end",()=>{clearTimeout(B),clearTimeout(H),_({status:q.statusCode||0,content:ne,isTimedOut:!1})})}),T=(q,ne)=>setTimeout(()=>{O.abort(),_({status:0,content:ne,isTimedOut:!0})},q*1e3),B=T(c.connectTimeout,"Connection timeout"),H;O.on("error",q=>{clearTimeout(B),clearTimeout(H),_({status:0,content:q.message,isTimedOut:!1})}),O.once("response",()=>{clearTimeout(B),H=T(c.responseTimeout,"Socket timeout")}),c.data!==void 0&&O.write(c.data),O.end()})},destroy(){return o.destroy(),a.destroy(),Promise.resolve()}}}h3.createNodeHttpRequester=ZH});var g9=Ke((iY,y9)=>{y9.exports=m9()});var w9=Ke((uY,_9)=>{"use strict";var E9=g5(),$H=D5(),im=V5(),v3=Bg(),m3=X5(),wn=f9(),eq=p9(),tq=g9(),nq=jg();function D9(i,o,a){let c={appId:i,apiKey:o,timeouts:{connect:2,read:5,write:30},requester:tq.createNodeHttpRequester(),logger:eq.createNullLogger(),responsesCache:E9.createNullCache(),requestsCache:E9.createNullCache(),hostsCache:$H.createInMemoryCache(),userAgent:nq.createUserAgent(v3.version).add({segment:"Node.js",version:process.versions.node})};return wn.createSearchClient(Zr(qt(qt({},c),a),{methods:{search:wn.multipleQueries,searchForFacetValues:wn.multipleSearchForFacetValues,multipleBatch:wn.multipleBatch,multipleGetObjects:wn.multipleGetObjects,multipleQueries:wn.multipleQueries,copyIndex:wn.copyIndex,copySettings:wn.copySettings,copyRules:wn.copyRules,copySynonyms:wn.copySynonyms,moveIndex:wn.moveIndex,listIndices:wn.listIndices,getLogs:wn.getLogs,listClusters:wn.listClusters,multipleSearchForFacetValues:wn.multipleSearchForFacetValues,getApiKey:wn.getApiKey,addApiKey:wn.addApiKey,listApiKeys:wn.listApiKeys,updateApiKey:wn.updateApiKey,deleteApiKey:wn.deleteApiKey,restoreApiKey:wn.restoreApiKey,assignUserID:wn.assignUserID,assignUserIDs:wn.assignUserIDs,getUserID:wn.getUserID,searchUserIDs:wn.searchUserIDs,listUserIDs:wn.listUserIDs,getTopUserIDs:wn.getTopUserIDs,removeUserID:wn.removeUserID,hasPendingMappings:wn.hasPendingMappings,generateSecuredApiKey:wn.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:wn.getSecuredApiKeyRemainingValidity,destroy:v3.destroy,initIndex:_=>t=>wn.initIndex(_)(t,{methods:{batch:wn.batch,delete:wn.deleteIndex,getObject:wn.getObject,getObjects:wn.getObjects,saveObject:wn.saveObject,saveObjects:wn.saveObjects,search:wn.search,searchForFacetValues:wn.searchForFacetValues,waitTask:wn.waitTask,setSettings:wn.setSettings,getSettings:wn.getSettings,partialUpdateObject:wn.partialUpdateObject,partialUpdateObjects:wn.partialUpdateObjects,deleteObject:wn.deleteObject,deleteObjects:wn.deleteObjects,deleteBy:wn.deleteBy,clearObjects:wn.clearObjects,browseObjects:wn.browseObjects,getObjectPosition:wn.getObjectPosition,findObject:wn.findObject,exists:wn.exists,saveSynonym:wn.saveSynonym,saveSynonyms:wn.saveSynonyms,getSynonym:wn.getSynonym,searchSynonyms:wn.searchSynonyms,browseSynonyms:wn.browseSynonyms,deleteSynonym:wn.deleteSynonym,clearSynonyms:wn.clearSynonyms,replaceAllObjects:wn.replaceAllObjects,replaceAllSynonyms:wn.replaceAllSynonyms,searchRules:wn.searchRules,getRule:wn.getRule,deleteRule:wn.deleteRule,saveRule:wn.saveRule,saveRules:wn.saveRules,replaceAllRules:wn.replaceAllRules,browseRules:wn.browseRules,clearRules:wn.clearRules}}),initAnalytics:()=>_=>im.createAnalyticsClient(Zr(qt(qt({},c),_),{methods:{addABTest:im.addABTest,getABTest:im.getABTest,getABTests:im.getABTests,stopABTest:im.stopABTest,deleteABTest:im.deleteABTest}})),initRecommendation:()=>_=>m3.createRecommendationClient(Zr(qt(qt({},c),_),{methods:{getPersonalizationStrategy:m3.getPersonalizationStrategy,setPersonalizationStrategy:m3.setPersonalizationStrategy}}))}}))}D9.version=v3.version;_9.exports=D9});var T9=Ke((oY,y3)=>{var S9=w9();y3.exports=S9;y3.exports.default=S9});var nd=Ke(E3=>{"use strict";Object.defineProperty(E3,"__esModule",{value:!0});E3.default=N9;function N9(){}N9.prototype={diff:function(o,a){var c=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},_=c.callback;typeof c=="function"&&(_=c,c={}),this.options=c;var t=this;function M(pe){return _?(setTimeout(function(){_(void 0,pe)},0),!0):pe}o=this.castInput(o),a=this.castInput(a),o=this.removeEmpty(this.tokenize(o)),a=this.removeEmpty(this.tokenize(a));var N=a.length,O=o.length,T=1,B=N+O,H=[{newPos:-1,components:[]}],q=this.extractCommon(H[0],a,o,0);if(H[0].newPos+1>=N&&q+1>=O)return M([{value:this.join(a),count:a.length}]);function ne(){for(var pe=-1*T;pe<=T;pe+=2){var ge=void 0,ve=H[pe-1],ue=H[pe+1],_e=(ue?ue.newPos:0)-pe;ve&&(H[pe-1]=void 0);var ce=ve&&ve.newPos+1=N&&_e+1>=O)return M(iq(t,ge.components,a,o,t.useLongestToken));H[pe]=ge}T++}if(_)(function pe(){setTimeout(function(){if(T>B)return _();ne()||pe()},0)})();else for(;T<=B;){var m=ne();if(m)return m}},pushComponent:function(o,a,c){var _=o[o.length-1];_&&_.added===a&&_.removed===c?o[o.length-1]={count:_.count+1,added:a,removed:c}:o.push({count:1,added:a,removed:c})},extractCommon:function(o,a,c,_){for(var t=a.length,M=c.length,N=o.newPos,O=N-_,T=0;N+1ne.length?pe:ne}),T.value=i.join(B)}else T.value=i.join(a.slice(N,N+T.count));N+=T.count,T.added||(O+=T.count)}}var q=o[M-1];return M>1&&typeof q.value=="string"&&(q.added||q.removed)&&i.equals("",q.value)&&(o[M-2].value+=q.value,o.pop()),o}function uq(i){return{newPos:i.newPos,components:i.components.slice(0)}}});var P9=Ke(Kg=>{"use strict";Object.defineProperty(Kg,"__esModule",{value:!0});Kg.diffChars=oq;Kg.characterDiff=void 0;var sq=lq(nd());function lq(i){return i&&i.__esModule?i:{default:i}}var F9=new sq.default;Kg.characterDiff=F9;function oq(i,o,a){return F9.diff(i,o,a)}});var w3=Ke(D3=>{"use strict";Object.defineProperty(D3,"__esModule",{value:!0});D3.generateOptions=aq;function aq(i,o){if(typeof i=="function")o.callback=i;else if(i)for(var a in i)i.hasOwnProperty(a)&&(o[a]=i[a]);return o}});var B9=Ke(um=>{"use strict";Object.defineProperty(um,"__esModule",{value:!0});um.diffWords=fq;um.diffWordsWithSpace=cq;um.wordDiff=void 0;var pq=dq(nd()),hq=w3();function dq(i){return i&&i.__esModule?i:{default:i}}var I9=/^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/,b9=/\S/,Xg=new pq.default;um.wordDiff=Xg;Xg.equals=function(i,o){return this.options.ignoreCase&&(i=i.toLowerCase(),o=o.toLowerCase()),i===o||this.options.ignoreWhitespace&&!b9.test(i)&&!b9.test(o)};Xg.tokenize=function(i){for(var o=i.split(/(\s+|[()[\]{}'"]|\b)/),a=0;a{"use strict";Object.defineProperty(om,"__esModule",{value:!0});om.diffLines=vq;om.diffTrimmedLines=mq;om.lineDiff=void 0;var gq=yq(nd()),_q=w3();function yq(i){return i&&i.__esModule?i:{default:i}}var z4=new gq.default;om.lineDiff=z4;z4.tokenize=function(i){var o=[],a=i.split(/(\n|\r\n)/);a[a.length-1]||a.pop();for(var c=0;c{"use strict";Object.defineProperty(Qg,"__esModule",{value:!0});Qg.diffSentences=Eq;Qg.sentenceDiff=void 0;var wq=Dq(nd());function Dq(i){return i&&i.__esModule?i:{default:i}}var S3=new wq.default;Qg.sentenceDiff=S3;S3.tokenize=function(i){return i.split(/(\S.+?[.!?])(?=\s+|$)/)};function Eq(i,o,a){return S3.diff(i,o,a)}});var j9=Ke(Jg=>{"use strict";Object.defineProperty(Jg,"__esModule",{value:!0});Jg.diffCss=Sq;Jg.cssDiff=void 0;var Cq=Tq(nd());function Tq(i){return i&&i.__esModule?i:{default:i}}var T3=new Cq.default;Jg.cssDiff=T3;T3.tokenize=function(i){return i.split(/([{}:;,]|\s+)/)};function Sq(i,o,a){return T3.diff(i,o,a)}});var H9=Ke(lm=>{"use strict";Object.defineProperty(lm,"__esModule",{value:!0});lm.diffJson=xq;lm.canonicalize=q4;lm.jsonDiff=void 0;var z9=Rq(nd()),Aq=H4();function Rq(i){return i&&i.__esModule?i:{default:i}}function W4(i){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?W4=function(a){return typeof a}:W4=function(a){return a&&typeof Symbol=="function"&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},W4(i)}var Oq=Object.prototype.toString,dh=new z9.default;lm.jsonDiff=dh;dh.useLongestToken=!0;dh.tokenize=Aq.lineDiff.tokenize;dh.castInput=function(i){var o=this.options,a=o.undefinedReplacement,c=o.stringifyReplacer,_=c===void 0?function(t,M){return typeof M=="undefined"?a:M}:c;return typeof i=="string"?i:JSON.stringify(q4(i,null,null,_),_," ")};dh.equals=function(i,o){return z9.default.prototype.equals.call(dh,i.replace(/,([\r\n])/g,"$1"),o.replace(/,([\r\n])/g,"$1"))};function xq(i,o,a){return dh.diff(i,o,a)}function q4(i,o,a,c,_){o=o||[],a=a||[],c&&(i=c(_,i));var t;for(t=0;t{"use strict";Object.defineProperty(Zg,"__esModule",{value:!0});Zg.diffArrays=Mq;Zg.arrayDiff=void 0;var Lq=kq(nd());function kq(i){return i&&i.__esModule?i:{default:i}}var $g=new Lq.default;Zg.arrayDiff=$g;$g.tokenize=function(i){return i.slice()};$g.join=$g.removeEmpty=function(i){return i};function Mq(i,o,a){return $g.diff(i,o,a)}});var V4=Ke(C3=>{"use strict";Object.defineProperty(C3,"__esModule",{value:!0});C3.parsePatch=Nq;function Nq(i){var o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},a=i.split(/\r\n|[\n\v\f\r\x85]/),c=i.match(/\r\n|[\n\v\f\r\x85]/g)||[],_=[],t=0;function M(){var T={};for(_.push(T);t{"use strict";Object.defineProperty(x3,"__esModule",{value:!0});x3.default=Fq;function Fq(i,o,a){var c=!0,_=!1,t=!1,M=1;return function N(){if(c&&!t){if(_?M++:c=!1,i+M<=a)return M;t=!0}if(!_)return t||(c=!0),o<=i-M?-M++:(_=!0,N())}}});var Y9=Ke(G4=>{"use strict";Object.defineProperty(G4,"__esModule",{value:!0});G4.applyPatch=V9;G4.applyPatches=Pq;var G9=V4(),bq=Iq(W9());function Iq(i){return i&&i.__esModule?i:{default:i}}function V9(i,o){var a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};if(typeof o=="string"&&(o=(0,G9.parsePatch)(o)),Array.isArray(o)){if(o.length>1)throw new Error("applyPatch only works with a single input.");o=o[0]}var c=i.split(/\r\n|[\n\v\f\r\x85]/),_=i.match(/\r\n|[\n\v\f\r\x85]/g)||[],t=o.hunks,M=a.compareLine||function(kt,zt,nt,X){return zt===X},N=0,O=a.fuzzFactor||0,T=0,B=0,H,q;function ne(kt,zt){for(var nt=0;nt0?X[0]:" ",xe=X.length>0?X.substr(1):X;if(fe===" "||fe==="-"){if(!M(zt+1,c[zt],fe,xe)&&(N++,N>O))return!1;zt++}}return!0}for(var m=0;m0?je[0]:" ",pt=je.length>0?je.substr(1):je,Xe=re.linedelimiters[Ie];if(ct===" ")we++;else if(ct==="-")c.splice(we,1),_.splice(we,1);else if(ct==="+")c.splice(we,0,pt),_.splice(we,0,Xe),we++;else if(ct==="\\"){var tt=re.lines[Ie-1]?re.lines[Ie-1][0]:null;tt==="+"?H=!0:tt==="-"&&(q=!0)}}}if(H)for(;!c[c.length-1];)c.pop(),_.pop();else q&&(c.push(""),_.push(` -`));for(var He=0;He{"use strict";Object.defineProperty(e_,"__esModule",{value:!0});e_.structuredPatch=K9;e_.createTwoFilesPatch=X9;e_.createPatch=Bq;var Uq=H4();function R3(i){return Hq(i)||zq(i)||jq()}function jq(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function zq(i){if(Symbol.iterator in Object(i)||Object.prototype.toString.call(i)==="[object Arguments]")return Array.from(i)}function Hq(i){if(Array.isArray(i)){for(var o=0,a=new Array(i.length);o0?O(re.lines.slice(-M.context)):[],B-=q.length,H-=q.length)}(me=q).push.apply(me,R3(ce.map(function(He){return(_e.added?"+":"-")+He}))),_e.added?m+=ce.length:ne+=ce.length}else{if(B)if(ce.length<=M.context*2&&ue=N.length-2&&ce.length<=M.context){var pt=/\n$/.test(a),Xe=/\n$/.test(c),tt=ce.length==0&&q.length>ct.oldLines;!pt&&tt&&q.splice(ct.oldLines,0,"\\ No newline at end of file"),(!pt&&!tt||!Xe)&&q.push("\\ No newline at end of file")}T.push(ct),B=0,H=0,q=[]}ne+=ce.length,m+=ce.length}},ge=0;ge{"use strict";Object.defineProperty(Y4,"__esModule",{value:!0});Y4.arrayEqual=qq;Y4.arrayStartsWith=Q9;function qq(i,o){return i.length!==o.length?!1:Q9(i,o)}function Q9(i,o){if(o.length>i.length)return!1;for(var a=0;a{"use strict";Object.defineProperty(K4,"__esModule",{value:!0});K4.calcLineCount=Z9;K4.merge=Wq;var Vq=A3(),Gq=V4(),O3=J9();function sm(i){return Xq(i)||Kq(i)||Yq()}function Yq(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function Kq(i){if(Symbol.iterator in Object(i)||Object.prototype.toString.call(i)==="[object Arguments]")return Array.from(i)}function Xq(i){if(Array.isArray(i)){for(var o=0,a=new Array(i.length);o{"use strict";Object.defineProperty(L3,"__esModule",{value:!0});L3.convertChangesToDMP=$q;function $q(i){for(var o=[],a,c,_=0;_{"use strict";Object.defineProperty(N3,"__esModule",{value:!0});N3.convertChangesToXML=eW;function eW(i){for(var o=[],a=0;a"):c.removed&&o.push(""),o.push(tW(c.value)),c.added?o.push(""):c.removed&&o.push("")}return o.join("")}function tW(i){var o=i;return o=o.replace(/&/g,"&"),o=o.replace(//g,">"),o=o.replace(/"/g,"""),o}});var vR=Ke(Yo=>{"use strict";Object.defineProperty(Yo,"__esModule",{value:!0});Object.defineProperty(Yo,"Diff",{enumerable:!0,get:function(){return nW.default}});Object.defineProperty(Yo,"diffChars",{enumerable:!0,get:function(){return rW.diffChars}});Object.defineProperty(Yo,"diffWords",{enumerable:!0,get:function(){return cR.diffWords}});Object.defineProperty(Yo,"diffWordsWithSpace",{enumerable:!0,get:function(){return cR.diffWordsWithSpace}});Object.defineProperty(Yo,"diffLines",{enumerable:!0,get:function(){return dR.diffLines}});Object.defineProperty(Yo,"diffTrimmedLines",{enumerable:!0,get:function(){return dR.diffTrimmedLines}});Object.defineProperty(Yo,"diffSentences",{enumerable:!0,get:function(){return iW.diffSentences}});Object.defineProperty(Yo,"diffCss",{enumerable:!0,get:function(){return uW.diffCss}});Object.defineProperty(Yo,"diffJson",{enumerable:!0,get:function(){return pR.diffJson}});Object.defineProperty(Yo,"canonicalize",{enumerable:!0,get:function(){return pR.canonicalize}});Object.defineProperty(Yo,"diffArrays",{enumerable:!0,get:function(){return oW.diffArrays}});Object.defineProperty(Yo,"applyPatch",{enumerable:!0,get:function(){return hR.applyPatch}});Object.defineProperty(Yo,"applyPatches",{enumerable:!0,get:function(){return hR.applyPatches}});Object.defineProperty(Yo,"parsePatch",{enumerable:!0,get:function(){return lW.parsePatch}});Object.defineProperty(Yo,"merge",{enumerable:!0,get:function(){return sW.merge}});Object.defineProperty(Yo,"structuredPatch",{enumerable:!0,get:function(){return F3.structuredPatch}});Object.defineProperty(Yo,"createTwoFilesPatch",{enumerable:!0,get:function(){return F3.createTwoFilesPatch}});Object.defineProperty(Yo,"createPatch",{enumerable:!0,get:function(){return F3.createPatch}});Object.defineProperty(Yo,"convertChangesToDMP",{enumerable:!0,get:function(){return aW.convertChangesToDMP}});Object.defineProperty(Yo,"convertChangesToXML",{enumerable:!0,get:function(){return fW.convertChangesToXML}});var nW=cW(nd()),rW=P9(),cR=B9(),dR=H4(),iW=U9(),uW=j9(),pR=H9(),oW=q9(),hR=Y9(),lW=V4(),sW=sR(),F3=A3(),aW=aR(),fW=fR();function cW(i){return i&&i.__esModule?i:{default:i}}});var dW={};oI(dW,{default:()=>hW});var x9=ou(require("@yarnpkg/cli")),ch=ou(require("@yarnpkg/core"));var u5=ou(sc()),lh=ou(Mi()),C4=(0,lh.memo)(({active:i})=>{let o=(0,lh.useMemo)(()=>i?"\u25C9":"\u25EF",[i]),a=(0,lh.useMemo)(()=>i?"green":"yellow",[i]);return lh.default.createElement(u5.Text,{color:a},o)});var g2=ou(sc()),ra=ou(Mi());var o5=ou(sc()),x4=ou(Mi());function y2({active:i},o,a){let{stdin:c}=(0,o5.useStdin)(),_=(0,x4.useCallback)((t,M)=>o(t,M),a);(0,x4.useEffect)(()=>{if(!(!i||!c))return c.on("keypress",_),()=>{c.off("keypress",_)}},[i,_,c])}var R4;(function(a){a.BEFORE="before",a.AFTER="after"})(R4||(R4={}));var l5=function({active:i},o,a){y2({active:i},(c,_)=>{_.name==="tab"&&(_.shift?o(R4.BEFORE):o(R4.AFTER))},a)};var A4=function(i,o,{active:a,minus:c,plus:_,set:t,loop:M=!0}){y2({active:a},(N,O)=>{let T=o.indexOf(i);switch(O.name){case c:{let B=T-1;if(M){t(o[(o.length+B)%o.length]);return}if(B<0)return;t(o[B])}break;case _:{let B=T+1;if(M){t(o[B%o.length]);return}if(B>=o.length)return;t(o[B])}break}},[o,i,_,t,M])};var O4=({active:i=!0,children:o=[],radius:a=10,size:c=1,loop:_=!0,onFocusRequest:t,willReachEnd:M})=>{let N=ge=>{if(ge.key===null)throw new Error("Expected all children to have a key");return ge.key},O=ra.default.Children.map(o,ge=>N(ge)),T=O[0],[B,H]=(0,ra.useState)(T),q=O.indexOf(B);(0,ra.useEffect)(()=>{O.includes(B)||H(T)},[o]),(0,ra.useEffect)(()=>{M&&q>=O.length-2&&M()},[q]),l5({active:i&&!!t},ge=>{t==null||t(ge)},[t]),A4(B,O,{active:i,minus:"up",plus:"down",set:H,loop:_});let ne=q-a,m=q+a;m>O.length&&(ne-=m-O.length,m=O.length),ne<0&&(m+=-ne,ne=0),m>=O.length&&(m=O.length-1);let pe=[];for(let ge=ne;ge<=m;++ge){let ve=O[ge],ue=i&&ve===B;pe.push(ra.default.createElement(g2.Box,{key:ve,height:c},ra.default.createElement(g2.Box,{marginLeft:1,marginRight:1},ra.default.createElement(g2.Text,null,ue?ra.default.createElement(g2.Text,{color:"cyan",bold:!0},">"):" ")),ra.default.createElement(g2.Box,null,ra.default.cloneElement(o[ge],{active:ue}))))}return ra.default.createElement(g2.Box,{flexDirection:"column",width:"100%"},pe)};var M4=ou(Mi());var s5=ou(sc()),td=ou(Mi()),a5=ou(require("readline")),$w=td.default.createContext(null),f5=({children:i})=>{let{stdin:o,setRawMode:a}=(0,s5.useStdin)();(0,td.useEffect)(()=>{a&&a(!0),o&&(0,a5.emitKeypressEvents)(o)},[o,a]);let[c,_]=(0,td.useState)(new Map),t=(0,td.useMemo)(()=>({getAll:()=>c,get:M=>c.get(M),set:(M,N)=>_(new Map([...c,[M,N]]))}),[c,_]);return td.default.createElement($w.Provider,{value:t,children:i})};function sh(i,o){let a=(0,M4.useContext)($w);if(a===null)throw new Error("Expected this hook to run with a ministore context attached");if(typeof i=="undefined")return a.getAll();let c=(0,M4.useCallback)(t=>{a.set(i,t)},[i,a.set]),_=a.get(i);return typeof _=="undefined"&&(_=o),[_,c]}var k4=ou(sc()),e3=ou(Mi());async function L4(i,o,{stdin:a,stdout:c,stderr:_}={}){let t,M=O=>{let{exit:T}=(0,k4.useApp)();y2({active:!0},(B,H)=>{H.name==="return"&&(t=O,T())},[T,O])},{waitUntilExit:N}=(0,k4.render)(e3.default.createElement(f5,null,e3.default.createElement(i,Zr(qt({},o),{useSubmit:M}))),{stdin:a,stdout:c,stderr:_});return await N(),t}var R9=ou(require("clipanion")),A9=ou(h5()),or=ou(sc()),En=ou(Mi());var C9=ou(T9()),g3={appId:"OFCNCOG2CU",apiKey:"6fe4476ee5a1832882e326b506d14126",indexName:"npm-search"},rq=(0,C9.default)(g3.appId,g3.apiKey).initIndex(g3.indexName),_3=async(i,o=0)=>await rq.search(i,{analyticsTags:["yarn-plugin-interactive-tools"],attributesToRetrieve:["name","version","owner","repository","humanDownloadsLast30Days"],page:o,hitsPerPage:10});var Vg=["regular","dev","peer"],Gg=class extends x9.BaseCommand{async execute(){let o=await ch.Configuration.find(this.context.cwd,this.context.plugins),a=()=>En.default.createElement(or.Box,{flexDirection:"row"},En.default.createElement(or.Box,{flexDirection:"column",width:48},En.default.createElement(or.Box,null,En.default.createElement(or.Text,null,"Press ",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},""),"/",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},"")," to move between packages.")),En.default.createElement(or.Box,null,En.default.createElement(or.Text,null,"Press ",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},"")," to select a package.")),En.default.createElement(or.Box,null,En.default.createElement(or.Text,null,"Press ",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},"")," again to change the target."))),En.default.createElement(or.Box,{flexDirection:"column"},En.default.createElement(or.Box,{marginLeft:1},En.default.createElement(or.Text,null,"Press ",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},"")," to install the selected packages.")),En.default.createElement(or.Box,{marginLeft:1},En.default.createElement(or.Text,null,"Press ",En.default.createElement(or.Text,{bold:!0,color:"cyanBright"},"")," to abort.")))),c=()=>En.default.createElement(En.default.Fragment,null,En.default.createElement(or.Box,{width:15},En.default.createElement(or.Text,{bold:!0,underline:!0,color:"gray"},"Owner")),En.default.createElement(or.Box,{width:11},En.default.createElement(or.Text,{bold:!0,underline:!0,color:"gray"},"Version")),En.default.createElement(or.Box,{width:10},En.default.createElement(or.Text,{bold:!0,underline:!0,color:"gray"},"Downloads"))),_=()=>En.default.createElement(or.Box,{width:17},En.default.createElement(or.Text,{bold:!0,underline:!0,color:"gray"},"Target")),t=({hit:ne,active:m})=>{let[pe,ge]=sh(ne.name,null);y2({active:m},(_e,ce)=>{if(ce.name!=="space")return;if(!pe){ge(Vg[0]);return}let me=Vg.indexOf(pe)+1;me===Vg.length?ge(null):ge(Vg[me])},[pe,ge]);let ve=ch.structUtils.parseIdent(ne.name),ue=ch.structUtils.prettyIdent(o,ve);return En.default.createElement(or.Box,null,En.default.createElement(or.Box,{width:45},En.default.createElement(or.Text,{bold:!0,wrap:"wrap"},ue)),En.default.createElement(or.Box,{width:14,marginLeft:1},En.default.createElement(or.Text,{bold:!0,wrap:"truncate"},ne.owner.name)),En.default.createElement(or.Box,{width:10,marginLeft:1},En.default.createElement(or.Text,{italic:!0,wrap:"truncate"},ne.version)),En.default.createElement(or.Box,{width:16,marginLeft:1},En.default.createElement(or.Text,null,ne.humanDownloadsLast30Days)))},M=({name:ne,active:m})=>{let[pe]=sh(ne,null),ge=ch.structUtils.parseIdent(ne);return En.default.createElement(or.Box,null,En.default.createElement(or.Box,{width:47},En.default.createElement(or.Text,{bold:!0}," - ",ch.structUtils.prettyIdent(o,ge))),Vg.map(ve=>En.default.createElement(or.Box,{key:ve,width:14,marginLeft:1},En.default.createElement(or.Text,null," ",En.default.createElement(C4,{active:pe===ve})," ",En.default.createElement(or.Text,{bold:!0},ve)))))},N=()=>En.default.createElement(or.Box,{marginTop:1},En.default.createElement(or.Text,null,"Powered by Algolia.")),T=await L4(({useSubmit:ne})=>{let m=sh();ne(m);let pe=Array.from(m.keys()).filter(je=>m.get(je)!==null),[ge,ve]=(0,En.useState)(""),[ue,_e]=(0,En.useState)(0),[ce,me]=(0,En.useState)([]),re=je=>{je.match(/\t| /)||ve(je)},we=async()=>{_e(0);let je=await _3(ge);je.query===ge&&me(je.hits)},Ie=async()=>{let je=await _3(ge,ue+1);je.query===ge&&je.page-1===ue&&(_e(je.page),me([...ce,...je.hits]))};return(0,En.useEffect)(()=>{ge?we():me([])},[ge]),En.default.createElement(or.Box,{flexDirection:"column"},En.default.createElement(a,null),En.default.createElement(or.Box,{flexDirection:"row",marginTop:1},En.default.createElement(or.Text,{bold:!0},"Search: "),En.default.createElement(or.Box,{width:41},En.default.createElement(A9.default,{value:ge,onChange:re,placeholder:"i.e. babel, webpack, react...",showCursor:!1})),En.default.createElement(c,null)),ce.length?En.default.createElement(O4,{radius:2,loop:!1,children:ce.map(je=>En.default.createElement(t,{key:je.name,hit:je,active:!1})),willReachEnd:Ie}):En.default.createElement(or.Text,{color:"gray"},"Start typing..."),En.default.createElement(or.Box,{flexDirection:"row",marginTop:1},En.default.createElement(or.Box,{width:49},En.default.createElement(or.Text,{bold:!0},"Selected:")),En.default.createElement(_,null)),pe.length?pe.map(je=>En.default.createElement(M,{key:je,name:je,active:!1})):En.default.createElement(or.Text,{color:"gray"},"No selected packages..."),En.default.createElement(N,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof T=="undefined")return 1;let B=Array.from(T.keys()).filter(ne=>T.get(ne)==="regular"),H=Array.from(T.keys()).filter(ne=>T.get(ne)==="dev"),q=Array.from(T.keys()).filter(ne=>T.get(ne)==="peer");return B.length&&await this.cli.run(["add",...B]),H.length&&await this.cli.run(["add","--dev",...H]),q&&await this.cli.run(["add","--peer",...q]),0}};Gg.paths=[["search"]],Gg.usage=R9.Command.Usage({category:"Interactive commands",description:"open the search interface",details:` - This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry. - `,examples:[["Open the search window","yarn search"]]});var O9=Gg;var Q4=ou(require("@yarnpkg/cli")),R0=ou(require("@yarnpkg/core"));var Yg=ou(sc()),E2=ou(Mi());var M9=ou(sc()),k9=ou(Mi()),j4=({length:i,active:o})=>{if(i===0)return null;let a=i>1?` ${"-".repeat(i-1)}`:" ";return k9.default.createElement(M9.Text,{dimColor:!o},a)};var L9=function({active:i,skewer:o,options:a,value:c,onChange:_,sizes:t=[]}){let M=a.filter(({label:O})=>!!O).map(({value:O})=>O),N=a.findIndex(O=>O.value===c&&O.label!="");return A4(c,M,{active:i,minus:"left",plus:"right",set:_}),E2.default.createElement(E2.default.Fragment,null,a.map(({label:O},T)=>{let B=T===N,H=t[T]-1||0,q=O.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,""),ne=Math.max(0,H-q.length-2);return O?E2.default.createElement(Yg.Box,{key:O,width:H,marginLeft:1},E2.default.createElement(Yg.Text,{wrap:"truncate"},E2.default.createElement(C4,{active:B})," ",O),o?E2.default.createElement(j4,{active:i,length:ne}):null):E2.default.createElement(Yg.Box,{key:`spacer-${T}`,width:H,marginLeft:1})}))};var mR=ou(require("@yarnpkg/plugin-essentials")),J4=ou(require("clipanion")),yR=ou(vR()),bi=ou(sc()),Tr=ou(Mi()),gR=ou(require("semver")),_R=/^((?:[\^~]|>=?)?)([0-9]+)(\.[0-9]+)(\.[0-9]+)((?:-\S+)?)$/,ER=(i,o)=>i.length>0?[i.slice(0,o)].concat(ER(i.slice(o),o)):[],t_=class extends Q4.BaseCommand{async execute(){if(!this.context.stdout.isTTY)throw new J4.UsageError("This command can only be run in a TTY environment");let o=await R0.Configuration.find(this.context.cwd,this.context.plugins),{project:a,workspace:c}=await R0.Project.find(o,this.context.cwd),_=await R0.Cache.find(o);if(!c)throw new Q4.WorkspaceRequiredError(a.cwd,this.context.cwd);await a.restoreInstallState({restoreResolutions:!1});let t=this.context.stdout.rows-7,M=(ue,_e)=>{let ce=(0,yR.diffWords)(ue,_e),me="";for(let re of ce)re.added?me+=R0.formatUtils.pretty(o,re.value,"green"):re.removed||(me+=re.value);return me},N=(ue,_e)=>{if(ue===_e)return _e;let ce=R0.structUtils.parseRange(ue),me=R0.structUtils.parseRange(_e),re=ce.selector.match(_R),we=me.selector.match(_R);if(!re||!we)return M(ue,_e);let Ie=["gray","red","yellow","green","magenta"],je=null,ct="";for(let pt=1;pt{let me=await mR.suggestUtils.fetchDescriptorFrom(ue,ce,{project:a,cache:_,preserveModifier:_e,workspace:c});return me!==null?me.range:ue.range},T=async ue=>{let _e=gR.default.valid(ue.range)?`^${ue.range}`:ue.range,[ce,me]=await Promise.all([O(ue,ue.range,_e).catch(()=>null),O(ue,ue.range,"latest").catch(()=>null)]),re=[{value:null,label:ue.range}];return ce&&ce!==ue.range?re.push({value:ce,label:N(ue.range,ce)}):re.push({value:null,label:""}),me&&me!==ce&&me!==ue.range?re.push({value:me,label:N(ue.range,me)}):re.push({value:null,label:""}),re},B=()=>Tr.default.createElement(bi.Box,{flexDirection:"row"},Tr.default.createElement(bi.Box,{flexDirection:"column",width:49},Tr.default.createElement(bi.Box,{marginLeft:1},Tr.default.createElement(bi.Text,null,"Press ",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},""),"/",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},"")," to select packages.")),Tr.default.createElement(bi.Box,{marginLeft:1},Tr.default.createElement(bi.Text,null,"Press ",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},""),"/",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},"")," to select versions."))),Tr.default.createElement(bi.Box,{flexDirection:"column"},Tr.default.createElement(bi.Box,{marginLeft:1},Tr.default.createElement(bi.Text,null,"Press ",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},"")," to install.")),Tr.default.createElement(bi.Box,{marginLeft:1},Tr.default.createElement(bi.Text,null,"Press ",Tr.default.createElement(bi.Text,{bold:!0,color:"cyanBright"},"")," to abort.")))),H=()=>Tr.default.createElement(bi.Box,{flexDirection:"row",paddingTop:1,paddingBottom:1},Tr.default.createElement(bi.Box,{width:50},Tr.default.createElement(bi.Text,{bold:!0},Tr.default.createElement(bi.Text,{color:"greenBright"},"?")," Pick the packages you want to upgrade.")),Tr.default.createElement(bi.Box,{width:17},Tr.default.createElement(bi.Text,{bold:!0,underline:!0,color:"gray"},"Current")),Tr.default.createElement(bi.Box,{width:17},Tr.default.createElement(bi.Text,{bold:!0,underline:!0,color:"gray"},"Range")),Tr.default.createElement(bi.Box,{width:17},Tr.default.createElement(bi.Text,{bold:!0,underline:!0,color:"gray"},"Latest"))),q=({active:ue,descriptor:_e,suggestions:ce})=>{let[me,re]=sh(_e.descriptorHash,null),we=R0.structUtils.stringifyIdent(_e),Ie=Math.max(0,45-we.length);return Tr.default.createElement(Tr.default.Fragment,null,Tr.default.createElement(bi.Box,null,Tr.default.createElement(bi.Box,{width:45},Tr.default.createElement(bi.Text,{bold:!0},R0.structUtils.prettyIdent(o,_e)),Tr.default.createElement(j4,{active:ue,length:Ie})),Tr.default.createElement(L9,{active:ue,options:ce,value:me,skewer:!0,onChange:re,sizes:[17,17,17]})))},ne=({dependencies:ue})=>{let[_e,ce]=(0,Tr.useState)(ue.map(()=>null)),me=(0,Tr.useRef)(!0),re=async we=>{let Ie=await T(we);return Ie.filter(je=>je.label!=="").length<=1?null:{descriptor:we,suggestions:Ie}};return(0,Tr.useEffect)(()=>()=>{me.current=!1},[]),(0,Tr.useEffect)(()=>{let we=Math.trunc(t*1.75),Ie=ue.slice(0,we),je=ue.slice(we),ct=ER(je,t),pt=Ie.map(re).reduce(async(Xe,tt)=>{await Xe;let He=await tt;He!==null&&(!me.current||ce(kt=>{let zt=kt.findIndex(X=>X===null),nt=[...kt];return nt[zt]=He,nt}))},Promise.resolve());ct.reduce((Xe,tt)=>Promise.all(tt.map(He=>Promise.resolve().then(()=>re(He)))).then(async He=>{He=He.filter(kt=>kt!==null),await Xe,me.current&&ce(kt=>{let zt=kt.findIndex(nt=>nt===null);return kt.slice(0,zt).concat(He).concat(kt.slice(zt+He.length))})}),pt).then(()=>{me.current&&ce(Xe=>Xe.filter(tt=>tt!==null))})},[]),_e.length?Tr.default.createElement(O4,{radius:t>>1,children:_e.map((we,Ie)=>we!==null?Tr.default.createElement(q,{key:Ie,active:!1,descriptor:we.descriptor,suggestions:we.suggestions}):Tr.default.createElement(bi.Text,{key:Ie},"Loading..."))}):Tr.default.createElement(bi.Text,null,"No upgrades found")},pe=await L4(({useSubmit:ue})=>{ue(sh());let _e=new Map;for(let me of a.workspaces)for(let re of["dependencies","devDependencies"])for(let we of me.manifest[re].values())a.tryWorkspaceByDescriptor(we)===null&&_e.set(we.descriptorHash,we);let ce=R0.miscUtils.sortMap(_e.values(),me=>R0.structUtils.stringifyDescriptor(me));return Tr.default.createElement(bi.Box,{flexDirection:"column"},Tr.default.createElement(B,null),Tr.default.createElement(H,null),Tr.default.createElement(ne,{dependencies:ce}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof pe=="undefined")return 1;let ge=!1;for(let ue of a.workspaces)for(let _e of["dependencies","devDependencies"]){let ce=ue.manifest[_e];for(let me of ce.values()){let re=pe.get(me.descriptorHash);typeof re!="undefined"&&re!==null&&(ce.set(me.identHash,R0.structUtils.makeDescriptor(me,re)),ge=!0)}}return ge?(await R0.StreamReport.start({configuration:o,stdout:this.context.stdout,includeLogs:!this.context.quiet},async ue=>{await a.install({cache:_,report:ue})})).exitCode():0}};t_.paths=[["upgrade-interactive"]],t_.usage=J4.Command.Usage({category:"Interactive commands",description:"open the upgrade interface",details:` - This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade. - `,examples:[["Open the upgrade window","yarn upgrade-interactive"]]});var DR=t_;var pW={commands:[O9,DR]},hW=pW;return dW;})(); -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -/** @license React v0.0.0-experimental-51a3aa6af - * react-debug-tools.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.0.0-experimental-51a3aa6af - * react-is.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.0.0-experimental-51a3aa6af - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.18.0 - * scheduler-tracing.development.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.18.0 - * scheduler-tracing.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.18.0 - * scheduler.development.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.18.0 - * scheduler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.24.0 - * react-reconciler.development.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.24.0 - * react-reconciler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v16.13.1 - * react.development.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v16.13.1 - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -return plugin; -} -}; diff --git a/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs b/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs deleted file mode 100644 index b9044a014..000000000 --- a/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +++ /dev/null @@ -1,28 +0,0 @@ -/* eslint-disable */ -//prettier-ignore -module.exports = { -name: "@yarnpkg/plugin-workspace-tools", -factory: function (require) { -var plugin=(()=>{var wr=Object.create,me=Object.defineProperty,Sr=Object.defineProperties,vr=Object.getOwnPropertyDescriptor,Hr=Object.getOwnPropertyDescriptors,$r=Object.getOwnPropertyNames,et=Object.getOwnPropertySymbols,kr=Object.getPrototypeOf,tt=Object.prototype.hasOwnProperty,Tr=Object.prototype.propertyIsEnumerable;var rt=(e,t,r)=>t in e?me(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,B=(e,t)=>{for(var r in t||(t={}))tt.call(t,r)&&rt(e,r,t[r]);if(et)for(var r of et(t))Tr.call(t,r)&&rt(e,r,t[r]);return e},Q=(e,t)=>Sr(e,Hr(t)),Lr=e=>me(e,"__esModule",{value:!0});var K=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Or=(e,t)=>{for(var r in t)me(e,r,{get:t[r],enumerable:!0})},Nr=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of $r(t))!tt.call(e,n)&&n!=="default"&&me(e,n,{get:()=>t[n],enumerable:!(r=vr(t,n))||r.enumerable});return e},X=e=>Nr(Lr(me(e!=null?wr(kr(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var $e=K(te=>{"use strict";te.isInteger=e=>typeof e=="number"?Number.isInteger(e):typeof e=="string"&&e.trim()!==""?Number.isInteger(Number(e)):!1;te.find=(e,t)=>e.nodes.find(r=>r.type===t);te.exceedsLimit=(e,t,r=1,n)=>n===!1||!te.isInteger(e)||!te.isInteger(t)?!1:(Number(t)-Number(e))/Number(r)>=n;te.escapeNode=(e,t=0,r)=>{let n=e.nodes[t];!n||(r&&n.type===r||n.type==="open"||n.type==="close")&&n.escaped!==!0&&(n.value="\\"+n.value,n.escaped=!0)};te.encloseBrace=e=>e.type!=="brace"?!1:e.commas>>0+e.ranges>>0==0?(e.invalid=!0,!0):!1;te.isInvalidBrace=e=>e.type!=="brace"?!1:e.invalid===!0||e.dollar?!0:e.commas>>0+e.ranges>>0==0||e.open!==!0||e.close!==!0?(e.invalid=!0,!0):!1;te.isOpenOrClose=e=>e.type==="open"||e.type==="close"?!0:e.open===!0||e.close===!0;te.reduce=e=>e.reduce((t,r)=>(r.type==="text"&&t.push(r.value),r.type==="range"&&(r.type="text"),t),[]);te.flatten=(...e)=>{let t=[],r=n=>{for(let s=0;s{"use strict";var it=$e();at.exports=(e,t={})=>{let r=(n,s={})=>{let a=t.escapeInvalid&&it.isInvalidBrace(s),i=n.invalid===!0&&t.escapeInvalid===!0,o="";if(n.value)return(a||i)&&it.isOpenOrClose(n)?"\\"+n.value:n.value;if(n.value)return n.value;if(n.nodes)for(let h of n.nodes)o+=r(h);return o};return r(e)}});var ct=K((os,ot)=>{"use strict";ot.exports=function(e){return typeof e=="number"?e-e==0:typeof e=="string"&&e.trim()!==""?Number.isFinite?Number.isFinite(+e):isFinite(+e):!1}});var At=K((cs,ut)=>{"use strict";var lt=ct(),pe=(e,t,r)=>{if(lt(e)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(t===void 0||e===t)return String(e);if(lt(t)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let n=B({relaxZeros:!0},r);typeof n.strictZeros=="boolean"&&(n.relaxZeros=n.strictZeros===!1);let s=String(n.relaxZeros),a=String(n.shorthand),i=String(n.capture),o=String(n.wrap),h=e+":"+t+"="+s+a+i+o;if(pe.cache.hasOwnProperty(h))return pe.cache[h].result;let g=Math.min(e,t),f=Math.max(e,t);if(Math.abs(g-f)===1){let R=e+"|"+t;return n.capture?`(${R})`:n.wrap===!1?R:`(?:${R})`}let A=ft(e)||ft(t),p={min:e,max:t,a:g,b:f},k=[],y=[];if(A&&(p.isPadded=A,p.maxLen=String(p.max).length),g<0){let R=f<0?Math.abs(f):1;y=pt(R,Math.abs(g),p,n),g=p.a=0}return f>=0&&(k=pt(g,f,p,n)),p.negatives=y,p.positives=k,p.result=Ir(y,k,n),n.capture===!0?p.result=`(${p.result})`:n.wrap!==!1&&k.length+y.length>1&&(p.result=`(?:${p.result})`),pe.cache[h]=p,p.result};function Ir(e,t,r){let n=Pe(e,t,"-",!1,r)||[],s=Pe(t,e,"",!1,r)||[],a=Pe(e,t,"-?",!0,r)||[];return n.concat(a).concat(s).join("|")}function Mr(e,t){let r=1,n=1,s=ht(e,r),a=new Set([t]);for(;e<=s&&s<=t;)a.add(s),r+=1,s=ht(e,r);for(s=dt(t+1,n)-1;e1&&o.count.pop(),o.count.push(f.count[0]),o.string=o.pattern+gt(o.count),i=g+1;continue}r.isPadded&&(A=Gr(g,r,n)),f.string=A+f.pattern+gt(f.count),a.push(f),i=g+1,o=f}return a}function Pe(e,t,r,n,s){let a=[];for(let i of e){let{string:o}=i;!n&&!mt(t,"string",o)&&a.push(r+o),n&&mt(t,"string",o)&&a.push(r+o)}return a}function Pr(e,t){let r=[];for(let n=0;nt?1:t>e?-1:0}function mt(e,t,r){return e.some(n=>n[t]===r)}function ht(e,t){return Number(String(e).slice(0,-t)+"9".repeat(t))}function dt(e,t){return e-e%Math.pow(10,t)}function gt(e){let[t=0,r=""]=e;return r||t>1?`{${t+(r?","+r:"")}}`:""}function Dr(e,t,r){return`[${e}${t-e==1?"":"-"}${t}]`}function ft(e){return/^-?(0+)\d/.test(e)}function Gr(e,t,r){if(!t.isPadded)return e;let n=Math.abs(t.maxLen-String(e).length),s=r.relaxZeros!==!1;switch(n){case 0:return"";case 1:return s?"0?":"0";case 2:return s?"0{0,2}":"00";default:return s?`0{0,${n}}`:`0{${n}}`}}pe.cache={};pe.clearCache=()=>pe.cache={};ut.exports=pe});var Ge=K((us,Rt)=>{"use strict";var qr=require("util"),yt=At(),bt=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),Kr=e=>t=>e===!0?Number(t):String(t),De=e=>typeof e=="number"||typeof e=="string"&&e!=="",Re=e=>Number.isInteger(+e),Ue=e=>{let t=`${e}`,r=-1;if(t[0]==="-"&&(t=t.slice(1)),t==="0")return!1;for(;t[++r]==="0";);return r>0},Wr=(e,t,r)=>typeof e=="string"||typeof t=="string"?!0:r.stringify===!0,jr=(e,t,r)=>{if(t>0){let n=e[0]==="-"?"-":"";n&&(e=e.slice(1)),e=n+e.padStart(n?t-1:t,"0")}return r===!1?String(e):e},_t=(e,t)=>{let r=e[0]==="-"?"-":"";for(r&&(e=e.slice(1),t--);e.length{e.negatives.sort((i,o)=>io?1:0),e.positives.sort((i,o)=>io?1:0);let r=t.capture?"":"?:",n="",s="",a;return e.positives.length&&(n=e.positives.join("|")),e.negatives.length&&(s=`-(${r}${e.negatives.join("|")})`),n&&s?a=`${n}|${s}`:a=n||s,t.wrap?`(${r}${a})`:a},Et=(e,t,r,n)=>{if(r)return yt(e,t,B({wrap:!1},n));let s=String.fromCharCode(e);if(e===t)return s;let a=String.fromCharCode(t);return`[${s}-${a}]`},xt=(e,t,r)=>{if(Array.isArray(e)){let n=r.wrap===!0,s=r.capture?"":"?:";return n?`(${s}${e.join("|")})`:e.join("|")}return yt(e,t,r)},Ct=(...e)=>new RangeError("Invalid range arguments: "+qr.inspect(...e)),wt=(e,t,r)=>{if(r.strictRanges===!0)throw Ct([e,t]);return[]},Qr=(e,t)=>{if(t.strictRanges===!0)throw new TypeError(`Expected step "${e}" to be a number`);return[]},Xr=(e,t,r=1,n={})=>{let s=Number(e),a=Number(t);if(!Number.isInteger(s)||!Number.isInteger(a)){if(n.strictRanges===!0)throw Ct([e,t]);return[]}s===0&&(s=0),a===0&&(a=0);let i=s>a,o=String(e),h=String(t),g=String(r);r=Math.max(Math.abs(r),1);let f=Ue(o)||Ue(h)||Ue(g),A=f?Math.max(o.length,h.length,g.length):0,p=f===!1&&Wr(e,t,n)===!1,k=n.transform||Kr(p);if(n.toRegex&&r===1)return Et(_t(e,A),_t(t,A),!0,n);let y={negatives:[],positives:[]},R=T=>y[T<0?"negatives":"positives"].push(Math.abs(T)),_=[],x=0;for(;i?s>=a:s<=a;)n.toRegex===!0&&r>1?R(s):_.push(jr(k(s,x),A,p)),s=i?s-r:s+r,x++;return n.toRegex===!0?r>1?Fr(y,n):xt(_,null,B({wrap:!1},n)):_},Zr=(e,t,r=1,n={})=>{if(!Re(e)&&e.length>1||!Re(t)&&t.length>1)return wt(e,t,n);let s=n.transform||(p=>String.fromCharCode(p)),a=`${e}`.charCodeAt(0),i=`${t}`.charCodeAt(0),o=a>i,h=Math.min(a,i),g=Math.max(a,i);if(n.toRegex&&r===1)return Et(h,g,!1,n);let f=[],A=0;for(;o?a>=i:a<=i;)f.push(s(a,A)),a=o?a-r:a+r,A++;return n.toRegex===!0?xt(f,null,{wrap:!1,options:n}):f},Te=(e,t,r,n={})=>{if(t==null&&De(e))return[e];if(!De(e)||!De(t))return wt(e,t,n);if(typeof r=="function")return Te(e,t,1,{transform:r});if(bt(r))return Te(e,t,0,r);let s=B({},n);return s.capture===!0&&(s.wrap=!0),r=r||s.step||1,Re(r)?Re(e)&&Re(t)?Xr(e,t,r,s):Zr(e,t,Math.max(Math.abs(r),1),s):r!=null&&!bt(r)?Qr(r,s):Te(e,t,1,r)};Rt.exports=Te});var Ht=K((ls,St)=>{"use strict";var Yr=Ge(),vt=$e(),zr=(e,t={})=>{let r=(n,s={})=>{let a=vt.isInvalidBrace(s),i=n.invalid===!0&&t.escapeInvalid===!0,o=a===!0||i===!0,h=t.escapeInvalid===!0?"\\":"",g="";if(n.isOpen===!0||n.isClose===!0)return h+n.value;if(n.type==="open")return o?h+n.value:"(";if(n.type==="close")return o?h+n.value:")";if(n.type==="comma")return n.prev.type==="comma"?"":o?n.value:"|";if(n.value)return n.value;if(n.nodes&&n.ranges>0){let f=vt.reduce(n.nodes),A=Yr(...f,Q(B({},t),{wrap:!1,toRegex:!0}));if(A.length!==0)return f.length>1&&A.length>1?`(${A})`:A}if(n.nodes)for(let f of n.nodes)g+=r(f,n);return g};return r(e)};St.exports=zr});var Tt=K((ps,$t)=>{"use strict";var Vr=Ge(),kt=ke(),he=$e(),fe=(e="",t="",r=!1)=>{let n=[];if(e=[].concat(e),t=[].concat(t),!t.length)return e;if(!e.length)return r?he.flatten(t).map(s=>`{${s}}`):t;for(let s of e)if(Array.isArray(s))for(let a of s)n.push(fe(a,t,r));else for(let a of t)r===!0&&typeof a=="string"&&(a=`{${a}}`),n.push(Array.isArray(a)?fe(s,a,r):s+a);return he.flatten(n)},Jr=(e,t={})=>{let r=t.rangeLimit===void 0?1e3:t.rangeLimit,n=(s,a={})=>{s.queue=[];let i=a,o=a.queue;for(;i.type!=="brace"&&i.type!=="root"&&i.parent;)i=i.parent,o=i.queue;if(s.invalid||s.dollar){o.push(fe(o.pop(),kt(s,t)));return}if(s.type==="brace"&&s.invalid!==!0&&s.nodes.length===2){o.push(fe(o.pop(),["{}"]));return}if(s.nodes&&s.ranges>0){let A=he.reduce(s.nodes);if(he.exceedsLimit(...A,t.step,r))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let p=Vr(...A,t);p.length===0&&(p=kt(s,t)),o.push(fe(o.pop(),p)),s.nodes=[];return}let h=he.encloseBrace(s),g=s.queue,f=s;for(;f.type!=="brace"&&f.type!=="root"&&f.parent;)f=f.parent,g=f.queue;for(let A=0;A{"use strict";Lt.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:` -`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Pt=K((hs,Nt)=>{"use strict";var en=ke(),{MAX_LENGTH:It,CHAR_BACKSLASH:qe,CHAR_BACKTICK:tn,CHAR_COMMA:rn,CHAR_DOT:nn,CHAR_LEFT_PARENTHESES:sn,CHAR_RIGHT_PARENTHESES:an,CHAR_LEFT_CURLY_BRACE:on,CHAR_RIGHT_CURLY_BRACE:cn,CHAR_LEFT_SQUARE_BRACKET:Bt,CHAR_RIGHT_SQUARE_BRACKET:Mt,CHAR_DOUBLE_QUOTE:un,CHAR_SINGLE_QUOTE:ln,CHAR_NO_BREAK_SPACE:pn,CHAR_ZERO_WIDTH_NOBREAK_SPACE:fn}=Ot(),hn=(e,t={})=>{if(typeof e!="string")throw new TypeError("Expected a string");let r=t||{},n=typeof r.maxLength=="number"?Math.min(It,r.maxLength):It;if(e.length>n)throw new SyntaxError(`Input length (${e.length}), exceeds max characters (${n})`);let s={type:"root",input:e,nodes:[]},a=[s],i=s,o=s,h=0,g=e.length,f=0,A=0,p,k={},y=()=>e[f++],R=_=>{if(_.type==="text"&&o.type==="dot"&&(o.type="text"),o&&o.type==="text"&&_.type==="text"){o.value+=_.value;return}return i.nodes.push(_),_.parent=i,_.prev=o,o=_,_};for(R({type:"bos"});f0){if(i.ranges>0){i.ranges=0;let _=i.nodes.shift();i.nodes=[_,{type:"text",value:en(i)}]}R({type:"comma",value:p}),i.commas++;continue}if(p===nn&&A>0&&i.commas===0){let _=i.nodes;if(A===0||_.length===0){R({type:"text",value:p});continue}if(o.type==="dot"){if(i.range=[],o.value+=p,o.type="range",i.nodes.length!==3&&i.nodes.length!==5){i.invalid=!0,i.ranges=0,o.type="text";continue}i.ranges++,i.args=[];continue}if(o.type==="range"){_.pop();let x=_[_.length-1];x.value+=o.value+p,o=x,i.ranges--;continue}R({type:"dot",value:p});continue}R({type:"text",value:p})}do if(i=a.pop(),i.type!=="root"){i.nodes.forEach(T=>{T.nodes||(T.type==="open"&&(T.isOpen=!0),T.type==="close"&&(T.isClose=!0),T.nodes||(T.type="text"),T.invalid=!0)});let _=a[a.length-1],x=_.nodes.indexOf(i);_.nodes.splice(x,1,...i.nodes)}while(a.length>0);return R({type:"eos"}),s};Nt.exports=hn});var Gt=K((ds,Dt)=>{"use strict";var Ut=ke(),dn=Ht(),gn=Tt(),mn=Pt(),V=(e,t={})=>{let r=[];if(Array.isArray(e))for(let n of e){let s=V.create(n,t);Array.isArray(s)?r.push(...s):r.push(s)}else r=[].concat(V.create(e,t));return t&&t.expand===!0&&t.nodupes===!0&&(r=[...new Set(r)]),r};V.parse=(e,t={})=>mn(e,t);V.stringify=(e,t={})=>typeof e=="string"?Ut(V.parse(e,t),t):Ut(e,t);V.compile=(e,t={})=>(typeof e=="string"&&(e=V.parse(e,t)),dn(e,t));V.expand=(e,t={})=>{typeof e=="string"&&(e=V.parse(e,t));let r=gn(e,t);return t.noempty===!0&&(r=r.filter(Boolean)),t.nodupes===!0&&(r=[...new Set(r)]),r};V.create=(e,t={})=>e===""||e.length<3?[e]:t.expand!==!0?V.compile(e,t):V.expand(e,t);Dt.exports=V});var ye=K((gs,qt)=>{"use strict";var An=require("path"),ie="\\\\/",Kt=`[^${ie}]`,ce="\\.",Rn="\\+",yn="\\?",Le="\\/",bn="(?=.)",Wt="[^/]",Ke=`(?:${Le}|$)`,jt=`(?:^|${Le})`,We=`${ce}{1,2}${Ke}`,_n=`(?!${ce})`,En=`(?!${jt}${We})`,xn=`(?!${ce}{0,1}${Ke})`,Cn=`(?!${We})`,wn=`[^.${Le}]`,Sn=`${Wt}*?`,Ft={DOT_LITERAL:ce,PLUS_LITERAL:Rn,QMARK_LITERAL:yn,SLASH_LITERAL:Le,ONE_CHAR:bn,QMARK:Wt,END_ANCHOR:Ke,DOTS_SLASH:We,NO_DOT:_n,NO_DOTS:En,NO_DOT_SLASH:xn,NO_DOTS_SLASH:Cn,QMARK_NO_DOT:wn,STAR:Sn,START_ANCHOR:jt},vn=Q(B({},Ft),{SLASH_LITERAL:`[${ie}]`,QMARK:Kt,STAR:`${Kt}*?`,DOTS_SLASH:`${ce}{1,2}(?:[${ie}]|$)`,NO_DOT:`(?!${ce})`,NO_DOTS:`(?!(?:^|[${ie}])${ce}{1,2}(?:[${ie}]|$))`,NO_DOT_SLASH:`(?!${ce}{0,1}(?:[${ie}]|$))`,NO_DOTS_SLASH:`(?!${ce}{1,2}(?:[${ie}]|$))`,QMARK_NO_DOT:`[^.${ie}]`,START_ANCHOR:`(?:^|[${ie}])`,END_ANCHOR:`(?:[${ie}]|$)`}),Hn={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};qt.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:Hn,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:An.sep,extglobChars(e){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${e.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(e){return e===!0?vn:Ft}}});var be=K(Z=>{"use strict";var $n=require("path"),kn=process.platform==="win32",{REGEX_BACKSLASH:Tn,REGEX_REMOVE_BACKSLASH:Ln,REGEX_SPECIAL_CHARS:On,REGEX_SPECIAL_CHARS_GLOBAL:Nn}=ye();Z.isObject=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);Z.hasRegexChars=e=>On.test(e);Z.isRegexChar=e=>e.length===1&&Z.hasRegexChars(e);Z.escapeRegex=e=>e.replace(Nn,"\\$1");Z.toPosixSlashes=e=>e.replace(Tn,"/");Z.removeBackslashes=e=>e.replace(Ln,t=>t==="\\"?"":t);Z.supportsLookbehinds=()=>{let e=process.version.slice(1).split(".").map(Number);return e.length===3&&e[0]>=9||e[0]===8&&e[1]>=10};Z.isWindows=e=>e&&typeof e.windows=="boolean"?e.windows:kn===!0||$n.sep==="\\";Z.escapeLast=(e,t,r)=>{let n=e.lastIndexOf(t,r);return n===-1?e:e[n-1]==="\\"?Z.escapeLast(e,t,n-1):`${e.slice(0,n)}\\${e.slice(n)}`};Z.removePrefix=(e,t={})=>{let r=e;return r.startsWith("./")&&(r=r.slice(2),t.prefix="./"),r};Z.wrapOutput=(e,t={},r={})=>{let n=r.contains?"":"^",s=r.contains?"":"$",a=`${n}(?:${e})${s}`;return t.negated===!0&&(a=`(?:^(?!${a}).*$)`),a}});var er=K((As,Qt)=>{"use strict";var Xt=be(),{CHAR_ASTERISK:je,CHAR_AT:In,CHAR_BACKWARD_SLASH:_e,CHAR_COMMA:Bn,CHAR_DOT:Fe,CHAR_EXCLAMATION_MARK:Qe,CHAR_FORWARD_SLASH:Zt,CHAR_LEFT_CURLY_BRACE:Xe,CHAR_LEFT_PARENTHESES:Ze,CHAR_LEFT_SQUARE_BRACKET:Mn,CHAR_PLUS:Pn,CHAR_QUESTION_MARK:Yt,CHAR_RIGHT_CURLY_BRACE:Dn,CHAR_RIGHT_PARENTHESES:zt,CHAR_RIGHT_SQUARE_BRACKET:Un}=ye(),Vt=e=>e===Zt||e===_e,Jt=e=>{e.isPrefix!==!0&&(e.depth=e.isGlobstar?Infinity:1)},Gn=(e,t)=>{let r=t||{},n=e.length-1,s=r.parts===!0||r.scanToEnd===!0,a=[],i=[],o=[],h=e,g=-1,f=0,A=0,p=!1,k=!1,y=!1,R=!1,_=!1,x=!1,T=!1,O=!1,W=!1,G=!1,ne=0,E,b,C={value:"",depth:0,isGlob:!1},M=()=>g>=n,l=()=>h.charCodeAt(g+1),H=()=>(E=b,h.charCodeAt(++g));for(;g0&&(j=h.slice(0,f),h=h.slice(f),A-=f),w&&y===!0&&A>0?(w=h.slice(0,A),c=h.slice(A)):y===!0?(w="",c=h):w=h,w&&w!==""&&w!=="/"&&w!==h&&Vt(w.charCodeAt(w.length-1))&&(w=w.slice(0,-1)),r.unescape===!0&&(c&&(c=Xt.removeBackslashes(c)),w&&T===!0&&(w=Xt.removeBackslashes(w)));let u={prefix:j,input:e,start:f,base:w,glob:c,isBrace:p,isBracket:k,isGlob:y,isExtglob:R,isGlobstar:_,negated:O,negatedExtglob:W};if(r.tokens===!0&&(u.maxDepth=0,Vt(b)||i.push(C),u.tokens=i),r.parts===!0||r.tokens===!0){let I;for(let $=0;${"use strict";var Oe=ye(),J=be(),{MAX_LENGTH:Ne,POSIX_REGEX_SOURCE:qn,REGEX_NON_SPECIAL_CHARS:Kn,REGEX_SPECIAL_CHARS_BACKREF:Wn,REPLACEMENTS:rr}=Oe,jn=(e,t)=>{if(typeof t.expandRange=="function")return t.expandRange(...e,t);e.sort();let r=`[${e.join("-")}]`;try{new RegExp(r)}catch(n){return e.map(s=>J.escapeRegex(s)).join("..")}return r},de=(e,t)=>`Missing ${e}: "${t}" - use "\\\\${t}" to match literal characters`,nr=(e,t)=>{if(typeof e!="string")throw new TypeError("Expected a string");e=rr[e]||e;let r=B({},t),n=typeof r.maxLength=="number"?Math.min(Ne,r.maxLength):Ne,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);let a={type:"bos",value:"",output:r.prepend||""},i=[a],o=r.capture?"":"?:",h=J.isWindows(t),g=Oe.globChars(h),f=Oe.extglobChars(g),{DOT_LITERAL:A,PLUS_LITERAL:p,SLASH_LITERAL:k,ONE_CHAR:y,DOTS_SLASH:R,NO_DOT:_,NO_DOT_SLASH:x,NO_DOTS_SLASH:T,QMARK:O,QMARK_NO_DOT:W,STAR:G,START_ANCHOR:ne}=g,E=m=>`(${o}(?:(?!${ne}${m.dot?R:A}).)*?)`,b=r.dot?"":_,C=r.dot?O:W,M=r.bash===!0?E(r):G;r.capture&&(M=`(${M})`),typeof r.noext=="boolean"&&(r.noextglob=r.noext);let l={input:e,index:-1,start:0,dot:r.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:i};e=J.removePrefix(e,l),s=e.length;let H=[],w=[],j=[],c=a,u,I=()=>l.index===s-1,$=l.peek=(m=1)=>e[l.index+m],ee=l.advance=()=>e[++l.index]||"",se=()=>e.slice(l.index+1),z=(m="",L=0)=>{l.consumed+=m,l.index+=L},Ce=m=>{l.output+=m.output!=null?m.output:m.value,z(m.value)},xr=()=>{let m=1;for(;$()==="!"&&($(2)!=="("||$(3)==="?");)ee(),l.start++,m++;return m%2==0?!1:(l.negated=!0,l.start++,!0)},we=m=>{l[m]++,j.push(m)},ue=m=>{l[m]--,j.pop()},v=m=>{if(c.type==="globstar"){let L=l.braces>0&&(m.type==="comma"||m.type==="brace"),d=m.extglob===!0||H.length&&(m.type==="pipe"||m.type==="paren");m.type!=="slash"&&m.type!=="paren"&&!L&&!d&&(l.output=l.output.slice(0,-c.output.length),c.type="star",c.value="*",c.output=M,l.output+=c.output)}if(H.length&&m.type!=="paren"&&(H[H.length-1].inner+=m.value),(m.value||m.output)&&Ce(m),c&&c.type==="text"&&m.type==="text"){c.value+=m.value,c.output=(c.output||"")+m.value;return}m.prev=c,i.push(m),c=m},Se=(m,L)=>{let d=Q(B({},f[L]),{conditions:1,inner:""});d.prev=c,d.parens=l.parens,d.output=l.output;let S=(r.capture?"(":"")+d.open;we("parens"),v({type:m,value:L,output:l.output?"":y}),v({type:"paren",extglob:!0,value:ee(),output:S}),H.push(d)},Cr=m=>{let L=m.close+(r.capture?")":""),d;if(m.type==="negate"){let S=M;m.inner&&m.inner.length>1&&m.inner.includes("/")&&(S=E(r)),(S!==M||I()||/^\)+$/.test(se()))&&(L=m.close=`)$))${S}`),m.inner.includes("*")&&(d=se())&&/^\.[^\\/.]+$/.test(d)&&(L=m.close=`)${d})${S})`),m.prev.type==="bos"&&(l.negatedExtglob=!0)}v({type:"paren",extglob:!0,value:u,output:L}),ue("parens")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(e)){let m=!1,L=e.replace(Wn,(d,S,P,F,q,Me)=>F==="\\"?(m=!0,d):F==="?"?S?S+F+(q?O.repeat(q.length):""):Me===0?C+(q?O.repeat(q.length):""):O.repeat(P.length):F==="."?A.repeat(P.length):F==="*"?S?S+F+(q?M:""):M:S?d:`\\${d}`);return m===!0&&(r.unescape===!0?L=L.replace(/\\/g,""):L=L.replace(/\\+/g,d=>d.length%2==0?"\\\\":d?"\\":"")),L===e&&r.contains===!0?(l.output=e,l):(l.output=J.wrapOutput(L,l,t),l)}for(;!I();){if(u=ee(),u==="\0")continue;if(u==="\\"){let d=$();if(d==="/"&&r.bash!==!0||d==="."||d===";")continue;if(!d){u+="\\",v({type:"text",value:u});continue}let S=/^\\+/.exec(se()),P=0;if(S&&S[0].length>2&&(P=S[0].length,l.index+=P,P%2!=0&&(u+="\\")),r.unescape===!0?u=ee():u+=ee(),l.brackets===0){v({type:"text",value:u});continue}}if(l.brackets>0&&(u!=="]"||c.value==="["||c.value==="[^")){if(r.posix!==!1&&u===":"){let d=c.value.slice(1);if(d.includes("[")&&(c.posix=!0,d.includes(":"))){let S=c.value.lastIndexOf("["),P=c.value.slice(0,S),F=c.value.slice(S+2),q=qn[F];if(q){c.value=P+q,l.backtrack=!0,ee(),!a.output&&i.indexOf(c)===1&&(a.output=y);continue}}}(u==="["&&$()!==":"||u==="-"&&$()==="]")&&(u=`\\${u}`),u==="]"&&(c.value==="["||c.value==="[^")&&(u=`\\${u}`),r.posix===!0&&u==="!"&&c.value==="["&&(u="^"),c.value+=u,Ce({value:u});continue}if(l.quotes===1&&u!=='"'){u=J.escapeRegex(u),c.value+=u,Ce({value:u});continue}if(u==='"'){l.quotes=l.quotes===1?0:1,r.keepQuotes===!0&&v({type:"text",value:u});continue}if(u==="("){we("parens"),v({type:"paren",value:u});continue}if(u===")"){if(l.parens===0&&r.strictBrackets===!0)throw new SyntaxError(de("opening","("));let d=H[H.length-1];if(d&&l.parens===d.parens+1){Cr(H.pop());continue}v({type:"paren",value:u,output:l.parens?")":"\\)"}),ue("parens");continue}if(u==="["){if(r.nobracket===!0||!se().includes("]")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(de("closing","]"));u=`\\${u}`}else we("brackets");v({type:"bracket",value:u});continue}if(u==="]"){if(r.nobracket===!0||c&&c.type==="bracket"&&c.value.length===1){v({type:"text",value:u,output:`\\${u}`});continue}if(l.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(de("opening","["));v({type:"text",value:u,output:`\\${u}`});continue}ue("brackets");let d=c.value.slice(1);if(c.posix!==!0&&d[0]==="^"&&!d.includes("/")&&(u=`/${u}`),c.value+=u,Ce({value:u}),r.literalBrackets===!1||J.hasRegexChars(d))continue;let S=J.escapeRegex(c.value);if(l.output=l.output.slice(0,-c.value.length),r.literalBrackets===!0){l.output+=S,c.value=S;continue}c.value=`(${o}${S}|${c.value})`,l.output+=c.value;continue}if(u==="{"&&r.nobrace!==!0){we("braces");let d={type:"brace",value:u,output:"(",outputIndex:l.output.length,tokensIndex:l.tokens.length};w.push(d),v(d);continue}if(u==="}"){let d=w[w.length-1];if(r.nobrace===!0||!d){v({type:"text",value:u,output:u});continue}let S=")";if(d.dots===!0){let P=i.slice(),F=[];for(let q=P.length-1;q>=0&&(i.pop(),P[q].type!=="brace");q--)P[q].type!=="dots"&&F.unshift(P[q].value);S=jn(F,r),l.backtrack=!0}if(d.comma!==!0&&d.dots!==!0){let P=l.output.slice(0,d.outputIndex),F=l.tokens.slice(d.tokensIndex);d.value=d.output="\\{",u=S="\\}",l.output=P;for(let q of F)l.output+=q.output||q.value}v({type:"brace",value:u,output:S}),ue("braces"),w.pop();continue}if(u==="|"){H.length>0&&H[H.length-1].conditions++,v({type:"text",value:u});continue}if(u===","){let d=u,S=w[w.length-1];S&&j[j.length-1]==="braces"&&(S.comma=!0,d="|"),v({type:"comma",value:u,output:d});continue}if(u==="/"){if(c.type==="dot"&&l.index===l.start+1){l.start=l.index+1,l.consumed="",l.output="",i.pop(),c=a;continue}v({type:"slash",value:u,output:k});continue}if(u==="."){if(l.braces>0&&c.type==="dot"){c.value==="."&&(c.output=A);let d=w[w.length-1];c.type="dots",c.output+=u,c.value+=u,d.dots=!0;continue}if(l.braces+l.parens===0&&c.type!=="bos"&&c.type!=="slash"){v({type:"text",value:u,output:A});continue}v({type:"dot",value:u,output:A});continue}if(u==="?"){if(!(c&&c.value==="(")&&r.noextglob!==!0&&$()==="("&&$(2)!=="?"){Se("qmark",u);continue}if(c&&c.type==="paren"){let S=$(),P=u;if(S==="<"&&!J.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(c.value==="("&&!/[!=<:]/.test(S)||S==="<"&&!/<([!=]|\w+>)/.test(se()))&&(P=`\\${u}`),v({type:"text",value:u,output:P});continue}if(r.dot!==!0&&(c.type==="slash"||c.type==="bos")){v({type:"qmark",value:u,output:W});continue}v({type:"qmark",value:u,output:O});continue}if(u==="!"){if(r.noextglob!==!0&&$()==="("&&($(2)!=="?"||!/[!=<:]/.test($(3)))){Se("negate",u);continue}if(r.nonegate!==!0&&l.index===0){xr();continue}}if(u==="+"){if(r.noextglob!==!0&&$()==="("&&$(2)!=="?"){Se("plus",u);continue}if(c&&c.value==="("||r.regex===!1){v({type:"plus",value:u,output:p});continue}if(c&&(c.type==="bracket"||c.type==="paren"||c.type==="brace")||l.parens>0){v({type:"plus",value:u});continue}v({type:"plus",value:p});continue}if(u==="@"){if(r.noextglob!==!0&&$()==="("&&$(2)!=="?"){v({type:"at",extglob:!0,value:u,output:""});continue}v({type:"text",value:u});continue}if(u!=="*"){(u==="$"||u==="^")&&(u=`\\${u}`);let d=Kn.exec(se());d&&(u+=d[0],l.index+=d[0].length),v({type:"text",value:u});continue}if(c&&(c.type==="globstar"||c.star===!0)){c.type="star",c.star=!0,c.value+=u,c.output=M,l.backtrack=!0,l.globstar=!0,z(u);continue}let m=se();if(r.noextglob!==!0&&/^\([^?]/.test(m)){Se("star",u);continue}if(c.type==="star"){if(r.noglobstar===!0){z(u);continue}let d=c.prev,S=d.prev,P=d.type==="slash"||d.type==="bos",F=S&&(S.type==="star"||S.type==="globstar");if(r.bash===!0&&(!P||m[0]&&m[0]!=="/")){v({type:"star",value:u,output:""});continue}let q=l.braces>0&&(d.type==="comma"||d.type==="brace"),Me=H.length&&(d.type==="pipe"||d.type==="paren");if(!P&&d.type!=="paren"&&!q&&!Me){v({type:"star",value:u,output:""});continue}for(;m.slice(0,3)==="/**";){let ve=e[l.index+4];if(ve&&ve!=="/")break;m=m.slice(3),z("/**",3)}if(d.type==="bos"&&I()){c.type="globstar",c.value+=u,c.output=E(r),l.output=c.output,l.globstar=!0,z(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&!F&&I()){l.output=l.output.slice(0,-(d.output+c.output).length),d.output=`(?:${d.output}`,c.type="globstar",c.output=E(r)+(r.strictSlashes?")":"|$)"),c.value+=u,l.globstar=!0,l.output+=d.output+c.output,z(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&m[0]==="/"){let ve=m[1]!==void 0?"|$":"";l.output=l.output.slice(0,-(d.output+c.output).length),d.output=`(?:${d.output}`,c.type="globstar",c.output=`${E(r)}${k}|${k}${ve})`,c.value+=u,l.output+=d.output+c.output,l.globstar=!0,z(u+ee()),v({type:"slash",value:"/",output:""});continue}if(d.type==="bos"&&m[0]==="/"){c.type="globstar",c.value+=u,c.output=`(?:^|${k}|${E(r)}${k})`,l.output=c.output,l.globstar=!0,z(u+ee()),v({type:"slash",value:"/",output:""});continue}l.output=l.output.slice(0,-c.output.length),c.type="globstar",c.output=E(r),c.value+=u,l.output+=c.output,l.globstar=!0,z(u);continue}let L={type:"star",value:u,output:M};if(r.bash===!0){L.output=".*?",(c.type==="bos"||c.type==="slash")&&(L.output=b+L.output),v(L);continue}if(c&&(c.type==="bracket"||c.type==="paren")&&r.regex===!0){L.output=u,v(L);continue}(l.index===l.start||c.type==="slash"||c.type==="dot")&&(c.type==="dot"?(l.output+=x,c.output+=x):r.dot===!0?(l.output+=T,c.output+=T):(l.output+=b,c.output+=b),$()!=="*"&&(l.output+=y,c.output+=y)),v(L)}for(;l.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(de("closing","]"));l.output=J.escapeLast(l.output,"["),ue("brackets")}for(;l.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(de("closing",")"));l.output=J.escapeLast(l.output,"("),ue("parens")}for(;l.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(de("closing","}"));l.output=J.escapeLast(l.output,"{"),ue("braces")}if(r.strictSlashes!==!0&&(c.type==="star"||c.type==="bracket")&&v({type:"maybe_slash",value:"",output:`${k}?`}),l.backtrack===!0){l.output="";for(let m of l.tokens)l.output+=m.output!=null?m.output:m.value,m.suffix&&(l.output+=m.suffix)}return l};nr.fastpaths=(e,t)=>{let r=B({},t),n=typeof r.maxLength=="number"?Math.min(Ne,r.maxLength):Ne,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);e=rr[e]||e;let a=J.isWindows(t),{DOT_LITERAL:i,SLASH_LITERAL:o,ONE_CHAR:h,DOTS_SLASH:g,NO_DOT:f,NO_DOTS:A,NO_DOTS_SLASH:p,STAR:k,START_ANCHOR:y}=Oe.globChars(a),R=r.dot?A:f,_=r.dot?p:f,x=r.capture?"":"?:",T={negated:!1,prefix:""},O=r.bash===!0?".*?":k;r.capture&&(O=`(${O})`);let W=b=>b.noglobstar===!0?O:`(${x}(?:(?!${y}${b.dot?g:i}).)*?)`,G=b=>{switch(b){case"*":return`${R}${h}${O}`;case".*":return`${i}${h}${O}`;case"*.*":return`${R}${O}${i}${h}${O}`;case"*/*":return`${R}${O}${o}${h}${_}${O}`;case"**":return R+W(r);case"**/*":return`(?:${R}${W(r)}${o})?${_}${h}${O}`;case"**/*.*":return`(?:${R}${W(r)}${o})?${_}${O}${i}${h}${O}`;case"**/.*":return`(?:${R}${W(r)}${o})?${i}${h}${O}`;default:{let C=/^(.*?)\.(\w+)$/.exec(b);if(!C)return;let M=G(C[1]);return M?M+i+C[2]:void 0}}},ne=J.removePrefix(e,T),E=G(ne);return E&&r.strictSlashes!==!0&&(E+=`${o}?`),E};tr.exports=nr});var ir=K((ys,ar)=>{"use strict";var Fn=require("path"),Qn=er(),Ye=sr(),ze=be(),Xn=ye(),Zn=e=>e&&typeof e=="object"&&!Array.isArray(e),D=(e,t,r=!1)=>{if(Array.isArray(e)){let f=e.map(p=>D(p,t,r));return p=>{for(let k of f){let y=k(p);if(y)return y}return!1}}let n=Zn(e)&&e.tokens&&e.input;if(e===""||typeof e!="string"&&!n)throw new TypeError("Expected pattern to be a non-empty string");let s=t||{},a=ze.isWindows(t),i=n?D.compileRe(e,t):D.makeRe(e,t,!1,!0),o=i.state;delete i.state;let h=()=>!1;if(s.ignore){let f=Q(B({},t),{ignore:null,onMatch:null,onResult:null});h=D(s.ignore,f,r)}let g=(f,A=!1)=>{let{isMatch:p,match:k,output:y}=D.test(f,i,t,{glob:e,posix:a}),R={glob:e,state:o,regex:i,posix:a,input:f,output:y,match:k,isMatch:p};return typeof s.onResult=="function"&&s.onResult(R),p===!1?(R.isMatch=!1,A?R:!1):h(f)?(typeof s.onIgnore=="function"&&s.onIgnore(R),R.isMatch=!1,A?R:!1):(typeof s.onMatch=="function"&&s.onMatch(R),A?R:!0)};return r&&(g.state=o),g};D.test=(e,t,r,{glob:n,posix:s}={})=>{if(typeof e!="string")throw new TypeError("Expected input to be a string");if(e==="")return{isMatch:!1,output:""};let a=r||{},i=a.format||(s?ze.toPosixSlashes:null),o=e===n,h=o&&i?i(e):e;return o===!1&&(h=i?i(e):e,o=h===n),(o===!1||a.capture===!0)&&(a.matchBase===!0||a.basename===!0?o=D.matchBase(e,t,r,s):o=t.exec(h)),{isMatch:Boolean(o),match:o,output:h}};D.matchBase=(e,t,r,n=ze.isWindows(r))=>(t instanceof RegExp?t:D.makeRe(t,r)).test(Fn.basename(e));D.isMatch=(e,t,r)=>D(t,r)(e);D.parse=(e,t)=>Array.isArray(e)?e.map(r=>D.parse(r,t)):Ye(e,Q(B({},t),{fastpaths:!1}));D.scan=(e,t)=>Qn(e,t);D.compileRe=(e,t,r=!1,n=!1)=>{if(r===!0)return e.output;let s=t||{},a=s.contains?"":"^",i=s.contains?"":"$",o=`${a}(?:${e.output})${i}`;e&&e.negated===!0&&(o=`^(?!${o}).*$`);let h=D.toRegex(o,t);return n===!0&&(h.state=e),h};D.makeRe=(e,t={},r=!1,n=!1)=>{if(!e||typeof e!="string")throw new TypeError("Expected a non-empty string");let s={negated:!1,fastpaths:!0};return t.fastpaths!==!1&&(e[0]==="."||e[0]==="*")&&(s.output=Ye.fastpaths(e,t)),s.output||(s=Ye(e,t)),D.compileRe(s,t,r,n)};D.toRegex=(e,t)=>{try{let r=t||{};return new RegExp(e,r.flags||(r.nocase?"i":""))}catch(r){if(t&&t.debug===!0)throw r;return/$^/}};D.constants=Xn;ar.exports=D});var cr=K((bs,or)=>{"use strict";or.exports=ir()});var hr=K((_s,ur)=>{"use strict";var lr=require("util"),pr=Gt(),oe=cr(),Ve=be(),fr=e=>e===""||e==="./",N=(e,t,r)=>{t=[].concat(t),e=[].concat(e);let n=new Set,s=new Set,a=new Set,i=0,o=f=>{a.add(f.output),r&&r.onResult&&r.onResult(f)};for(let f=0;f!n.has(f));if(r&&g.length===0){if(r.failglob===!0)throw new Error(`No matches found for "${t.join(", ")}"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?t.map(f=>f.replace(/\\/g,"")):t}return g};N.match=N;N.matcher=(e,t)=>oe(e,t);N.isMatch=(e,t,r)=>oe(t,r)(e);N.any=N.isMatch;N.not=(e,t,r={})=>{t=[].concat(t).map(String);let n=new Set,s=[],a=o=>{r.onResult&&r.onResult(o),s.push(o.output)},i=N(e,t,Q(B({},r),{onResult:a}));for(let o of s)i.includes(o)||n.add(o);return[...n]};N.contains=(e,t,r)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${lr.inspect(e)}"`);if(Array.isArray(t))return t.some(n=>N.contains(e,n,r));if(typeof t=="string"){if(fr(e)||fr(t))return!1;if(e.includes(t)||e.startsWith("./")&&e.slice(2).includes(t))return!0}return N.isMatch(e,t,Q(B({},r),{contains:!0}))};N.matchKeys=(e,t,r)=>{if(!Ve.isObject(e))throw new TypeError("Expected the first argument to be an object");let n=N(Object.keys(e),t,r),s={};for(let a of n)s[a]=e[a];return s};N.some=(e,t,r)=>{let n=[].concat(e);for(let s of[].concat(t)){let a=oe(String(s),r);if(n.some(i=>a(i)))return!0}return!1};N.every=(e,t,r)=>{let n=[].concat(e);for(let s of[].concat(t)){let a=oe(String(s),r);if(!n.every(i=>a(i)))return!1}return!0};N.all=(e,t,r)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${lr.inspect(e)}"`);return[].concat(t).every(n=>oe(n,r)(e))};N.capture=(e,t,r)=>{let n=Ve.isWindows(r),a=oe.makeRe(String(e),Q(B({},r),{capture:!0})).exec(n?Ve.toPosixSlashes(t):t);if(a)return a.slice(1).map(i=>i===void 0?"":i)};N.makeRe=(...e)=>oe.makeRe(...e);N.scan=(...e)=>oe.scan(...e);N.parse=(e,t)=>{let r=[];for(let n of[].concat(e||[]))for(let s of pr(String(n),t))r.push(oe.parse(s,t));return r};N.braces=(e,t)=>{if(typeof e!="string")throw new TypeError("Expected a string");return t&&t.nobrace===!0||!/\{.*\}/.test(e)?[e]:pr(e,t)};N.braceExpand=(e,t)=>{if(typeof e!="string")throw new TypeError("Expected a string");return N.braces(e,Q(B({},t),{expand:!0}))};ur.exports=N});var gr=K((Es,dr)=>{"use strict";dr.exports=(e,...t)=>new Promise(r=>{r(e(...t))})});var Ar=K((xs,Je)=>{"use strict";var Yn=gr(),mr=e=>{if(e<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let t=[],r=0,n=()=>{r--,t.length>0&&t.shift()()},s=(o,h,...g)=>{r++;let f=Yn(o,...g);h(f),f.then(n,n)},a=(o,h,...g)=>{rnew Promise(g=>a(o,g,...h));return Object.defineProperties(i,{activeCount:{get:()=>r},pendingCount:{get:()=>t.length}}),i};Je.exports=mr;Je.exports.default=mr});var Vn={};Or(Vn,{default:()=>es});var He=X(require("@yarnpkg/cli")),ae=X(require("@yarnpkg/core")),nt=X(require("@yarnpkg/core")),le=X(require("clipanion")),Ae=class extends He.BaseCommand{constructor(){super(...arguments);this.json=le.Option.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=le.Option.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=le.Option.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=le.Option.Rest()}async execute(){let t=await ae.Configuration.find(this.context.cwd,this.context.plugins),{project:r,workspace:n}=await ae.Project.find(t,this.context.cwd),s=await ae.Cache.find(t);await r.restoreInstallState({restoreResolutions:!1});let a;if(this.all)a=new Set(r.workspaces);else if(this.workspaces.length===0){if(!n)throw new He.WorkspaceRequiredError(r.cwd,this.context.cwd);a=new Set([n])}else a=new Set(this.workspaces.map(o=>r.getWorkspaceByIdent(nt.structUtils.parseIdent(o))));for(let o of a)for(let h of this.production?["dependencies"]:ae.Manifest.hardDependencies)for(let g of o.manifest.getForScope(h).values()){let f=r.tryWorkspaceByDescriptor(g);f!==null&&a.add(f)}for(let o of r.workspaces)a.has(o)?this.production&&o.manifest.devDependencies.clear():(o.manifest.installConfig=o.manifest.installConfig||{},o.manifest.installConfig.selfReferences=!1,o.manifest.dependencies.clear(),o.manifest.devDependencies.clear(),o.manifest.peerDependencies.clear(),o.manifest.scripts.clear());return(await ae.StreamReport.start({configuration:t,json:this.json,stdout:this.context.stdout,includeLogs:!0},async o=>{await r.install({cache:s,report:o,persistProject:!1})})).exitCode()}};Ae.paths=[["workspaces","focus"]],Ae.usage=le.Command.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});var st=Ae;var Ie=X(require("@yarnpkg/cli")),ge=X(require("@yarnpkg/core")),Ee=X(require("@yarnpkg/core")),Y=X(require("@yarnpkg/core")),Rr=X(require("@yarnpkg/plugin-git")),U=X(require("clipanion")),Be=X(hr()),yr=X(require("os")),br=X(Ar()),re=X(require("typanion")),xe=class extends Ie.BaseCommand{constructor(){super(...arguments);this.recursive=U.Option.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.from=U.Option.Array("--from",[],{description:"An array of glob pattern idents from which to base any recursion"});this.all=U.Option.Boolean("-A,--all",!1,{description:"Run the command on all workspaces of a project"});this.verbose=U.Option.Boolean("-v,--verbose",!1,{description:"Prefix each output line with the name of the originating workspace"});this.parallel=U.Option.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=U.Option.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=U.Option.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:re.isOneOf([re.isEnum(["unlimited"]),re.applyCascade(re.isNumber(),[re.isInteger(),re.isAtLeast(1)])])});this.topological=U.Option.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=U.Option.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=U.Option.Array("--include",[],{description:"An array of glob pattern idents; only matching workspaces will be traversed"});this.exclude=U.Option.Array("--exclude",[],{description:"An array of glob pattern idents; matching workspaces won't be traversed"});this.publicOnly=U.Option.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=U.Option.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.commandName=U.Option.String();this.args=U.Option.Proxy()}async execute(){let t=await ge.Configuration.find(this.context.cwd,this.context.plugins),{project:r,workspace:n}=await ge.Project.find(t,this.context.cwd);if(!this.all&&!n)throw new Ie.WorkspaceRequiredError(r.cwd,this.context.cwd);await r.restoreInstallState();let s=this.cli.process([this.commandName,...this.args]),a=s.path.length===1&&s.path[0]==="run"&&typeof s.scriptName!="undefined"?s.scriptName:null;if(s.path.length===0)throw new U.UsageError("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let i=this.all?r.topLevelWorkspace:n,o=this.since?Array.from(await Rr.gitUtils.fetchChangedWorkspaces({ref:this.since,project:r})):[i,...this.from.length>0?i.getRecursiveWorkspaceChildren():[]],h=E=>Be.default.isMatch(Y.structUtils.stringifyIdent(E.locator),this.from),g=this.from.length>0?o.filter(h):o,f=new Set([...g,...g.map(E=>[...this.recursive?this.since?E.getRecursiveWorkspaceDependents():E.getRecursiveWorkspaceDependencies():E.getRecursiveWorkspaceChildren()]).flat()]),A=[],p=!1;if(a==null?void 0:a.includes(":")){for(let E of r.workspaces)if(E.manifest.scripts.has(a)&&(p=!p,p===!1))break}for(let E of f)a&&!E.manifest.scripts.has(a)&&!p&&!(await ge.scriptUtils.getWorkspaceAccessibleBinaries(E)).has(a)||a===process.env.npm_lifecycle_event&&E.cwd===n.cwd||this.include.length>0&&!Be.default.isMatch(Y.structUtils.stringifyIdent(E.locator),this.include)||this.exclude.length>0&&Be.default.isMatch(Y.structUtils.stringifyIdent(E.locator),this.exclude)||this.publicOnly&&E.manifest.private===!0||A.push(E);let k=this.parallel?this.jobs==="unlimited"?Infinity:this.jobs||Math.max(1,(0,yr.cpus)().length/2):1,y=k===1?!1:this.parallel,R=y?this.interlaced:!0,_=(0,br.default)(k),x=new Map,T=new Set,O=0,W=null,G=!1,ne=await Ee.StreamReport.start({configuration:t,stdout:this.context.stdout},async E=>{let b=async(C,{commandIndex:M})=>{if(G)return-1;!y&&this.verbose&&M>1&&E.reportSeparator();let l=zn(C,{configuration:t,verbose:this.verbose,commandIndex:M}),[H,w]=_r(E,{prefix:l,interlaced:R}),[j,c]=_r(E,{prefix:l,interlaced:R});try{this.verbose&&E.reportInfo(null,`${l} Process started`);let u=Date.now(),I=await this.cli.run([this.commandName,...this.args],{cwd:C.cwd,stdout:H,stderr:j})||0;H.end(),j.end(),await w,await c;let $=Date.now();if(this.verbose){let ee=t.get("enableTimers")?`, completed in ${Y.formatUtils.pretty(t,$-u,Y.formatUtils.Type.DURATION)}`:"";E.reportInfo(null,`${l} Process exited (exit code ${I})${ee}`)}return I===130&&(G=!0,W=I),I}catch(u){throw H.end(),j.end(),await w,await c,u}};for(let C of A)x.set(C.anchoredLocator.locatorHash,C);for(;x.size>0&&!E.hasErrors();){let C=[];for(let[H,w]of x){if(T.has(w.anchoredDescriptor.descriptorHash))continue;let j=!0;if(this.topological||this.topologicalDev){let c=this.topologicalDev?new Map([...w.manifest.dependencies,...w.manifest.devDependencies]):w.manifest.dependencies;for(let u of c.values()){let I=r.tryWorkspaceByDescriptor(u);if(j=I===null||!x.has(I.anchoredLocator.locatorHash),!j)break}}if(!!j&&(T.add(w.anchoredDescriptor.descriptorHash),C.push(_(async()=>{let c=await b(w,{commandIndex:++O});return x.delete(H),T.delete(w.anchoredDescriptor.descriptorHash),c})),!y))break}if(C.length===0){let H=Array.from(x.values()).map(w=>Y.structUtils.prettyLocator(t,w.anchoredLocator)).join(", ");E.reportError(Ee.MessageName.CYCLIC_DEPENDENCIES,`Dependency cycle detected (${H})`);return}let l=(await Promise.all(C)).find(H=>H!==0);W===null&&(W=typeof l!="undefined"?1:W),(this.topological||this.topologicalDev)&&typeof l!="undefined"&&E.reportError(Ee.MessageName.UNNAMED,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return W!==null?W:ne.exitCode()}};xe.paths=[["workspaces","foreach"]],xe.usage=U.Command.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project. By default yarn runs the command only on current and all its descendant workspaces.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n Adding the `-v,--verbose` flag will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish current and all descendant packages","yarn workspaces foreach npm publish --tolerate-republish"],["Run build script on current and all descendant packages","yarn workspaces foreach run build"],["Run build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -pt run build"],["Run build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -ptR --from '{workspace-a,workspace-b}' run build"]]});var Er=xe;function _r(e,{prefix:t,interlaced:r}){let n=e.createStreamReporter(t),s=new Y.miscUtils.DefaultStream;s.pipe(n,{end:!1}),s.on("finish",()=>{n.end()});let a=new Promise(o=>{n.on("finish",()=>{o(s.active)})});if(r)return[s,a];let i=new Y.miscUtils.BufferStream;return i.pipe(s,{end:!1}),i.on("finish",()=>{s.end()}),[i,a]}function zn(e,{configuration:t,commandIndex:r,verbose:n}){if(!n)return null;let s=Y.structUtils.convertToIdent(e.locator),i=`[${Y.structUtils.stringifyIdent(s)}]:`,o=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],h=o[r%o.length];return Y.formatUtils.pretty(t,i,h)}var Jn={commands:[st,Er]},es=Jn;return Vn;})(); -/*! - * fill-range - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. - */ -/*! - * is-number - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. - */ -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ -return plugin; -} -}; diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 98b7b0dde..000000000 --- a/.yarnrc.yml +++ /dev/null @@ -1,30 +0,0 @@ -httpTimeout: 600000 - -nmHoistingLimits: none - -nodeLinker: pnpm - -packageExtensions: - "@bull-board/api@*": - peerDependencies: - "@bull-board/ui": "*" - chartjs-adapter-date-fns@*: - peerDependencies: - date-fns: "*" - swiper@*: - peerDependencies: - vue: "*" - consolidate@*: - dependencies: - ejs: "*" - koa-views@*: - dependencies: - pug: "*" - -plugins: - - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs - spec: "@yarnpkg/plugin-interactive-tools" - - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - spec: "@yarnpkg/plugin-workspace-tools" - -progressBarStyle: patrick diff --git a/CALCKEY.md b/CALCKEY.md index 4371d5abd..015232f70 100644 --- a/CALCKEY.md +++ b/CALCKEY.md @@ -41,7 +41,7 @@ ## Implemented - A lot of general bugfixes -- Yarn 3 +- pnpm instead of yarn - Fix Dockerfile @hanna - Upgrade packages with security vunrabilities - Saner defaults @@ -101,6 +101,13 @@ - Obliteration of Ai-chan - Switch to [Calckey.js](https://codeberg.org/calckey/calckey.js) - Woozy mode 🥴 +- Improve blocking instances +- Release notes +- New post style +- Admins set default reaction emoji + - Allows custom emoji +- Fix lint errors +- Use Rome instead of ESLint - MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1) - [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996) - [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..da0597bb3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,338 @@ +# Changelog + +All changes from v13.0.0 onwards, for a full list of differences read [CALCKEY.md](./CALCKEY.md) + +## [13.0.6-rc] - 2023-01-04 + +### Bug Fixes + +- Prevent notifications if the notification contains a note that is muted + +- Fix padding on normal display + +- Fix: Cliff design + +- Fix: user view z-fighting + +- Fix: overlapping user follow button in mobile view + +- Fix: Add .js to the end of two type-scripts, fixing a critical error that crashes calckey ([#9347](https://github.com/orhun/git-cliff/issues/9347)) + + +### Features + +- New post style + +- Add antenna mark read functionality + +- Automatic changelog generation using git cliffy + + +### Miscellaneous Tasks + +- Update yarn + +- Chore: bump version number + +- Chore: upgrade packages + +- Chore: up pkgs + +- Chore: deprecate `deckDivider` + + +## [13.0.5] - 2022-12-18 + +### Bug Fixes + +- Fix typo + +- Fix-docker-env-path ([#9241](https://github.com/orhun/git-cliff/issues/9241)) + +- Fix: use correct color for MkMoved + +- Fixed additional path to .config + + +### Documentation + +- more badges + +- weblate + +- Docker-compose-port-fix ([#9251](https://github.com/orhun/git-cliff/issues/9251)) + + +### Features + +- weblate + +- upgrade to vite 4 + + +### Miscellaneous Tasks + +- Update example.yml with container names specified in docker-compose, to support running either a dev or production containers off the same configs + +- Chore: lint + +- Chore: dockerfile cleanup + +- Chore: Update patron list + +- Chore: remove unicode fault in KO + +- Chore: update gitignore + +- Chore: fix rebuild + + +### Refactor + +- Refactor: :busts_in_silhouette: update cleo link + +- Refactor: new repo link + + +### Testing + +- Test: 🥴 + +## [13.0.3] - 2022-12-16 + +### Bug Fixes + +- Fix: 🐛 fix inconsistent theming + +- Fix: css class match + +- Fix: insert into correct textarea + + +### Documentation + +- Docs: :memo: fix badge position + + +### Features + +- Feat: Insert text at cursor for caption + + +### Refactor + +- Refactor: rm .github folder + + +## [13.0.0] - 2022-12-16 + +## [13-rc1] - 2022-12-16 + +### Bug Fixes + + +- Fix: messaging pagination + +- Fix groups button display + +- Fix scroll anim bug + +- Fix pinned users list + +- Fix: workaround for sticky image container header + +- Fix pages swiping + +- Fix pages margin + +- Fix user profile + +- Fix fill out profile step of tutorial + +- Fix: :bug: fix image size in dms + +- Fix: actually set in-dm to be true if in dm + +- Fix: don't do icon transform by default + +- Fix problems from #9146 + +- Fix more icons + +- Fix remote move queue + +- Fix import + +- Fix path + +- Fix liked pages + +- Fix liked pages endpoint + +- Fix remote move queue + +- Fix path + +- Fix unicode weirdness + +- Fix: call functions properly + +- Fix viewing basic federaion info + +- Fix: migration labels + +- Fix ckjs + +- Fix locale + +- Fix alsoKnownAs federation + +- Fix redis in ci + +- Fix federation of moved to to pleroma +because it expects it to be non-existant if its null. + +- Fix docker ci + + +### Documentation + +- Docs: :memo: deps + +- Docs: :memo: typo + +- Docs: :memo: latest 18 + +- Docs: 📝 pm2 + +- Docs: more accessible links + +- Docs: move intro to wip + +- Docs: :memo: intro tutorial + +- Docs: 📝 tips & tricks + +- Docs: fix typo + +- Docs: tips + +- Docs: :memo: improve documentation, nginx + +- Docs: :memo: tip + +- Docs: :memo: open port tip + +- Docs: 📝 alt text for calc + +- Docs: 📝 typo + +It's "available". Thank you luke :P + +- Docs: 📝 typo + +- Docs: 📝 official account + +- Docs: another tip + +- Docs: 📝 improve install instructions + +- Docs: 📝 formatting + +- Docs: 📝 optional deps + +- Docs: custom locales + +- Docs: a11y + +- Docs: reflect last change in readme + +- Docs: deps + +- Docs: 📝 better links + +- Docs: 📝 be more descriptive with new techs + +- Docs: 📝 scylla will be optional + +- Docs: 📝 better links + +- Docs: 📝 be more descriptive with new techs + +- Docs: 📝 scylla will be optional + +- Docs: 📝 account migration + + +### Features + +- Feat: :art: move reaction button + +- Feat: :sparkles: Star button + +- Feat: :art: add ripple to star react + +- Feat: :art: add ripple to star react + +- Feat: :sparkles: Toggle showing calckey updates as admin + +- Feat: ✨ add `os.yesno` for yes/no questions + +- Feat: :lipstick: add right margin to title text + +- Feat: :sparkles: Allow importing follows from Pixelfed + +- Feat: ✨ Append caption to textarea + +- Feat: :sparkles: Managed hosting complete + +- Feat: :lipstick: Phosphor icons! + +- Feat: :lipstick: Phosphor icons! + +- Add effects, japanese translation + +- Feat: ✨ Page drafts + +- Feat: Docker update script ([#9159](https://github.com/orhun/git-cliff/issues/9159)) + +- Feat: Docker update script ([#9159](https://github.com/orhun/git-cliff/issues/9159)) + +- Feat: :sparkles: Add delete all lists + +- Add local move follower migration + +- Feat: customizable max note length + +- Add check for already moved + + +### Miscellaneous Tasks + +- Chore: :package: Update packages + +- Update example + +- Update deps + +- Chore: :package: package upgrades + +- Chore: :arrow_up: update deps + +- Chore: :arrow_up: upgrade packages + +- Chore: :arrow_up: yarn 3.3.0 + +- Update person model + + +### Performance + +- Perf: :zap: load icons css last + + +### Refactor + +- Refactor: :alembic: try `active-class` + +- Refactor: :recycle: Replace all `$ts` with i18n diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 541cc98df..f824432e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,10 @@ # Contribution guide We're glad you're interested in contributing Calckey! In this document you will find the information you need to contribute to the project. -# Translations +## Localization (l10n) +Calckey uses [Weblate](hhttps://hosted.weblate.org/engage/calckey/) for localization management. + +If your language is not listed in Weblate, please open an issue. You can contribute without knowing how to code by helping translate here: @@ -10,14 +13,14 @@ You can contribute without knowing how to code by helping translate here: [![Translation bars](https://hosted.weblate.org/widgets/calckey/-/multi-auto.svg)](https://hosted.weblate.org/engage/calckey/) ## Roadmap -See [ROADMAP.md](./ROADMAP.md) +See [CALCKEY.md](./CALCKEY.md) ## Issues Before creating an issue, please check the following: - To avoid duplication, please search for similar issues before creating a new issue. - Do not use Issues to ask questions or troubleshooting. - Issues should only be used to feature requests, suggestions, and bug tracking. - - Please ask questions or troubleshooting in the [Misskey Forum](https://forum.misskey.io/) or [Discord](https://discord.gg/Wp8gVStHW3). + - Please ask questions or troubleshooting in the [Matrix room](https://matrix.to/#/#calckey:matrix.fedibird.com). > **Warning** > Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged. @@ -31,22 +34,22 @@ PRs that do not have a clear set of do's and don'ts tend to be bloated and diffi Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask another member to assign you). By expressing your intention to work the Issue, you can prevent conflicts in the work. ## Well-known branches -- **`master`** branch is tracking the latest release and used for production purposes. -- **`develop`** branch is where we work for the next release. - - When you create a PR, basically target it to this branch. -- **`l10n_develop`** branch is reserved for localization management. +- The **`main`** branch is tracking the latest release and used for production purposes. +- The **`develop`** branch is where we work for the next release. + - When you create a PR, basically target it to this branch. **But create a different branch** +- The **`l10n_develop`** branch is reserved for localization management. +- **`feature/*`** branches are reserved for the development of a specific feature ## Creating a PR Thank you for your PR! Before creating a PR, please check the following: - If possible, prefix the title with a keyword that identifies the type of this PR, as shown below. - - `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc + - `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc. You are also welcome to use gitmoji. This is important as we use these to A) easier read the git history and B) generate our changelog. Without propper prefixing it is possible that your PR is rejected. - Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR. -- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text. -- Please add the summary of the changes to [`CHANGELOG.md`](/CHANGELOG.md). However, this is not necessary for changes that do not affect the users, such as refactoring. +- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text. Good examples include `Closing: #21` or `Resolves: #21` - Check if there are any documents that need to be created or updated due to this change. - If you have added a feature or fixed a bug, please add a test case if possible. - Please make sure that tests and Lint are passed in advance. - - You can run it with `yarn test` and `yarn lint`. [See more info](#testing) + - You can run it with `pnpm run test` and `pnpm run lint`. [See more info](#testing) - If this PR includes UI changes, please attach a screenshot in the text. Thanks for your cooperation 🤗 @@ -68,7 +71,7 @@ Be willing to comment on the good points and not just the things you want fixed - Are there any omissions or gaps? - Does it check for anomalies? -## Deploy +## Deploy (SOON) The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment. ``` /deploy sha= @@ -90,21 +93,14 @@ An actual domain will be assigned so you can test the federation. - The target branch must be `master` - The tag name must be the version -## Localization (l10n) -Misskey uses [Crowdin](https://crowdin.com/project/misskey) for localization management. -You can improve our translations with your Crowdin account. -Your changes in Crowdin are automatically submitted as a PR (with the title "New Crowdin translations") to the repository. -The owner [@syuilo](https://github.com/syuilo) merges the PR into the develop branch before the next release. - -If your language is not listed in Crowdin, please open an issue. - -![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg) - ## Development During development, it is useful to use the `yarn dev` command. This command monitors the server-side and client-side source files and automatically builds them if they are modified. In addition, it will also automatically start the Misskey server process. + +# THE FOLLOWING IS OUTDATED: + ## Testing - Test codes are located in [`/test`](/test). @@ -259,7 +255,7 @@ MongoDBは`null`で返してきてたので、その感覚で`if (x === null)` ### Migration作成方法 packages/backendで: ```sh -yarn dlx typeorm migration:generate -d ormconfig.js -o +pnpm dlx typeorm migration:generate -d ormconfig.js -o ``` - 生成後、ファイルをmigration下に移してください diff --git a/Dockerfile b/Dockerfile index b0ffa9904..4df93d1cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ -FROM node:18-alpine -ENV YARN_CHECKSUM_BEHAVIOR=update +FROM node:19-alpine ARG NODE_ENV=production WORKDIR /calckey @@ -10,17 +9,17 @@ COPY . ./ RUN apk update RUN apk add git ffmpeg tini alpine-sdk python3 -# Configure corepack and yarn +# Configure corepack and pnpm RUN corepack enable -RUN yarn set version berry -RUN yarn plugin import workspace-tools +RUN corepack prepare pnpm@latest --activate +RUN pnpm i --frozen-lockfile +ARG NODE_ENV=production -# Install Dependencies -RUN yarn install -RUN yarn run build +# Build project (pnp dependencies are installed) +RUN pnpm run build # Remove git files RUN rm -rf .git ENTRYPOINT [ "/sbin/tini", "--" ] -CMD [ "yarn", "run", "migrateandstart" ] +CMD [ "pnpm", "run", "migrateandstart" ] diff --git a/README.md b/README.md index 9b2afab26..d15d2fa94 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,13 @@ **🌎 **[Calckey](https://i.calckey.cloud/)** is an open source, decentralized social media platform that's free forever! 🚀** -[![status-badge](https://ci.codeberg.org/api/badges/calckey/calckey/status.svg)](https://ci.codeberg.org/calckey/calckey) -[![liberapay-badge](https://img.shields.io/liberapay/receives/ThatOneCalculator?logo=liberapay)](https://liberapay.com/ThatOneCalculator) +[![no github badge](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page/) +[![status badge](https://ci.codeberg.org/api/badges/calckey/calckey/status.svg)](https://ci.codeberg.org/calckey/calckey) +[![liberapay badge](https://img.shields.io/liberapay/receives/ThatOneCalculator?logo=liberapay)](https://liberapay.com/ThatOneCalculator) [![translate-badge](https://hosted.weblate.org/widgets/calckey/-/svg-badge.svg)](https://hosted.weblate.org/engage/calckey/) -[![docker-badge](https://img.shields.io/docker/pulls/thatonecalculator/calckey?logo=docker)](https://hub.docker.com/r/thatonecalculator/calckey) -[![codeberg-badge](https://custom-icon-badges.demolab.com/badge/hosted%20on-codeberg-blue.svg?logo=codeberg&logoColor=white)](https://codeberg.org/calckey/calckey/) +[![docker badge](https://img.shields.io/docker/pulls/thatonecalculator/calckey?logo=docker)](https://hub.docker.com/r/thatonecalculator/calckey) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](./CODE_OF_CONDUCT.md) +[![lavaforge badge](https://custom-icon-badges.demolab.com/badge/hosted%20on-lavaforge-FF8066.svg?logo=lavaforge&logoColor=white)](https://codeberg.org/calckey/calckey/) @@ -50,12 +52,23 @@ - 📖 JoinFediverse Wiki: - 🐋 Docker Hub: - ✍️ Weblate: +- 📦 Yunohost: # 🌠 Getting started This guide will work for both **starting from scratch** and **migrating from Misskey**. -## 📦 Dependencies +## 🔰 Easy installers + +If you have access to a server that supports one of the sources below, I recommend you use it! Note that these methods *won't* allow you to migrate from Misskey without manual intervention. + +[![Install on Ubuntu](https://pool.jortage.com/voringme/misskey/3b62a443-1b44-45cf-8f9e-f1c588f803ed.png)](https://codeberg.org/calckey/ubuntu-bash-install)  [![Install on the Arch User Repository](https://pool.jortage.com/voringme/misskey/ba2a5c07-f078-43f1-8483-2e01acca9c40.png)](https://aur.archlinux.org/packages/calckey)  [![Install Calckey with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=calckey) + +### 🐋 Docker + +[How to run Calckey with Docker](./docker-README.md). + +## 🧑‍💻 Dependencies - 🐢 At least [NodeJS](https://nodejs.org/en/) v18.12.1 (v19 recommended) - Install with [nvm](https://github.com/nvm-sh/nvm) @@ -82,7 +95,7 @@ This guide will work for both **starting from scratch** and **migrating from Mis ## 👀 Get folder ready ```sh -git clone https://codeberg.org/calckey/calckey.git +git clone --depth 1 https://codeberg.org/calckey/calckey.git cd calckey/ # git checkout main # if you want only stable versions ``` @@ -90,8 +103,11 @@ cd calckey/ ## 📩 Install dependencies ```sh -# nvm install 18 && nvm alias default 18 && nvm use 18 +# nvm install 19 && nvm use 19 corepack enable +corepack prepare pnpm@latest --activate +# To build without TensorFlow, append --no-optional +pnpm i # --no-optional ``` ## 🐘 Create database @@ -107,7 +123,7 @@ psql postgres -c "create database calckey with encoding = 'UTF8';" - To add custom CSS for all users, edit `./custom/assets/instance.css`. - To add static assets (such as images for the splash screen), place them in the `./custom/assets/` directory. They'll then be available on `https://yourinstance.tld/static-assets/filename.ext`. - To add custom locales, place them in the `./custom/locales/` directory. If you name your custom locale the same as an existing locale, it will overwrite it. If you give it a unique name, it will be added to the list. Also make sure that the first part of the filename matches the locale you're basing it on. (Example: `en-FOO.yml`) -- To update custom assets without rebuilding, just run `yarn run gulp`. +- To update custom assets without rebuilding, just run `pnpm run gulp`. ## 🧑‍🔬 Configuring a new instance @@ -121,7 +137,7 @@ psql postgres -c "create database calckey with encoding = 'UTF8';" ```sh cp ../misskey/.config/default.yml ./.config/default.yml # replace `../misskey/` with misskey path, add `docker.env` if you use Docker -cp -r ../misskey/files . # if you don't use object storage +cp -r ../misskey/files . ``` ## 🍀 NGINX @@ -141,22 +157,17 @@ cp -r ../misskey/files . # if you don't use object storage ```sh # git pull -yarn install -NODE_ENV=production yarn run rebuild && yarn run migrate -pm2 start "NODE_ENV=production yarn start" --name Calckey +NODE_ENV=production pnpm install && pnpm run build && pnpm run migrate +pm2 start "NODE_ENV=production pnpm run start" --name Calckey ``` -### 🐋 Docker - -[How to run Calckey with Docker](./docker-README.md). - ## 😉 Tips & Tricks - When editing the config file, please don't fill out the settings at the bottom. They're designed *only* for managed hosting, not self hosting. Those settings are much better off being set in Calckey's control panel. -- Port 3000 (used in the default config) might be already used on your server for something else. To find an open port for Calckey, run `for p in $(seq 3000 4000); do ss -tlnH | tr -s ' ' | cut -d" " -sf4 | grep -q "${p}$" || echo "${p}"; done | head -n 1` +- Port 3000 (used in the default config) might be already used on your server for something else. To find an open port for Calckey, run `for p in {3000..4000}; do ss -tlnH | tr -s ' ' | cut -d" " -sf4 | grep -q "${p}$" || echo "${p}"; done | head -n 1`. Replace 3000 with the minimum port and 4000 with the maximum port if you need it. - I'd recommend you use a S3 Bucket/CDN for Object Storage, especially if you use Docker. - I'd ***strongly*** recommend against using CloudFlare, but if you do, make sure to turn code minification off. -- For push notifications, run `npx web-push generate-vapid-keys`, the put the public and private keys into Control Panel > General > ServiceWorker. +- For push notifications, run `npx web-push generate-vapid-keys`, then put the public and private keys into Control Panel > General > ServiceWorker. - For translations, make a [DeepL](https://deepl.com) account and generate an API key, then put it into Control Panel > General > DeepL Translation. - To add another admin account: - Go to the user's page > 3 Dots > About > Moderation > turn on "Moderator" diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 000000000..394b84577 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,103 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +# changelog header +header = """ +# Changelog\n +All changes from v13.0.0 onwards, for a full list of differences read CALCKEY.md\n +""" +# template for the changelog body +# https://tera.netlify.app/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | upper_first }} + {% for commit in commits %} + - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\ + {% endfor %} +{% endfor %}\n +""" +# remove the leading and trailing whitespace from the template +trim = true +# changelog footer +footer = """ + +""" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = false +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "Features"}, + { message = "^add", group = "Features"}, + { message = "^fix", group = "Bug Fixes"}, + { message = "^prevent", group = "Bug Fixes"}, + { message = "^doc", group = "Documentation"}, + { message = "^perf", group = "Performance"}, + { message = "^🎨", group = "Refactor"}, + { message = "^enhance", group = "Refactor"}, + { message = "^⚡️", group = "Refactor"}, + { message = "^🔥", group = "Features"}, + { message = "^🐛", group = "Bug Fixes"}, + { message = "^🚑️", group = "Bug Fixes"}, + { message = "^block", group = "Bug Fixes"}, + { message = "^✨", group = "Features"}, + { message = "^📝", group = "Documentation"}, + { message = "^🚀", group = "Features"}, + { message = "^💄", group = "Styling"}, + { message = "^✅", group = "Testing"}, + { message = "^🔒️", group = "Security"}, + { message = "^🚨", group = "Testing"}, + { message = "^💚", group = "CI"}, + { message = "^👷", group = "CI"}, + { message = "^⬇️", group = "Miscellaneous Tasks"}, + { message = "^⬆️", group = "Miscellaneous Tasks"}, + { message = "^📌", group = "Miscellaneous Tasks"}, + { message = "^➕", group = "Miscellaneous Tasks"}, + { message = "^➖", group = "Miscellaneous Tasks"}, + { message = "^♻️", group = "Refactor"}, + { message = "^🔧", group = "CI"}, + { message = "^🔨", group = "CI"}, + { message = "^🌐", group = "Localization"}, + { message = "^✏️", group = "Localization"}, + { message = "^👽️", group = "Bug Fixes"}, + { message = "^🍱", group = "Styling"}, + { message = "^♿️", group = "Styling"}, + { message = "^🩹", group = "Bug Fixes"}, + { message = "^refactor", group = "Refactor"}, + { message = "^style", group = "Styling"}, + { message = "^test", group = "Testing"}, + { message = "^chore\\(release\\): prepare for", skip = true}, + { message = "^chore", group = "Miscellaneous Tasks"}, + { message = "^update", group = "Miscellaneous Tasks"}, + { body = ".*security", group = "Security"}, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" +# regex for skipping tags +skip_tags = "v0.1.0-beta.1" +# regex for ignoring tags +ignore_tags = "" +# sort the tags chronologically +date_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" +# limit the number of commits included in the changelog. +# limit_commits = 42 diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index 59b2bab6e..aa9918d21 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -15,7 +15,6 @@ /** * @type {Cypress.PluginConfig} */ -// eslint-disable-next-line no-unused-vars module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config diff --git a/dev/docker-compose.yml.example b/dev/docker-compose.yml.example index 0ab9f264c..db235f7a7 100644 --- a/dev/docker-compose.yml.example +++ b/dev/docker-compose.yml.example @@ -30,7 +30,7 @@ services: db: restart: always - image: docker.io/postgres:13.9-alpine + image: docker.io/postgres:12.2-alpine container_name: calckey_db networks: - network diff --git a/docker-README.md b/docker-README.md index 26d0e940a..1119b34f1 100644 --- a/docker-README.md +++ b/docker-README.md @@ -42,6 +42,6 @@ Once the instance is up you can use a web browser to access the web interface at ```sh cd dev/ docker-compose build -docker-compose run --rm web yarn run init +docker-compose run --rm web pnpm run init docker-compose up -d -``` \ No newline at end of file +``` diff --git a/docker-compose.yml b/docker-compose.yml index d5ed78ac7..f51cf1b9a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: db: restart: unless-stopped - image: docker.io/postgres:13.9-alpine + image: docker.io/postgres:12.2-alpine container_name: calckey_db networks: - calcnet diff --git a/issue_template/bug.yaml b/issue_template/bug.yaml new file mode 100644 index 000000000..3a21f1399 --- /dev/null +++ b/issue_template/bug.yaml @@ -0,0 +1,70 @@ +name: Bug Report +about: File a bug report +title: "[Bug]: " +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Please give us a brief description of what happened. + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + - type: textarea + id: what-is-expected + attributes: + label: What did you expect to happen? + description: Please give us a brief description of what you expected to happen. + placeholder: Tell us what you wish happened! + value: "Instead of x, y should happen instead!" + validations: + required: true + - type: input + id: version + attributes: + label: Version + description: What version of calckey is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. + placeholder: Calckey Version 13.0.4 + validations: + required: true + - type: input + id: instance + attributes: + label: Instance + description: What instance of calckey are you using? + placeholder: stop.voring.me + validations: + required: false + - type: dropdown + id: browsers + attributes: + label: What browser are you using? + multiple: false + options: + - Firefox + - Chrome + - Brave + - Librewolf + - Chromium + - Safari + - Microsoft Edge + - Other (Please Specify) + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Contribution Guidelines + description: By submitting this issue, you agree to follow our [Contribution Guidelines](https://codeberg.org/calckey/calckey/src/branch/develop/CONTRIBUTING.md) + options: + - label: I agree to follow this project's Contribution Guidelines + required: true diff --git a/issue_template/feature.yaml b/issue_template/feature.yaml new file mode 100644 index 000000000..32f7f2c10 --- /dev/null +++ b/issue_template/feature.yaml @@ -0,0 +1,70 @@ +name: Feature Request +about: Request a Feature +title: "[Feature]: " +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + - type: textarea + id: what-feature + attributes: + label: What feature would you like implemented? + description: Please give us a brief description of what you'd like. + placeholder: Tell us what you want! + value: "x feature would be great!" + validations: + required: true + - type: textarea + id: why-add-feature + attributes: + label: Why should we add this feature? + description: Please give us a brief description of why your feature is important. + placeholder: Tell us why you want this feature! + value: "x feature is super useful because y!" + validations: + required: true + - type: input + id: version + attributes: + label: Version + description: What version of calckey is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. + placeholder: Calckey Version 13.0.4 + validations: + required: true + - type: input + id: instance + attributes: + label: Instance + description: What instance of calckey are you using? + placeholder: stop.voring.me + validations: + required: false + - type: dropdown + id: browsers + attributes: + label: What browser are you using? + multiple: false + options: + - Firefox + - Chrome + - Brave + - Librewolf + - Chromium + - Safari + - Microsoft Edge + - Other (Please Specify) + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Contribution Guidelines + description: By submitting this issue, you agree to follow our [Contribution Guidelines](https://codeberg.org/calckey/calckey/src/branch/develop/CONTRIBUTING.md) + options: + - label: I agree to follow this project's Contribution Guidelines + required: true diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index da4361ef7..fc29623dd 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -556,7 +556,6 @@ tokenRequested: "منح حق الوصول إلى الحساب" pluginTokenRequestedDescription: "ستتمكن الإضافة من استخدام هذه الأذونات." notificationType: "أنواع الإشعارات" edit: "التعديل" -useStarForReactionFallback: "استخدم ★ كبديل إذا كان التفاعل مجهولًا" emailServer: "خادم البريد الإلكتروني" emailConfigInfo: "يستخدم لتأكيد عنوان بريدك الإلكتروني ولإعادة تعيين كلمة المرور إن نسيتها." email: "البريد الإلكتروني " diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 58e03e4ba..3ed6e53aa 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -577,7 +577,6 @@ tokenRequested: "অ্যাকাউন্টে অ্যাক্সেস pluginTokenRequestedDescription: "এই প্লাগইনটি এখানে দেওয়া অনুমুতিসমূহ ব্যাবহার করবে" notificationType: "বিজ্ঞপ্তির ধরন" edit: "সম্পাদনা" -useStarForReactionFallback: "রিঅ্যাকশনের ইমোজি না জানলে ★ ব্যবহার করুন" emailServer: "ইমেইল সার্ভার" enableEmail: "ইমেইল বিতরণ চালু করুন" emailConfigInfo: "আপনার ইমেল ঠিকানা নিশ্চিত করতে এবং আপনার পাসওয়ার্ড পুনরায় সেট করতে ব্যবহৃত হয়" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index cf9cc7d83..da470c294 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -581,7 +581,6 @@ tokenRequested: "Zugriff zum Benutzerkonto gewähren" pluginTokenRequestedDescription: "Dieses Plugin wird die hier konfigurierten Berechtigungen verwenden können." notificationType: "Art der Benachrichtigung" edit: "Bearbeiten" -useStarForReactionFallback: "Verwende ★ falls das Reaktions-Emoji unbekannt ist" emailServer: "Email-Server" enableEmail: "Email-Versand aktivieren" emailConfigInfo: "Zur Email-Bestätigung bei Registrierung oder zum Zurücksetzen des Passworts verwendet" diff --git a/locales/el-GR.yml b/locales/el-GR.yml new file mode 100644 index 000000000..d32dd9c72 --- /dev/null +++ b/locales/el-GR.yml @@ -0,0 +1,408 @@ +--- +_lang_: "Ελληνικά" +monthAndDay: "{μήνας}/{ημέρα}" +search: "Αναζήτηση" +notifications: "Ειδοποιήσεις" +username: "Όνομα μέλους" +password: "Κωδικός πρόσβασης" +forgotPassword: "Ξέχασα τον κωδικό πρόσβασης" +fetchingAsApObject: "Μαζεύοντας από το Fediverse..." +ok: "Εντάξει" +gotIt: "Τό'πιασα!" +cancel: "Ακύρωση" +enterUsername: "Εισάγετε το όνομα μέλους" +renotedBy: "Κοινοποιήθηκε από {user}" +noNotes: "Δεν υπάρχουν σημειώματα" +noNotifications: "Δεν υπάρχουν ειδοποιήσεις" +settings: "Ρυθμίσεις" +basicSettings: "Βασικές ρυθμίσεις" +otherSettings: "Άλλες ρυθμίσεις" +openInWindow: "Άνοιγμα σε παράθυρο" +profile: "Προφίλ" +timeline: "Χρονολόγιο" +noAccountDescription: "Αυτό το μέλος δεν έχει γράψει βιογραφικό ακόμη." +login: "Σύνδεση" +loggingIn: "Συνδέεστε" +logout: "Αποσύνδεση" +signup: "Δημιουργία λογαριασμού" +uploading: "Ανέβασμα..." +save: "Αποθήκευση" +users: "Μέλη" +addUser: "Προσθήκη μέλους" +favorite: "Προσθήκη στα αγαπημένα" +favorites: "Αγαπημένα" +unfavorite: "Αφαίρεση από αγαπημένα" +favorited: "Προστέθηκε στα αγαπημένα." +alreadyFavorited: "Έχει ήδη προστεθεί στα αγαπημένα." +cantFavorite: "Αδυναμία προσθήκης στα αγαπημένα." +pin: "Καρφίτσωμα στο προφίλ" +unpin: "Ξεκαρφίτσωμα από το προφίλ" +copyContent: "Αντιγραφή περιεχομένων" +copyLink: "Αντιγραφή συνδέσμου" +delete: "Διαγραφή" +deleteAndEdit: "Διαγραφή και επεξεργασία" +deleteAndEditConfirm: "Σίγουρα θέλετε να διαγράψετε αυτό το σημείωμα και να το επεξεργαστείτε; Θα χάσετε όλες τις αντιδράσεις, κοινοποιήσεις και απαντήσεις σε αυτό." +addToList: "Προσθήκη στη λίστα" +sendMessage: "Αποστολή μηνύματος" +copyUsername: "Αντιγραφή ονόματος μέλους" +searchUser: "Αναζήτηση μέλους" +reply: "Απάντηση" +loadMore: "Φόρτωσε περισσότερα" +showMore: "Δείξε περισσότερα" +showLess: "Κλείσιμο" +youGotNewFollower: "σε ακολούθησε" +receiveFollowRequest: "Λάβατε αίτημα ακολούθησης" +followRequestAccepted: "Το αίτημα ακολούθησης έγινε δεκτό" +mention: "Επισήμανση" +mentions: "Επισημάνσεις" +directNotes: "Απευθείας σημειώματα" +importAndExport: "Εισαγωγή / Εξαγωγή" +import: "Εισαγωγή" +export: "Εξαγωγή" +files: "Αρχεία" +download: "Λήψη" +driveFileDeleteConfirm: "Θέλετε σίγουρα να διαγράψετε το αρχείο \"{name}\"; Τα σημειώματα με αυτό το συνημμένο αρχείο επίσης θα διαγραφούν." +unfollowConfirm: "Θέλετε σίγουρα να σταματήσετε να ακολουθείτε το μέλος {name};" +exportRequested: "Ζητήσατε μία εξαγωγή. Αυτό μπορεί να πάρει κάποιον χρόνο. Επίσης θα προστεθεί στον Δίσκο σας μόλις ολοκληρωθεί." +importRequested: "Ζητήσατε μία εισαγωγή. Αυτό μπορεί να πάρει κάποιον χρόνο." +lists: "Λίστες" +noLists: "Δεν έχετε λίστες" +note: "Σημείωμα" +notes: "Σημειώματα" +following: "Ακολουθεί" +followers: "Ακολουθούν" +followsYou: "Σε ακολουθεί" +createList: "Δημιουργία λίστας" +manageLists: "Διαχείριση λιστών" +error: "Σφάλμα" +somethingHappened: "Προέκυψε ένα σφάλμα" +retry: "Προσπάθεια ξανά" +pageLoadError: "Ένα σφάλμα προέκυψε φορτώνοντας τη σελίδα." +pageLoadErrorDescription: "Αυτό κανονικά προκαλείται από σφάλματα δικτύου ή από την προσωρινή μνήμη του προγράμματος περιήγησης. Δοκιμάστε να σβήσετε την προσωρινή μνήμη (cache) και ξαναδοκιμάστε μετά από λίγο." +serverIsDead: "Αυτός ο server δεν αποκρίνεται. Παρακαλώ περιμέντε λίγο και δοκιμάστε ξανά." +youShouldUpgradeClient: "Για να δείτε αυτή τη σελίδα, παρακαλώ επαναφορτώστε για να ενημερωθεί το πρόγραμμα." +enterListName: "Πληκτρολογήστε ένα όνομα για τη λίστα" +privacy: "Ιδιωτικότητα" +makeFollowManuallyApprove: "Τα αιτήματα ακολούθησης χρειάζονται έγκριση" +defaultNoteVisibility: "Προεπιλεγμένη ορατότητα" +follow: "Ακολουθήστε" +followRequest: "Στείλτε αίτημα ακολούθησης" +followRequests: "Αιτήματα ακολούθησης" +unfollow: "Να μην ακολουθώ" +followRequestPending: "Το αίτημα ακολούθησης εκκρεμεί" +enterEmoji: "Εισάγετε ένα emoji" +renote: "Κοινοποίηση σημειώματος" +unrenote: "Ακύρωση κοινοποίησης" +renoted: "Κοινοποιήθηκε." +cantRenote: "Αυτή η δημοσίευση δεν μπορεί να κοινοποιηθεί." +cantReRenote: "Μία κοινοποίηση δεν μπορεί να κοινοποιηθεί." +quote: "Παράθεση" +pinnedNote: "Καρφιτσωμένο σημείωμα" +pinned: "Καρφίτσωμα στο προφίλ" +you: "Εσύ" +clickToShow: "Κάντε κλικ για εμφάνιση" +add: "Προσθέστε" +reaction: "Αντιδράσεις" +reactionSetting: "Αντιδράσεις για εμφάνιση στην επιλογή αντίδρασης" +reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε." +rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος" +attachCancel: "Διαγραφή αρχείου" +enterFileName: "Πληκτρολογήστε όνομα αρχείου" +mute: "Σίγαση" +unmute: "Άρση σίγασης" +block: "Μπλοκάρισμα" +unblock: "Άρση μπλοκαρίσματος" +suspend: "Αποβολή" +unsuspend: "Άρση αποβολής" +blockConfirm: "Θέλετε σίγουρα να μπλοκάρετε αυτόν τον λογαριασμό;" +unblockConfirm: "Θέλετε σίγουρα να ξεμπλοκάρετε αυτόν τον λογαριασμό;" +suspendConfirm: "Θέλετε σίγουρα να αποβάλλετε αυτόν τον λογαριασμό;" +unsuspendConfirm: "Θέλετε σίγουρα να άρετε την αποβολή αυτού του λογαριασμού;" +selectList: "Επιλέξτε μία λίστα" +selectAntenna: "Επιλέξτε μία αντένα" +selectWidget: "Επιλέξτε ένα μαραφέτι" +editWidgets: "Επεξεργασία μαραφετίων" +editWidgetsExit: "Ολοκληρώθηκε" +customEmojis: "Επιπλέον emoji" +emojiName: "Όνομα emoji" +addEmoji: "Προσθήκη emoji" +settingGuide: "Συνιστώμενες ρυθμίσεις" +flagAsBot: "Αυτός ο λογαριασμός είναι bot" +flagAsCat: "Αυτός ο λογαριασμός είναι γάτα" +flagShowTimelineReplies: "Εμφάνιση απαντήσεων στο χρονολόγιο" +addAccount: "Προσθήκη λογαριασμού" +general: "Γενικές" +wallpaper: "Ταπετσαρία" +setWallpaper: "Ορισμός ταπετσαρίας" +removeWallpaper: "Διαγραφή ταπετσαρίας" +searchWith: "Αναζήτηση: {q}" +youHaveNoLists: "Δεν έχετε λίστες" +followConfirm: "Θέλετε σίγουρα να ακολουθήσετε τον λογαριασμό {name};" +host: "Φιλοξενεί" +selectUser: "Επιλέξτε ένα μέλος" +recipient: "Αποδέκτης-τρια" +annotation: "Σχόλια" +federation: "Ομοσπονδία" +storageUsage: "Χρήση χώρου" +version: "Έκδοση" +metadata: "Μεταδεδομένα" +network: "Δίκτυο" +disk: "Δίσκος" +instanceInfo: "Πληροφορίες του instance" +statistics: "Στατιστικά" +clearQueue: "Εκκαθάριση ουράς" +clearQueueConfirmTitle: "Θέλετε να διαγράψετε την ουρά;" +clearCachedFiles: "Εκκαθάριση προσωρινής μνήμης" +done: "Ολοκληρώθηκε" +attachFile: "Επισύναψη αρχείων" +more: "Περισσότερα!" +noSuchUser: "Το μέλος δεν βρέθηκε" +announcements: "Ανακοινώσεις" +imageUrl: "URL εικόνας" +remove: "Διαγραφή" +removed: "Η διαγραφή ολοκληρώθηκε επιτυχώς" +saved: "Αποθηκεύτηκε" +messaging: "Συνομιλία" +upload: "Ανεβάστε" +fromDrive: "Από τον Αποθηκευτικό Χώρο" +fromUrl: "Από URL" +uploadFromUrl: "Ανεβάστε από URL" +explore: "Εξερευνήστε" +messageRead: "Διαβάστηκε" +startMessaging: "Ξεκινήστε μία συνομιλία" +nUsersRead: "διαβάστηκε από {n}" +tos: "Όροι χρήσης" +start: "Ας αρχίσουμε" +home: "Κεντρικό" +activity: "Δραστηριότητα" +images: "Εικόνες" +birthday: "Γενέθλια" +registeredDate: "Έγινε μέλος στις" +location: "Τοποθεσία" +theme: "Θέματα" +light: "Ανοιχτόχρωμο" +dark: "Σκούρο" +drive: "Αποθηκευτικός Χώρος" +fileName: "Όνομα αρχείου" +selectFile: "Επιλέξτε ένα αρχείο" +selectFiles: "Επιλέξτε αρχεία" +selectFolder: "Επιλέξτε φάκελο" +selectFolders: "Επιλέξτε φακέλους" +renameFile: "Μετονομασία αρχείου" +addFile: "Προσθήκη αρχείου" +emptyDrive: "Ο Αποθηκευτικός Χώρος σας είναι άδειος" +copyUrl: "Αντιγραφή URL" +rename: "Αλλαγή ονόματος" +avatar: "Εικονίδιο" +banner: "Πανό" +reload: "Ανανέωση" +doNothing: "Αγνόηση" +watch: "Παρακολούθηση" +unwatch: "Τέλος παρακολούθησης" +accept: "Αποδοχή" +reject: "Απόρριψη" +normal: "Κανονικό" +instanceName: "Όνομα instance" +thisYear: "Έτος" +thisMonth: "Μήνας" +today: "Σήμερα" +dayX: "{day}" +pages: "Σελίδες" +connectService: "Σύνδεση" +disconnectService: "Αποσύνδεση" +registration: "Εγγραφή" +pinnedPages: "Καρφιτσωμένες Σελίδες" +pinnedNotes: "Καρφιτσωμένα σημειώματα" +antennas: "Αντένες" +manageAntennas: "Διαχείριση αντενών" +name: "Όνομα" +antennaSource: "Πηγή αντένας" +antennaKeywords: "Λέξεις-κλειδιά για παρακολούθηση" +antennaExcludeKeywords: "Λέξεις-κλειδιά για αποκλεισμό" +notifyAntenna: "Ειδοποίηση για νέα σημειώματα" +withFileAntenna: "Μόνο σημειώματα με αρχεία" +caseSensitive: "Διάκριση Πεζών-Κεφαλαίων" +popularTags: "Δημοφιλείς ετικέτες" +userList: "Λίστες" +about: "Πληροφορίες" +moderator: "Συντονιστής" +moderation: "Συντονισμός" +cacheClear: "Εκκαθάριση προσωρινής μνήμης" +markAsReadAllNotifications: "Όλες οι ειδοποιήσεις διαβάστηκαν" +group: "Ομάδα" +groups: "Ομάδες" +createGroup: "Δημιουργία ομάδας" +ownedGroups: "Οι ομάδες σας" +groupName: "Όνομα ομάδας" +members: "Μέλη" +transfer: "Μεταφορά" +messagingWithUser: "Ιδιωτική συνομιλία" +messagingWithGroup: "Ομαδική συνομιλία" +title: "Τίτλος" +text: "Κείμενο" +enable: "Ενεργοποίηση" +next: "Επόμενο" +noteOf: "Σημείωμα από {user}" +inviteToGroup: "Πρόσκληση στην ομάδα" +quoteAttached: "Παράθεση" +signinRequired: "Παρακαλούμε δημιουργήστε λογαριασμό ή συνδεθείτε πριν συνεχίσετε" +category: "Κατηγορία" +tags: "Ετικέτες" +createAccount: "Δημιουργία λογαριασμού" +local: "Τοπικό" +remote: "Απομακρυσμένo" +total: "Σύνολο" +appearance: "Εμφάνιση" +accountSettings: "Ρυθμίσεις λογαριασμού" +sounds: "Ήχοι" +sound: "Ήχοι" +listen: "Ακρόαση" +showInPage: "Εμφάνιση στη σελίδα" +volume: "Ένταση" +masterVolume: "Κύρια ένταση" +details: "Λεπτομέρειες" +install: "Εγκατάσταση" +uninstall: "Κατάργηση εγκατάστασης" +manage: "Διαχείριση" +smtpHost: "Φιλοξενεί" +smtpUser: "Όνομα μέλους" +smtpPass: "Κωδικός πρόσβασης" +notificationSetting: "Ρυθμίσεις ειδοποιήσεων" +notificationSettingDesc: "Επιλέξτε τους τύπους ειδοποιήσεων που εμφανίζονται" +switchUi: "Αλλαγή UI" +clip: "Κλιπ" +driveFilesCount: "Αριθμός αρχείων Αποθηκευτικού Χώρου" +driveUsage: "Χρήση Αποθηκευτικού Χώρου" +noteFavoritesCount: "Αριθμός αγαπημένων σημειωμάτων" +clips: "Κλιπ" +clearCache: "Εκκαθάριση προσωρινής μνήμης" +emailNotification: "Ειδοποιήσεις μέσω mail" +inChannelSearch: "Αναζήτηση στο κανάλι" +info: "Πληροφορίες" +notRecommended: "Δεν προτείνεται" +switchAccount: "Αλλαγή λογαριασμού" +user: "Μέλη" +administration: "Διαχείριση" +switch: "Εναλλαγή" +gallery: "Γκαλερί" +global: "Παγκόσμιο" +searchResult: "Αποτελέσματα αναζήτησης" +learnMore: "Μάθετε περισσότερα" +controlPanel: "Πίνακας ελέγχου" +manageAccounts: "Διαχείριση Λογαριασμών" +searchByGoogle: "Αναζήτηση" +file: "Αρχεία" +recommended: "Προτεινόμενα" +cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού Χώρου" +_email: + _follow: + title: "Έχετε ένα νέο ακόλουθο" +_mfm: + mention: "Επισήμανση" + quote: "Παράθεση" + emoji: "Επιπλέον emoji" + search: "Αναζήτηση" +_channel: + featured: "Δημοφιλή" +_theme: + keys: + panel: "Πίνακας" + mention: "Επισήμανση" + renote: "Κοινοποίηση σημειώματος" +_sfx: + note: "Σημειώματα" + notification: "Ειδοποιήσεις" + chat: "Συνομιλία" + chatBg: "Συνομιλία (Παρασκήνιο)" + antenna: "Αντένες" + channel: "Ειδοποιήσεις καναλιών" +_ago: + future: "Μελλοντικό" + justNow: "Μόλις τώρα" + secondsAgo: "{n} δευτερόλεπτο(α) πριν" + minutesAgo: "{n} λεπτό(ά) πριν" + hoursAgo: "{n} ώρα(ες) πριν" + daysAgo: "{n} μέρα(ες) πριν" + weeksAgo: "{n} εβδομάδα(ες) πριν" + monthsAgo: "{n} μήνα(ες) πριν" + yearsAgo: "{n} έτος(η) πριν" +_permissions: + "write:drive": "Επεξεργαστείτε ή διαγράψτε τα αρχεία και τους φακέλους του Αποθηκευτικού Χώρου σας" + "read:favorites": "Δείτε τη λίστα των αγαπημένων σας" + "write:favorites": "Επεξεργαστείτε τη λίστα των αγαπημένων σας" + "read:messaging": "Δείτε τις συνομιλίες σας" + "write:messaging": "Γράψτε ή διαγράψτε μηνύματα συνομιλίας" + "read:notifications": "Δείτε τις ειδοποιήσεις σας" + "write:notifications": "Διαχειριστείτε τις ειδοποιήσεις σας" + "read:pages": "Δείτε τις Σελίδες σας" + "write:pages": "Επεξεργαστείτε ή διαγράψτε τις σελίδες σας" +_antennaSources: + all: "Όλα τα σημειώματα" + homeTimeline: "Σημειώματα από μέλη που ακολουθείτε" + users: "Σημειώματα από συγκεκριμένα μέλη" + userList: "Σημειώματα από καθορισμένη λίστα μελών" + userGroup: "Σημειώματα από μέλη καθορισμένης ομάδας" +_widgets: + profile: "Προφίλ" + instanceInfo: "Πληροφορίες του instance" + notifications: "Ειδοποιήσεις" + timeline: "Χρονολόγιο" + calendar: "Ημερολόγιο" + trends: "Δημοφιλή" + clock: "Ρολόι" + activity: "Δραστηριότητα" + photos: "Φωτογραφίες" + digitalClock: "Ψηφιακό ρολόι" + federation: "Ομοσπονδία" + postForm: "Φόρμα δημοσίευσης" + button: "Κουμπί" + onlineUsers: "Συνδεδεμένα μέλη" + _userList: + chooseList: "Επιλέξτε μία λίστα" +_cw: + show: "Δείτε περισσότερα" +_visibility: + home: "Κεντρικό" + homeDescription: "Δημοσίευση στο κεντρικό χρονολόγιο μόνο" + followers: "Ακολουθούν" +_profile: + name: "Όνομα" + username: "Όνομα μέλους" +_exportOrImport: + allNotes: "Όλα τα σημειώματα" + followingList: "Ακολουθεί" + muteList: "Μέλη σε σίγαση" + blockingList: "Μπλοκαρισμένα μέλη" + userLists: "Λίστες" +_charts: + federation: "Ομοσπονδία" +_timelines: + home: "Κεντρικό" + local: "Τοπικό" + social: "Κοινωνικό" + global: "Παγκόσμιο" +_pages: + viewPage: "Δείτε τις Σελίδες σας" + blocks: + image: "Εικόνες" +_notification: + youGotMessagingMessageFromUser: "{name} σάς έστειλε ένα μήνυμα συνομιλίας" + youWereFollowed: "σε ακολούθησε" + _types: + follow: "Νέοι ακόλουθοι" + mention: "Επισήμανση" + renote: "Κοινοποίηση σημειώματος" + quote: "Παράθεση" + reaction: "Αντιδράσεις" + _actions: + reply: "Απάντηση" + renote: "Κοινοποίηση σημειώματος" +_deck: + widgetsIntroduction: "Παρακαλούμε επιλέξτε \"Επεξεργασία μαραφετίων\" στο μενού και προσθέστε μαραφέτι." + _columns: + widgets: "Μαραφέτια" + notifications: "Ειδοποιήσεις" + tl: "Χρονολόγιο" + antenna: "Αντένες" + list: "Λίστα" + mentions: "Επισημάνσεις" diff --git a/locales/en-US.yml b/locales/en-US.yml index 948934d81..cc741bd60 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -13,8 +13,8 @@ ok: "OK" gotIt: "Got it!" cancel: "Cancel" enterUsername: "Enter username" -renotedBy: "Renoted by {user}" -noNotes: "No notes" +renotedBy: "Boosted by {user}" +noNotes: "No posts" noNotifications: "No notifications" instance: "Instance" settings: "Settings" @@ -44,7 +44,7 @@ copyContent: "Copy contents" copyLink: "Copy link" delete: "Delete" deleteAndEdit: "Delete and edit" -deleteAndEditConfirm: "Are you sure you want to delete this note and edit it? You will lose all reactions, renotes and replies to it." +deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You will lose all reactions, boosts and replies to it." addToList: "Add to list" sendMessage: "Send a message" copyUsername: "Copy username" @@ -58,20 +58,20 @@ receiveFollowRequest: "Follow request received" followRequestAccepted: "Follow request accepted" mention: "Mention" mentions: "Mentions" -directNotes: "Direct notes" +directNotes: "Direct messages" importAndExport: "Import/Export Data" import: "Import" export: "Export" files: "Files" download: "Download" -driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? Notes with this file attached will also be deleted." +driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? Posts with this file attached will also be deleted." unfollowConfirm: "Are you sure that you want to unfollow {name}?" exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed." importRequested: "You've requested an import. This may take a while." lists: "Lists" noLists: "You don't have any lists" -note: "Note" -notes: "Notes" +note: "Post" +notes: "Posts" following: "Following" followers: "Followers" followsYou: "Follows you" @@ -94,13 +94,13 @@ followRequests: "Follow requests" unfollow: "Unfollow" followRequestPending: "Follow request pending" enterEmoji: "Enter an emoji" -renote: "Renote" -unrenote: "Take back renote" -renoted: "Renoted." -cantRenote: "This post can't be renoted." -cantReRenote: "A renote can't be renoted." +renote: "Boost" +unrenote: "Take back boost" +renoted: "Boosted." +cantRenote: "This post can't be boosted." +cantReRenote: "A boost can't be boosted." quote: "Quote" -pinnedNote: "Pinned note" +pinnedNote: "Pinned post" pinned: "Pin to profile" you: "You" clickToShow: "Click to show" @@ -109,7 +109,7 @@ add: "Add" reaction: "Reactions" reactionSetting: "Reactions to show in the reaction picker" reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add." -rememberNoteVisibility: "Remember note visibility settings" +rememberNoteVisibility: "Remember post visibility settings" attachCancel: "Remove attachment" markAsSensitive: "Mark as NSFW" unmarkAsSensitive: "Unmark as NSFW" @@ -143,7 +143,7 @@ flagAsBotDescription: "Enable this option if this account is controlled by a pro flagAsCat: "Are you a cat? 😺" flagAsCatDescription: "You'll get cat ears and speak like a cat!" flagShowTimelineReplies: "Show replies in timeline" -flagShowTimelineRepliesDescription: "Shows replies of users to notes of other users in the timeline if turned on." +flagShowTimelineRepliesDescription: "Shows replies of users to posts of other users in the timeline if turned on." autoAcceptFollowed: "Automatically approve follow requests from users you're following" addAccount: "Add account" loginFailed: "Failed to sign in" @@ -188,7 +188,7 @@ instanceInfo: "Instance Information" statistics: "Statistics" clearQueue: "Clear queue" clearQueueConfirmTitle: "Are you sure that you want to clear the queue?" -clearQueueConfirmText: "Any undelivered notes remaining in the queue will not be federated. Usually this operation is not needed." +clearQueueConfirmText: "Any undelivered posts remaining in the queue will not be federated. Usually this operation is not needed." clearCachedFiles: "Clear cache" clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?" blockedInstances: "Blocked Instances" @@ -198,8 +198,8 @@ mutedUsers: "Muted users" blockedUsers: "Blocked users" noUsers: "There are no users" editProfile: "Edit profile" -noteDeleteConfirm: "Are you sure you want to delete this note?" -pinLimitExceeded: "You cannot pin any more notes" +noteDeleteConfirm: "Are you sure you want to delete this post?" +pinLimitExceeded: "You cannot pin any more posts" intro: "Installation of Calckey has been finished! Please create an admin user." done: "Done" processing: "Processing..." @@ -342,7 +342,7 @@ pinnedUsersDescription: "List usernames separated by line breaks to be pinned in pinnedPages: "Pinned Pages" pinnedPagesDescription: "Enter the paths of the Pages you want to pin to the top page of this instance, separated by line breaks." pinnedClipId: "ID of the clip to pin" -pinnedNotes: "Pinned notes" +pinnedNotes: "Pinned posts" hcaptcha: "hCaptcha" enableHcaptcha: "Enable hCaptcha" hcaptchaSiteKey: "Site key" @@ -359,14 +359,14 @@ antennaSource: "Antenna source" antennaKeywords: "Keywords to listen to" antennaExcludeKeywords: "Keywords to exclude" antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition." -notifyAntenna: "Notify about new notes" -withFileAntenna: "Only notes with files" +notifyAntenna: "Notify about new posts" +withFileAntenna: "Only posts with files" enableServiceworker: "Enable Push-Notifications for your Browser" antennaUsersDescription: "List one username per line" caseSensitive: "Case sensitive" withReplies: "Include replies" connectedTo: "Following account(s) are connected" -notesAndReplies: "Notes and replies" +notesAndReplies: "Posts and replies" withFiles: "Including files" silence: "Silence" silenceConfirm: "Are you sure that you want to silence this user?" @@ -403,7 +403,7 @@ notFoundDescription: "No page corresponding to this URL could be found." uploadFolder: "Default folder for uploads" cacheClear: "Clear cache" markAsReadAllNotifications: "Mark all notifications as read" -markAsReadAllUnreadNotes: "Mark all notes as read" +markAsReadAllUnreadNotes: "Mark all posts as read" markAsReadAllTalkMessages: "Mark all messages as read" help: "Help" inputMessageHere: "Enter message here" @@ -424,7 +424,7 @@ text: "Text" enable: "Enable" next: "Next" retype: "Enter again" -noteOf: "Note by {user}" +noteOf: "Post by {user}" inviteToGroup: "Invite to group" quoteAttached: "Quote" quoteQuestion: "Append as quote?" @@ -482,8 +482,8 @@ accountSettings: "Account Settings" promotion: "Promoted" promote: "Promote" numberOfDays: "Number of days" -hideThisNote: "Hide this note" -showFeaturedNotesInTimeline: "Show featured notes in timelines" +hideThisNote: "Hide this post" +showFeaturedNotesInTimeline: "Show featured posts in timelines" objectStorage: "Object Storage" useObjectStorage: "Use object storage" objectStorageBaseUrl: "Base URL" @@ -504,7 +504,7 @@ objectStorageSetPublicRead: "Set \"public-read\" on upload" serverLogs: "Server logs" deleteAll: "Delete all" showFixedPostForm: "Display the posting form at the top of the timeline" -newNoteRecived: "There are new notes" +newNoteRecived: "There are new posts" sounds: "Sounds" listen: "Listen" none: "None" @@ -548,8 +548,8 @@ addRelay: "Add Relay" inboxUrl: "Inbox URL" addedRelays: "Added Relays" serviceworkerInfo: "Must be enabled for push notifications." -deletedNote: "Deleted note" -invisibleNote: "Invisible note" +deletedNote: "Deleted post" +invisibleNote: "Invisible post" enableInfiniteScroll: "Automatically load more" visibility: "Visiblility" poll: "Poll" @@ -583,7 +583,6 @@ tokenRequested: "Grant access to account" pluginTokenRequestedDescription: "This plugin will be able to use the permissions set here." notificationType: "Notification type" edit: "Edit" -useStarForReactionFallback: "Use ★ as fallback if the reaction emoji is unknown" emailServer: "Email server" enableEmail: "Enable email distribution" emailConfigInfo: "Used to confirm your email during sign-up or if you forget your password" @@ -627,7 +626,7 @@ sample: "Sample" abuseReports: "Reports" reportAbuse: "Report" reportAbuseOf: "Report {name}" -fillAbuseReportDescription: "Please fill in details regarding this report. If it is about a specific note, please include its URL." +fillAbuseReportDescription: "Please fill in details regarding this report. If it is about a specific post, please include its URL." abuseReported: "Your report has been sent. Thank you very much." reporter: "Reporter" reporteeOrigin: "Reportee Origin" @@ -640,27 +639,27 @@ openInNewTab: "Open in new tab" openInSideView: "Open in side view" defaultNavigationBehaviour: "Default navigation behavior" editTheseSettingsMayBreakAccount: "Editing these settings may damage your account." -instanceTicker: "Instance information of notes" +instanceTicker: "Instance information of posts" waitingFor: "Waiting for {x}" random: "Random" system: "System" -switchUi: "Switch UI" +switchUi: "Layout" desktop: "Desktop" clip: "Clip" createNew: "Create new" optional: "Optional" createNewClip: "Create new clip" unclip: "Unclip" -confirmToUnclipAlreadyClippedNote: "This note is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?" +confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?" public: "Public" i18nInfo: "Calckey is being translated into various languages by volunteers. You can help at {link}." manageAccessTokens: "Manage access tokens" accountInfo: "Account Info" -notesCount: "Number of notes" +notesCount: "Number of posts" repliesCount: "Number of replies sent" -renotesCount: "Number of renotes sent" +renotesCount: "Number of boosts sent" repliedCount: "Number of replies received" -renotedCount: "Number of renotes received" +renotedCount: "Number of boosts received" followingCount: "Number of followed accounts" followersCount: "Number of followers" sentReactionsCount: "Number of sent reactions" @@ -672,15 +671,15 @@ no: "No" driveFilesCount: "Number of Drive files" driveUsage: "Drive space usage" noCrawle: "Reject crawler indexing" -noCrawleDescription: "Ask search engines to not index your profile page, notes, Pages, etc." -lockedAccountInfo: "Unless you set your note visiblity to \"Followers only\", your notes will be visible to anyone, even if you require followers to be manually approved." +noCrawleDescription: "Ask search engines to not index your profile page, posts, Pages, etc." +lockedAccountInfo: "Unless you set your post visiblity to \"Followers only\", your posts will be visible to anyone, even if you require followers to be manually approved." alwaysMarkSensitive: "Mark as NSFW by default" loadRawImages: "Load original images instead of showing thumbnails" disableShowingAnimatedImages: "Don't play animated images" verificationEmailSent: "A verification email has been sent. Please follow the included link to complete verification." notSet: "Not set" emailVerified: "Email has been verified" -noteFavoritesCount: "Number of bookmarked notes" +noteFavoritesCount: "Number of bookmarked posts" pageLikesCount: "Number of liked Pages" pageLikedCount: "Number of received Page likes" contact: "Contact" @@ -702,7 +701,7 @@ showTitlebar: "Show title bar" clearCache: "Clear cache" onlineUsersCount: "{n} users are online" nUsers: "{n} Users" -nNotes: "{n} Notes" +nNotes: "{n} Posts" sendErrorReports: "Send error reports" sendErrorReportsDescription: "When turned on, detailed error information will be shared with Calckey when a problem occurs, helping to improve the quality of Misskey.\nThis will include information such the version of your OS, what browser you're using, your activity in Calckey, etc." myTheme: "My theme" @@ -743,8 +742,8 @@ unlikeConfirm: "Really remove your like?" fullView: "Full view" quitFullView: "Exit full view" addDescription: "Add description" -userPagePinTip: "You can display notes here by selecting \"Pin to profile\" from the menu of individual notes." -notSpecifiedMentionWarning: "This note contains mentions of users not included as recipients" +userPagePinTip: "You can display posts here by selecting \"Pin to profile\" from the menu of individual posts." +notSpecifiedMentionWarning: "This post contains mentions of users not included as recipients" info: "About" userInfo: "User information" unknown: "Unknown" @@ -773,7 +772,7 @@ postToGallery: "Create new gallery post" gallery: "Gallery" recentPosts: "Recent pages" popularPosts: "Popular pages" -shareWithNote: "Share with note" +shareWithNote: "Share with post" ads: "Advertisements" expiration: "Deadline" memo: "Memo" @@ -787,7 +786,7 @@ secureMode: "Secure Mode (Authorized Fetch)" instanceSecurity: "Instance Security" secureModeInfo: "When requesting from other instances, do not send back without proof." privateMode: "Private Mode" -privateModeInfo: "When enabled, only whitelisted instances can federate with your instances. All notes will be hidden from the public." +privateModeInfo: "When enabled, only whitelisted instances can federate with your instances. All posts will be hidden from the public." allowedInstances: "Whitelisted Instances" allowedInstancesDescription: "Hosts of instances to be whitelisted for federation, each seperated by a new line (only applies in private mode)." previewNoteText: "Show preview" @@ -796,7 +795,7 @@ customCssWarn: "This setting should only be used if you know what it does. Enter global: "Global" recommended: "Recommended" squareAvatars: "Display squared avatars" -seperateRenoteQuote: "Seperate renote and quote buttons" +seperateRenoteQuote: "Seperate boost and quote buttons" sent: "Sent" received: "Received" searchResult: "Search results" @@ -930,6 +929,7 @@ moveFrom: "Move to this account from an older account" moveFromLabel: "Account you're moving from:" moveFromDescription: "This will set an alias of your old account so that you can move from that account to this current one. Do this BEFORE moving from your older account. Please enter the tag of the account formatted like @person@instance.com" migrationConfirm: "Are you absolutely sure you want to migrate your acccount to {account}? Once you do this, you won't be able to reverse it, and you won't be able to use your account normally again.\nAlso, please ensure that you've set this current account as the account you're moving from." +defaultReaction: "Default emoji reaction for outgoing and incoming posts" _sensitiveMediaDetection: description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server." @@ -1102,7 +1102,7 @@ _channel: owned: "Owned" following: "Followed" usersCount: "{n} Participants" - notesCount: "{n} Notes" + notesCount: "{n} Posts" _messaging: dms: "Private" groups: "Groups" @@ -1115,15 +1115,15 @@ _wordMute: muteWords: "Muted words" muteWordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition." muteWordsDescription2: "Surround keywords with slashes to use regular expressions." - softDescription: "Hide notes that fulfil the set conditions from the timeline." - hardDescription: "Prevents notes fulfilling the set conditions from being added to the timeline. In addition, these notes will not be added to the timeline even if the conditions are changed." + softDescription: "Hide posts that fulfil the set conditions from the timeline." + hardDescription: "Prevents posts fulfilling the set conditions from being added to the timeline. In addition, these posts will not be added to the timeline even if the conditions are changed." soft: "Soft" hard: "Hard" - mutedNotes: "Muted notes" + mutedNotes: "Muted posts" _instanceMute: - instanceMuteDescription: "This will mute any notes/renotes from the listed instances, including those of users replying to a user from a muted instance." + instanceMuteDescription: "This will mute any posts/boosts from the listed instances, including those of users replying to a user from a muted instance." instanceMuteDescription2: "Separate with newlines" - title: "Hides notes from listed instances." + title: "Hides posts from listed instances." heading: "List of instances to be muted" _theme: explore: "Explore Themes" @@ -1173,7 +1173,7 @@ _theme: hashtag: "Hashtag" mention: "Mention" mentionMe: "Mentions (Me)" - renote: "Renote" + renote: "Boost" modalBg: "Modal background" divider: "Divider" scrollbarHandle: "Scrollbar handle" @@ -1200,8 +1200,8 @@ _theme: accentLighten: "Accent (Lightened)" fgHighlighted: "Highlighted Text" _sfx: - note: "New note" - noteMy: "Own note" + note: "New post" + noteMy: "Own post" notification: "Notifications" chat: "Chat" chatBg: "Chat (Background)" @@ -1227,7 +1227,7 @@ _tutorial: step1_1: "Welcome!" step1_2: "Let's get you set up. You'll be up and running in no time!" step2_1: "First, please fill out your profile." - step2_2: "Providing some information about who you are will make it easier for others to tell if they want to see your notes or follow you." + step2_2: "Providing some information about who you are will make it easier for others to tell if they want to see your posts or follow you." step3_1: "Now time to follow some people!" step3_2: "Your home and social timelines are based off of who you follow, so try following a couple accounts to get started.\nClick the plus circle on the top right of a profile to follow them." step4_1: "Let's get you out there." @@ -1268,7 +1268,7 @@ _permissions: "write:messaging": "Compose or delete chat messages" "read:mutes": "View your list of muted users" "write:mutes": "Edit your list of muted users" - "write:notes": "Compose or delete notes" + "write:notes": "Compose or delete posts" "read:notifications": "View your notifications" "write:notifications": "Manage your notifications" "read:reactions": "View your reactions" @@ -1294,11 +1294,11 @@ _auth: callback: "Returning to the application" denied: "Access denied" _antennaSources: - all: "All notes" - homeTimeline: "Notes from followed users" - users: "Notes from specific users" - userList: "Notes from a specified list of users" - userGroup: "Notes from users in a specified group" + all: "All posts" + homeTimeline: "Posts from followed users" + users: "Posts from specific users" + userList: "Posts from a specified list of users" + userGroup: "Posts from users in a specified group" _weekday: sunday: "Sunday" monday: "Monday" @@ -1329,7 +1329,9 @@ _widgets: jobQueue: "Job Queue" serverMetric: "Server metrics" aiscript: "AiScript console" - aichan: "Ai" + userList: "User list" + _userList: + chooseList: "Select a list" _cw: hide: "Hide" show: "Show content" @@ -1359,7 +1361,7 @@ _poll: remainingSeconds: "{s} second(s) remaining" _visibility: public: "Public" - publicDescription: "Your note will be visible for all users" + publicDescription: "Your post will be visible for all users" home: "Home" homeDescription: "Post to home timeline only" followers: "Followers" @@ -1369,8 +1371,8 @@ _visibility: localOnly: "Local only" localOnlyDescription: "Not visible to remote users" _postForm: - replyPlaceholder: "Reply to this note..." - quotePlaceholder: "Quote this note..." + replyPlaceholder: "Reply to this post..." + quotePlaceholder: "Quote this post..." channelPlaceholder: "Post to a channel..." _placeholders: a: "What are you up to?" @@ -1392,7 +1394,7 @@ _profile: changeAvatar: "Change avatar" changeBanner: "Change banner" _exportOrImport: - allNotes: "All notes" + allNotes: "All posts" followingList: "Followed users" muteList: "Muted users" blockingList: "Blocked users" @@ -1405,10 +1407,10 @@ _charts: usersIncDec: "Difference in the number of users" usersTotal: "Total number of users" activeUsers: "Active users" - notesIncDec: "Difference in the number of notes" - localNotesIncDec: "Difference in the number of local notes" - remoteNotesIncDec: "Difference in the number of remote notes" - notesTotal: "Total number of notes" + notesIncDec: "Difference in the number of posts" + localNotesIncDec: "Difference in the number of local posts" + remoteNotesIncDec: "Difference in the number of remote posts" + notesTotal: "Total number of posts" filesIncDec: "Difference in the number of files" filesTotal: "Total number of files" storageUsageIncDec: "Difference in storage usage" @@ -1417,8 +1419,8 @@ _instanceCharts: requests: "Requests" users: "Difference in the number of users" usersTotal: "Cumulative number of users" - notes: "Difference in the number of notes" - notesTotal: "Cumulative number of notes" + notes: "Difference in the number of posts" + notesTotal: "Cumulative number of posts" ff: "Difference in the number of followed users / followers " ffTotal: "Cumulative number of followed users / followers" cacheSize: "Difference in cache size" @@ -1505,10 +1507,10 @@ _pages: id: "Canvas ID" width: "Width" height: "Height" - note: "Embedded note" + note: "Embedded post" _note: - id: "Note ID" - idDescription: "You can alternatively paste the note URL here." + id: "Post ID" + idDescription: "You can alternatively paste the post URL here." detailed: "Detailed view" switch: "Switch" _switch: @@ -1729,7 +1731,7 @@ _notification: youGotMention: "{name} mentioned you" youGotReply: "{name} replied to you" youGotQuote: "{name} quoted you" - youRenoted: "Renote from {name}" + youRenoted: "Boost from {name}" youGotPoll: "{name} voted on your poll" youGotMessagingMessageFromUser: "{name} sent you a chat message" youGotMessagingMessageFromGroup: "A chat message was sent to the {name} group" @@ -1744,7 +1746,7 @@ _notification: follow: "New followers" mention: "Mentions" reply: "Replies" - renote: "Renotes" + renote: "Boosts" quote: "Quotes" reaction: "Reactions" pollVote: "Votes on polls" @@ -1756,7 +1758,7 @@ _notification: _actions: followBack: "followed you back" reply: "Reply" - renote: "Renote" + renote: "Boosts" _deck: alwaysShowMainColumn: "Always show main column" columnAlign: "Align columns" @@ -1782,4 +1784,4 @@ _deck: antenna: "Antennas" list: "List" mentions: "Mentions" - direct: "Direct notes" + direct: "Direct messages" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 92e305d92..1d35c878c 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -580,7 +580,6 @@ tokenRequested: "Permiso de acceso a la cuenta" pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí" notificationType: "Tipo de notificación" edit: "Editar" -useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella" emailServer: "Servidor de correo" enableEmail: "Activar el envío de correos electrónicos" emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 5c5e7089f..9f7028d3b 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -567,14 +567,13 @@ large: "Grand" medium: "Moyen" small: "Petit" generateAccessToken: "Générer un jeton d'accès" -permission: "Autorisations " +permission: "Autorisations" enableAll: "Tout activer" disableAll: "Tout désactiver" tokenRequested: "Autoriser l'accès au compte" pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies ici." notificationType: "Type de notifications" edit: "Editer" -useStarForReactionFallback: "Utiliser ★ comme alternative si l’émoji de réaction est inconnu" emailServer: "Serveur mail" enableEmail: "Activer la distribution de courriel" emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas d’oubli." diff --git a/locales/id-ID.yml b/locales/id-ID.yml index b83a70bc1..bb3904e2e 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -577,7 +577,6 @@ tokenRequested: "Berikan ijin akses ke akun" pluginTokenRequestedDescription: "Plugin ini dapat menggunakan setelan ijin disini." notificationType: "Jenis pemberitahuan" edit: "Sunting" -useStarForReactionFallback: "Gunakan ★ sebagai fallback jika reaksi emoji tidak diketahui" emailServer: "Peladen surel" enableEmail: "Nyalakan distribusi surel" emailConfigInfo: "Digunakan untuk mengonfirmasi surel kamu disaat mendaftar dan lupa kata sandi" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 9e188ae08..185d12d5a 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -573,7 +573,6 @@ tokenRequested: "Autorizza accesso all'account" pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui." notificationType: "Tipo di notifiche" edit: "Modifica" -useStarForReactionFallback: "Se è sconosciuto l'emoji di reazione, usare la ★ come alternativa." emailServer: "Server email" enableEmail: "Abilita consegna email" emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica e per reimpostare la tua password" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ba29131a5..867331cc9 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -583,7 +583,6 @@ tokenRequested: "アカウントへのアクセス許可" pluginTokenRequestedDescription: "このプラグインはここで設定した権限を行使できるようになります。" notificationType: "通知の種類" edit: "編集" -useStarForReactionFallback: "リアクション絵文字が不明な場合、代わりに★を使う" emailServer: "メールサーバー" enableEmail: "メール配信機能を有効化する" emailConfigInfo: "メールアドレスの確認やパスワードリセットの際に使います" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 02d9e87bb..d5c48276f 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -579,7 +579,6 @@ tokenRequested: "アカウントへのアクセス許可" pluginTokenRequestedDescription: "このプラグインはここで設定した権限を使えるようになるで。" notificationType: "通知の種類" edit: "編集" -useStarForReactionFallback: "リアクションがようわからん場合、★を使う" emailServer: "メールサーバー" enableEmail: "メール配信を受け取る" emailConfigInfo: "メールアドレスの確認とかパスワードリセットの時に使うで" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 8b2730a94..b87a4b06c 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -580,7 +580,6 @@ tokenRequested: "계정 접근 허용" pluginTokenRequestedDescription: "이 플러그인은 여기서 설정한 권한을 사용할 수 있게 됩니다." notificationType: "알림 유형" edit: "편집" -useStarForReactionFallback: "알 수 없는 리액션 이모지 대신 ★ 사용" emailServer: "메일 서버" enableEmail: "이메일 송신 기능 활성화" emailConfigInfo: "가입 시 메일 주소 확인이나 비밀번호 초기화 시에 사용합니다." diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index ce24665e8..a7cbec5b6 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -572,7 +572,6 @@ tokenRequested: "Przydziel dostęp do konta" pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawionych tu uprawnień." notificationType: "Rodzaj powiadomień" edit: "Edytuj" -useStarForReactionFallback: "Użyj ★ jako zapasowego emoji, gdy emoji reakcji jest nieznane" emailServer: "Serwer poczty e-mail" enableEmail: "Włącz dostarczanie wiadomości e-mail" emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji, lub gdy zapomnisz hasła" diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 1ccddd145..8408d4c77 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -576,7 +576,6 @@ tokenRequested: "Acordă acces la cont" pluginTokenRequestedDescription: "Acest plugin va putea să folosească permisiunile setate aici." notificationType: "Tipul notificării" edit: "Editează" -useStarForReactionFallback: "Folosește ★ ca fallback dacă emoji-ul este necunoscut" emailServer: "Server email" enableEmail: "Activează distribuția de emailuri" emailConfigInfo: "Folosit pentru a confirma emailul tău în timpul logări dacă îți uiți parola" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 6f985a5f6..9d76dc623 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -580,7 +580,6 @@ tokenRequested: "Открыть доступ к учётной записи" pluginTokenRequestedDescription: "Это расширение сможет пользоваться разрешениями, установленными здесь." notificationType: "Тип уведомления" edit: "Изменить" -useStarForReactionFallback: "Ставить ★ в качестве реакции вместо неизвестного эмодзи" emailServer: "Сервер электронной почты" enableEmail: "Включить обмен электронной почтой" emailConfigInfo: "Используется для подтверждения адреса электронной почты и сброса пароля." diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 38ded0c8f..ced0d67b7 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -579,7 +579,6 @@ tokenRequested: "Povoliť prístup k účtu" pluginTokenRequestedDescription: "Tento plugin bude môcť používať oprávnenia nastavené tu." notificationType: "Typ oznámenia" edit: "Upraviť" -useStarForReactionFallback: "Použiť ★ keď emoji reakcie nie je známe" emailServer: "Email server" enableEmail: "Zapnúť email" emailConfigInfo: "Používa sa na overenie emaily pri registrácii alebo pri zabudnutí hesla" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 6f0a28b08..173548e90 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -580,7 +580,6 @@ tokenRequested: "ให้สิทธิ์การเข้าถึงบั pluginTokenRequestedDescription: "ปลั๊กอินนี้จะสามารถใช้การอนุญาตที่ตั้งค่าไว้ที่นี่นะ" notificationType: "ประเภทการแจ้งเตือน" edit: "แก้ไข" -useStarForReactionFallback: "ใช้ ★ เป็นทางเลือกแทนถ้าหากไม่ทราบอิโมจิ" emailServer: "อีเมล์เซิร์ฟเวอร์" enableEmail: "เปิดใช้งานการกระจายอีเมล" emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างการสมัครหรือถ้าหากคุณลืมรหัสผ่าน" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 053827fa1..63caf22c1 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -577,7 +577,6 @@ tokenRequested: "Надати доступ до акаунту" pluginTokenRequestedDescription: "Цей плагін зможе використовувати дозволи які тут вказані." notificationType: "Тип сповіщення" edit: "Редагувати" -useStarForReactionFallback: "Використовувати ★ як запасний варіант, якщо емодзі реакції невідомий" emailServer: "Сервер електронної пошти" enableEmail: "Увімкнути функцію доставки пошти" emailConfigInfo: "Використовується для підтвердження електронної пошти підчас реєстрації, а також для відновлення паролю." diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index bd0ab3e45..4f38b80c8 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -580,7 +580,6 @@ tokenRequested: "Cấp quyền truy cập vào tài khoản" pluginTokenRequestedDescription: "Plugin này sẽ có thể sử dụng các quyền được đặt ở đây." notificationType: "Loại thông báo" edit: "Sửa" -useStarForReactionFallback: "Dùng ★ nếu emoji biểu cảm không có" emailServer: "Email máy chủ" enableEmail: "Bật phân phối email" emailConfigInfo: "Được dùng để xác minh email của bạn lúc đăng ký hoặc nếu bạn quên mật khẩu của mình" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index e4782914a..310121c5a 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -580,7 +580,6 @@ tokenRequested: "允许访问账户" pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限" notificationType: "通知类型" edit: "编辑" -useStarForReactionFallback: "如果回应的是未知表情符号,则使用★作为代替" emailServer: "邮件服务器" enableEmail: "启用发送邮件功能" emailConfigInfo: "用于确认电子邮件和密码重置" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 892cdbcf1..e7528f9a2 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -580,7 +580,6 @@ tokenRequested: "允許存取帳戶" pluginTokenRequestedDescription: "此外掛將擁有在此設定的權限。" notificationType: "通知形式" edit: "編輯" -useStarForReactionFallback: "以★代替未知的表情符號" emailServer: "電郵伺服器" enableEmail: "啟用發送電郵功能" emailConfigInfo: "用於確認電郵地址及密碼重置" diff --git a/package.json b/package.json index e9794c30a..a7b90f8dc 100644 --- a/package.json +++ b/package.json @@ -1,51 +1,45 @@ { "name": "calckey", - "version": "13.0.5", + "version": "13.1.0", "codename": "aqua", "repository": { "type": "git", "url": "https://codeberg.org/calckey/calckey.git" }, - "packageManager": "yarn@3.3.0", - "workspaces": [ - "packages/client", - "packages/backend", - "packages/sw" - ], + "packageManager": "pnpm@7.26.3", "private": true, "scripts": { - "rebuild": "yarn clean && yarn workspaces foreach run build && yarn run gulp", - "build": "yarn workspaces foreach run build && yarn run gulp", - "start": "yarn workspace backend run start", - "start:test": "yarn workspace backend run start:test", - "init": "yarn migrate", - "migrate": "yarn workspace backend run migrate", - "revertmigration": "yarn workspace backend run revertmigration", - "migrateandstart": "yarn migrate && yarn start", + "rebuild": "pnpm run clean && pnpm -r run build && pnpm run gulp", + "build": "pnpm -r run build && pnpm run gulp", + "start": "pnpm --filter backend run start", + "start:test": "pnpm --filter backend run start:test", + "init": "pnpm run migrate", + "migrate": "pnpm --filter backend run migrate", + "revertmigration": "pnpm --filter backend run revertmigration", + "migrateandstart": "pnpm run migrate && pnpm run start", "gulp": "gulp build", - "watch": "yarn dev", - "dev": "node ./scripts/dev.js", - "lint": "yarn workspaces foreach run lint", + "watch": "pnpm run dev", + "dev": "pnpm node ./scripts/dev.js", + "lint": "pnpm -r run lint", "cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts", "cy:run": "cypress run", "e2e": "start-server-and-test start:test http://localhost:61812 cy:run", - "mocha": "yarn workspace backend run mocha", - "test": "yarn mocha", + "mocha": "pnpm --filter backend run mocha", + "test": "pnpm run mocha", "format": "gulp format", - "clean": "node ./scripts/clean.js", - "clean-all": "node ./scripts/clean-all.js", - "cleanall": "yarn clean-all" + "clean": "pnpm node ./scripts/clean.js", + "clean-all": "pnpm node ./scripts/clean-all.js", + "cleanall": "pnpm run clean-all" }, "resolutions": { "chokidar": "^3.3.1", "lodash": "^4.17.21" }, "dependencies": { - "@bull-board/api": "^4.6.4", - "@bull-board/ui": "^4.6.4", + "@bull-board/api": "^4.10.2", + "@bull-board/ui": "^4.10.2", "@tensorflow/tfjs": "^3.21.0", - "calckey-js": "^0.0.17", - "eslint": "^8.30.0", + "calckey-js": "^0.0.20", "execa": "5.1.1", "gulp": "4.0.2", "gulp-cssnano": "2.1.3", @@ -60,11 +54,11 @@ "devDependencies": { "@types/gulp": "4.0.10", "@types/gulp-rename": "2.0.1", - "@typescript-eslint/parser": "5.46.1", "cross-env": "7.0.3", "cypress": "10.11.0", + "install-peers": "^1.0.4", + "rome": "^11.0.0", "start-server-and-test": "1.15.2", - "typescript": "4.9.4", - "vue-eslint-parser": "^9.1.0" + "typescript": "4.9.4" } } diff --git a/packages/backend/.eslintignore b/packages/backend/.eslintignore deleted file mode 100644 index 790eb9014..000000000 --- a/packages/backend/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -/built -/.eslintrc.js -/@types/**/* diff --git a/packages/backend/.eslintrc.cjs b/packages/backend/.eslintrc.cjs deleted file mode 100644 index 5a06889dc..000000000 --- a/packages/backend/.eslintrc.cjs +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../shared/.eslintrc.js', - ], - rules: { - 'import/order': ['warn', { - 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - 'pathGroups': [ - { - 'pattern': '@/**', - 'group': 'external', - 'position': 'after' - } - ], - }], - 'no-restricted-globals': [ - 'error', - { - 'name': '__dirname', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - }, - { - 'name': '__filename', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - } - ] - }, -}; diff --git a/packages/backend/.swcrc b/packages/backend/.swcrc new file mode 100644 index 000000000..39e112ff7 --- /dev/null +++ b/packages/backend/.swcrc @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "dynamicImport": true, + "decorators": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + }, + "experimental": { + "keepImportAssertions": true + }, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + }, + "target": "es2022" + }, + "minify": false +} diff --git a/packages/backend/assets/icons/maskable.png b/packages/backend/assets/icons/maskable.png new file mode 100644 index 000000000..00edeaaac --- /dev/null +++ b/packages/backend/assets/icons/maskable.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9acf00c45965a91671844dd58593d6a6180a566c97d8ecb79f27b47aaef7b64a +size 10653 diff --git a/packages/backend/assets/icons/monochrome.png b/packages/backend/assets/icons/monochrome.png new file mode 100644 index 000000000..17ecc9271 --- /dev/null +++ b/packages/backend/assets/icons/monochrome.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a68ea0d3a1877fde5a3dc49de1fe6c3ea1dfd958a1f40fd7d6745ee2d34ec287 +size 6538 diff --git a/packages/backend/migration/1672882664294-DefaultReaction.js b/packages/backend/migration/1672882664294-DefaultReaction.js new file mode 100644 index 000000000..498a1810d --- /dev/null +++ b/packages/backend/migration/1672882664294-DefaultReaction.js @@ -0,0 +1,12 @@ +export class DefaultReaction1672882664294 { + name = 'DefaultReaction1672882664294' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "defaultReaction" character varying(256) NOT NULL DEFAULT '⭐'`); + await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS 'The fallback reaction for emoji reacts'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultReaction"`); + } +} diff --git a/packages/backend/migration/1673336077243-PollChoiceLength.js b/packages/backend/migration/1673336077243-PollChoiceLength.js new file mode 100644 index 000000000..13db7dd96 --- /dev/null +++ b/packages/backend/migration/1673336077243-PollChoiceLength.js @@ -0,0 +1,11 @@ +export class PollChoiceLength1673336077243 { + name = 'PollChoiceLength1673336077243' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(256) array`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(128) array`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 699e1aa1c..d4b9c1903 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -4,21 +4,22 @@ "private": true, "type": "module", "scripts": { - "start": "node ./built/index.js", - "start:test": "NODE_ENV=test node ./built/index.js", + "start": "pnpm node ./built/index.js", + "start:test": "NODE_ENV=test pnpm node ./built/index.js", "migrate": "typeorm migration:run -d ormconfig.js", "revertmigration": "typeorm migration:revert -d ormconfig.js", - "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", - "watch": "node watch.mjs", - "lint": "eslint --quiet \"src/**/*.ts\"", + "build": "pnpm swc src -d built -D", + "watch": "pnpm swc src -d built -D -w", + "lint": "pnpm rome check \"src/**/*.ts\"", "mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha", - "test": "npm run mocha" + "test": "pnpm run mocha" }, "resolutions": { "chokidar": "^3.3.1", "lodash": "^4.17.21" }, "optionalDependencies": { + "@swc/core-android-arm64": "1.3.11", "@tensorflow/tfjs-node": "3.21.1" }, "dependencies": { @@ -29,10 +30,14 @@ "@elastic/elasticsearch": "7.17.0", "@koa/cors": "3.4.3", "@koa/multer": "3.0.0", - "@koa/router": "9.4.0", + "@koa/router": "9.0.1", "@peertube/http-signature": "1.7.0", + "@redocly/openapi-core": "1.0.0-beta.120", "@sinonjs/fake-timers": "9.1.2", + "@swc/cli": "^0.1.59", + "@swc/core": "^1.3.26", "@syuilo/aiscript": "0.11.1", + "@tensorflow/tfjs": "^4.2.0", "ajv": "8.11.2", "archiver": "5.3.1", "autobind-decorator": "2.4.0", @@ -42,7 +47,7 @@ "blurhash": "1.1.5", "bull": "4.10.2", "cacheable-lookup": "7.0.0", - "calckey-js": "^0.0.17", + "calckey-js": "^0.0.20", "cbor": "8.1.0", "chalk": "5.2.0", "chalk-template": "0.4.0", @@ -58,12 +63,12 @@ "fluent-ffmpeg": "2.1.2", "got": "12.5.3", "hpagent": "0.1.2", - "ioredis": "4.28.5", + "ioredis": "5.2.4", "ip-cidr": "3.0.11", "is-svg": "4.3.2", "js-yaml": "4.1.0", "jsdom": "20.0.3", - "json5": "2.2.2", + "json5": "2.2.3", "json5-loader": "4.0.1", "jsonld": "6.0.0", "jsrsasign": "10.6.1", @@ -76,7 +81,7 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", - "mfm-js": "0.23.0", + "mfm-js": "0.23.2", "mime-types": "2.1.35", "mocha": "10.2.0", "multer": "1.4.4-lts.1", @@ -93,7 +98,7 @@ "promise-limit": "2.7.0", "pug": "3.0.2", "punycode": "2.1.1", - "pureimage": "0.3.14", + "pureimage": "0.3.15", "qrcode": "1.5.1", "random-seed": "0.3.0", "ratelimiter": "3.4.1", @@ -104,22 +109,22 @@ "rndstr": "1.0.0", "rss-parser": "3.12.0", "s-age": "1.1.2", - "sanitize-html": "2.8.0", + "sanitize-html": "2.8.1", + "seedrandom": "^3.0.5", "semver": "7.3.8", - "sharp": "0.31.2", + "sharp": "0.31.3", "speakeasy": "2.0.0", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "summaly": "2.7.0", "syslog-pro": "1.0.0", - "systeminformation": "5.16.6", + "systeminformation": "5.16.9", "tesseract.js": "^3.0.3", - "tinycolor2": "1.4.2", + "tinycolor2": "1.5.2", "tmp": "0.2.1", "ts-loader": "9.4.2", "ts-node": "10.9.1", - "tsc-alias": "1.8.2", - "tsconfig-paths": "4.1.1", + "tsconfig-paths": "4.1.2", "twemoji-parser": "14.0.0", "typeorm": "0.3.11", "ulid": "2.3.0", @@ -131,7 +136,6 @@ "xev": "3.0.2" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.114", "@types/bcryptjs": "2.4.2", "@types/bull": "3.15.9", "@types/cbor": "6.0.0", @@ -153,7 +157,7 @@ "@types/koa__multer": "2.0.4", "@types/koa__router": "8.0.11", "@types/mocha": "9.1.1", - "@types/node": "18.11.17", + "@types/node": "18.11.18", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.7", "@types/oauth": "0.9.1", @@ -166,7 +170,7 @@ "@types/rename": "1.0.4", "@types/sanitize-html": "2.8.0", "@types/semver": "7.3.13", - "@types/sharp": "0.31.0", + "@types/sharp": "0.31.1", "@types/sinonjs__fake-timers": "8.1.2", "@types/speakeasy": "2.0.7", "@types/tinycolor2": "1.4.3", @@ -175,12 +179,11 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.46.1", - "@typescript-eslint/parser": "5.46.1", "cross-env": "7.0.3", - "eslint": "8.30.0", - "eslint-plugin-import": "2.26.0", + "eslint": "^8.31.0", "execa": "6.1.0", - "typescript": "4.9.4" + "swc-loader": "^0.2.3", + "typescript": "4.9.4", + "webpack": "^5.75.0" } } diff --git a/packages/backend/src/@types/hcaptcha.d.ts b/packages/backend/src/@types/hcaptcha.d.ts index afed58756..21f65c678 100644 --- a/packages/backend/src/@types/hcaptcha.d.ts +++ b/packages/backend/src/@types/hcaptcha.d.ts @@ -1,11 +1,14 @@ -declare module 'hcaptcha' { +declare module "hcaptcha" { interface IVerifyResponse { success: boolean; challenge_ts: string; hostname: string; credit?: boolean; - 'error-codes'?: unknown[]; + "error-codes"?: unknown[]; } - export function verify(secret: string, token: string): Promise; + export function verify( + secret: string, + token: string, + ): Promise; } diff --git a/packages/backend/src/@types/http-signature.d.ts b/packages/backend/src/@types/http-signature.d.ts index d1f9cd955..3bfece8cb 100644 --- a/packages/backend/src/@types/http-signature.d.ts +++ b/packages/backend/src/@types/http-signature.d.ts @@ -1,5 +1,5 @@ -declare module '@peertube/http-signature' { - import { IncomingMessage, ClientRequest } from 'node:http'; +declare module "@peertube/http-signature" { + import type { IncomingMessage, ClientRequest } from "node:http"; interface ISignature { keyId: string; @@ -28,8 +28,8 @@ declare module '@peertube/http-signature' { } type RequestSignerConstructorOptions = - IRequestSignerConstructorOptionsFromProperties | - IRequestSignerConstructorOptionsFromFunction; + | IRequestSignerConstructorOptionsFromProperties + | IRequestSignerConstructorOptionsFromFunction; interface IRequestSignerConstructorOptionsFromProperties { keyId: string; @@ -59,11 +59,23 @@ declare module '@peertube/http-signature' { httpVersion?: string; } - export function parse(request: IncomingMessage, options?: IParseRequestOptions): IParsedSignature; - export function parseRequest(request: IncomingMessage, options?: IParseRequestOptions): IParsedSignature; + export function parse( + request: IncomingMessage, + options?: IParseRequestOptions, + ): IParsedSignature; + export function parseRequest( + request: IncomingMessage, + options?: IParseRequestOptions, + ): IParsedSignature; - export function sign(request: ClientRequest, options: ISignRequestOptions): boolean; - export function signRequest(request: ClientRequest, options: ISignRequestOptions): boolean; + export function sign( + request: ClientRequest, + options: ISignRequestOptions, + ): boolean; + export function signRequest( + request: ClientRequest, + options: ISignRequestOptions, + ): boolean; export function createSigner(): RequestSigner; export function isSigner(obj: any): obj is RequestSigner; @@ -71,7 +83,16 @@ declare module '@peertube/http-signature' { export function sshKeyFingerprint(key: string): string; export function pemToRsaSSHKey(pem: string, comment: string): string; - export function verify(parsedSignature: IParsedSignature, pubkey: string | Buffer): boolean; - export function verifySignature(parsedSignature: IParsedSignature, pubkey: string | Buffer): boolean; - export function verifyHMAC(parsedSignature: IParsedSignature, secret: string): boolean; + export function verify( + parsedSignature: IParsedSignature, + pubkey: string | Buffer, + ): boolean; + export function verifySignature( + parsedSignature: IParsedSignature, + pubkey: string | Buffer, + ): boolean; + export function verifyHMAC( + parsedSignature: IParsedSignature, + secret: string, + ): boolean; } diff --git a/packages/backend/src/@types/koa-json-body.d.ts b/packages/backend/src/@types/koa-json-body.d.ts index 5aa8179c5..e5282d81b 100644 --- a/packages/backend/src/@types/koa-json-body.d.ts +++ b/packages/backend/src/@types/koa-json-body.d.ts @@ -1,5 +1,5 @@ -declare module 'koa-json-body' { - import { Middleware } from 'koa'; +declare module "koa-json-body" { + import type { Middleware } from "koa"; interface IKoaJsonBodyOptions { strict: boolean; diff --git a/packages/backend/src/@types/koa-slow.d.ts b/packages/backend/src/@types/koa-slow.d.ts index e748e2cc9..e24be51e2 100644 --- a/packages/backend/src/@types/koa-slow.d.ts +++ b/packages/backend/src/@types/koa-slow.d.ts @@ -1,5 +1,5 @@ -declare module 'koa-slow' { - import { Middleware } from 'koa'; +declare module "koa-slow" { + import type { Middleware } from "koa"; interface ISlowOptions { url?: RegExp; diff --git a/packages/backend/src/@types/os-utils.d.ts b/packages/backend/src/@types/os-utils.d.ts index 390df17d3..504096ae2 100644 --- a/packages/backend/src/@types/os-utils.d.ts +++ b/packages/backend/src/@types/os-utils.d.ts @@ -1,4 +1,4 @@ -declare module 'os-utils' { +declare module "os-utils" { type FreeCommandCallback = (usedmem: number) => void; type HarddriveCallback = (total: number, free: number, used: number) => void; @@ -20,7 +20,10 @@ declare module 'os-utils' { export function harddrive(callback: HarddriveCallback): void; export function getProcesses(callback: GetProcessesCallback): void; - export function getProcesses(nProcess: number, callback: GetProcessesCallback): void; + export function getProcesses( + nProcess: number, + callback: GetProcessesCallback, + ): void; export function allLoadavg(): string; export function loadavg(_time?: number): number; diff --git a/packages/backend/src/@types/package.json.d.ts b/packages/backend/src/@types/package.json.d.ts index abe5fae68..d8ec63644 100644 --- a/packages/backend/src/@types/package.json.d.ts +++ b/packages/backend/src/@types/package.json.d.ts @@ -1,4 +1,4 @@ -declare module '*/package.json' { +declare module "*/package.json" { interface IRepository { type: string; url: string; diff --git a/packages/backend/src/@types/probe-image-size.d.ts b/packages/backend/src/@types/probe-image-size.d.ts index 11bb6c620..4ed13df7f 100644 --- a/packages/backend/src/@types/probe-image-size.d.ts +++ b/packages/backend/src/@types/probe-image-size.d.ts @@ -1,5 +1,5 @@ -declare module 'probe-image-size' { - import { ReadStream } from 'node:fs'; +declare module "probe-image-size" { + import type { ReadStream } from "node:fs"; type ProbeOptions = { retries: 1; @@ -12,14 +12,24 @@ declare module 'probe-image-size' { length?: number; type: string; mime: string; - wUnits: 'in' | 'mm' | 'cm' | 'pt' | 'pc' | 'px' | 'em' | 'ex'; - hUnits: 'in' | 'mm' | 'cm' | 'pt' | 'pc' | 'px' | 'em' | 'ex'; + wUnits: "in" | "mm" | "cm" | "pt" | "pc" | "px" | "em" | "ex"; + hUnits: "in" | "mm" | "cm" | "pt" | "pc" | "px" | "em" | "ex"; url?: string; }; - function probeImageSize(src: string | ReadStream, options?: ProbeOptions): Promise; - function probeImageSize(src: string | ReadStream, callback: (err: Error | null, result?: ProbeResult) => void): void; - function probeImageSize(src: string | ReadStream, options: ProbeOptions, callback: (err: Error | null, result?: ProbeResult) => void): void; + function probeImageSize( + src: string | ReadStream, + options?: ProbeOptions, + ): Promise; + function probeImageSize( + src: string | ReadStream, + callback: (err: Error | null, result?: ProbeResult) => void, + ): void; + function probeImageSize( + src: string | ReadStream, + options: ProbeOptions, + callback: (err: Error | null, result?: ProbeResult) => void, + ): void; namespace probeImageSize {} // Hack diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts index 694682e72..4e1d94765 100644 --- a/packages/backend/src/boot/index.ts +++ b/packages/backend/src/boot/index.ts @@ -1,28 +1,27 @@ -import cluster from 'node:cluster'; -import chalk from 'chalk'; -import Xev from 'xev'; +import cluster from "node:cluster"; +import chalk from "chalk"; +import Xev from "xev"; -import Logger from '@/services/logger.js'; -import { envOption } from '../env.js'; +import Logger from "@/services/logger.js"; +import { envOption } from "../env.js"; // for typeorm -import 'reflect-metadata'; -import { masterMain } from './master.js'; -import { workerMain } from './worker.js'; +import "reflect-metadata"; +import { masterMain } from "./master.js"; +import { workerMain } from "./worker.js"; -const logger = new Logger('core', 'cyan'); -const clusterLogger = logger.createSubLogger('cluster', 'orange', false); +const logger = new Logger("core", "cyan"); +const clusterLogger = logger.createSubLogger("cluster", "orange", false); const ev = new Xev(); /** * Init process */ -export default async function() { - process.title = `Calckey (${cluster.isPrimary ? 'master' : 'worker'})`; +export default async function () { + process.title = `Calckey (${cluster.isPrimary ? "master" : "worker"})`; if (cluster.isPrimary || envOption.disableClustering) { await masterMain(); - if (cluster.isPrimary) { ev.mount(); } @@ -32,27 +31,27 @@ export default async function() { await workerMain(); } - // ユニットテスト時にMisskeyが子プロセスで起動された時のため - // それ以外のときは process.send は使えないので弾く + // For when Calckey is started in a child process during unit testing. + // Otherwise, process.send cannot be used, so start it. if (process.send) { - process.send('ok'); + process.send("ok"); } } //#region Events // Listen new workers -cluster.on('fork', worker => { +cluster.on("fork", (worker) => { clusterLogger.debug(`Process forked: [${worker.id}]`); }); // Listen online workers -cluster.on('online', worker => { +cluster.on("online", (worker) => { clusterLogger.debug(`Process is now online: [${worker.id}]`); }); // Listen for dying workers -cluster.on('exit', worker => { +cluster.on("exit", (worker) => { // Replace the dead worker, // we're not sentimental clusterLogger.error(chalk.red(`[${worker.id}] died :(`)); @@ -61,18 +60,18 @@ cluster.on('exit', worker => { // Display detail of unhandled promise rejection if (!envOption.quiet) { - process.on('unhandledRejection', console.dir); + process.on("unhandledRejection", console.dir); } // Display detail of uncaught exception -process.on('uncaughtException', err => { +process.on("uncaughtException", (err) => { try { logger.error(err); - } catch { } + } catch {} }); // Dying away... -process.on('exit', code => { +process.on("exit", (code) => { logger.info(`The process is going to exit with code ${code}`); }); diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index f8e4059e7..193f02429 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -1,50 +1,64 @@ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import * as os from 'node:os'; -import cluster from 'node:cluster'; -import chalk from 'chalk'; -import chalkTemplate from 'chalk-template'; -import semver from 'semver'; +import * as fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import * as os from "node:os"; +import cluster from "node:cluster"; +import chalk from "chalk"; +import chalkTemplate from "chalk-template"; +import semver from "semver"; -import Logger from '@/services/logger.js'; -import loadConfig from '@/config/load.js'; -import { Config } from '@/config/types.js'; -import { lessThan } from '@/prelude/array.js'; -import { envOption } from '../env.js'; -import { showMachineInfo } from '@/misc/show-machine-info.js'; -import { db, initDb } from '../db/postgre.js'; +import Logger from "@/services/logger.js"; +import loadConfig from "@/config/load.js"; +import type { Config } from "@/config/types.js"; +import { lessThan } from "@/prelude/array.js"; +import { envOption } from "../env.js"; +import { showMachineInfo } from "@/misc/show-machine-info.js"; +import { db, initDb } from "../db/postgre.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); -const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8')); +const meta = JSON.parse( + fs.readFileSync(`${_dirname}/../../../../built/meta.json`, "utf-8"), +); -const logger = new Logger('core', 'cyan'); -const bootLogger = logger.createSubLogger('boot', 'magenta', false); +const logger = new Logger("core", "cyan"); +const bootLogger = logger.createSubLogger("boot", "magenta", false); -const themeColor = chalk.hex('#31748f'); +const themeColor = chalk.hex("#31748f"); function greet() { if (!envOption.quiet) { //#region Calckey logo const v = `v${meta.version}`; - console.log(themeColor(' ___ _ _ ')); - console.log(themeColor(' / __\\__ _| | ___| | _____ _ _ ')); - console.log(themeColor(' / / / _` | |/ __| |/ / _ \ | | |')); - console.log(themeColor('/ /__| (_| | | (__| < __/ |_| |')); - console.log(themeColor('\\____/\\__,_|_|\\___|_|\\_\\___|\\__, |')); - console.log(themeColor(' (___/ ')); + console.log(themeColor(" ___ _ _ ")); + console.log(themeColor(" / __\\__ _| | ___| | _____ _ _ ")); + console.log(themeColor(" / / / _` | |/ __| |/ / _ | | |")); + console.log(themeColor("/ /__| (_| | | (__| < __/ |_| |")); + console.log(themeColor("\\____/\\__,_|_|\\___|_|\\_\\___|\\__, |")); + console.log(themeColor(" (___/ ")); //#endregion - console.log(' Calckey is an open-source decentralized microblogging platform.'); - console.log(chalk.rgb(255, 136, 0)(' If you like Calckey, please consider starring or contributing to the repo. https://codeberg.org/calckey/calckey')); + console.log( + " Calckey is an open-source decentralized microblogging platform.", + ); + console.log( + chalk.rgb( + 255, + 136, + 0, + )( + " If you like Calckey, please consider starring or contributing to the repo. https://codeberg.org/calckey/calckey", + ), + ); - console.log(''); - console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`); + console.log(""); + console.log( + chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`, + ); } - bootLogger.info('Welcome to Calckey!'); + bootLogger.info("Welcome to Calckey!"); bootLogger.info(`Calckey v${meta.version}`, null, true); } @@ -63,42 +77,50 @@ export async function masterMain() { config = loadConfigBoot(); await connectDb(); } catch (e) { - bootLogger.error('Fatal error occurred during initialization', null, true); + bootLogger.error("Fatal error occurred during initialization", null, true); process.exit(1); } - bootLogger.succ('Calckey initialized'); + bootLogger.succ("Calckey initialized"); if (!envOption.disableClustering) { await spawnWorkers(config.clusterLimit); } - bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); + bootLogger.succ( + `Now listening on port ${config.port} on ${config.url}`, + null, + true, + ); if (!envOption.noDaemons) { - import('../daemons/server-stats.js').then(x => x.default()); - import('../daemons/queue-stats.js').then(x => x.default()); - import('../daemons/janitor.js').then(x => x.default()); + import("../daemons/server-stats.js").then((x) => x.default()); + import("../daemons/queue-stats.js").then((x) => x.default()); + import("../daemons/janitor.js").then((x) => x.default()); } } function showEnvironment(): void { const env = process.env.NODE_ENV; - const logger = bootLogger.createSubLogger('env'); - logger.info(typeof env === 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`); + const logger = bootLogger.createSubLogger("env"); + logger.info( + typeof env === "undefined" ? "NODE_ENV is not set" : `NODE_ENV: ${env}`, + ); - if (env !== 'production') { - logger.warn('The environment is not in production mode.'); - logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', null, true); + if (env !== "production") { + logger.warn("The environment is not in production mode."); + logger.warn("DO NOT USE FOR PRODUCTION PURPOSE!", null, true); } } function showNodejsVersion(): void { - const nodejsLogger = bootLogger.createSubLogger('nodejs'); + const nodejsLogger = bootLogger.createSubLogger("nodejs"); nodejsLogger.info(`Version ${process.version} detected.`); - const minVersion = fs.readFileSync(`${_dirname}/../../../../.node-version`, 'utf-8').trim(); + const minVersion = fs + .readFileSync(`${_dirname}/../../../../.node-version`, "utf-8") + .trim(); if (semver.lt(process.version, minVersion)) { nodejsLogger.error(`At least Node.js ${minVersion} required!`); process.exit(1); @@ -106,14 +128,14 @@ function showNodejsVersion(): void { } function loadConfigBoot(): Config { - const configLogger = bootLogger.createSubLogger('config'); + const configLogger = bootLogger.createSubLogger("config"); let config; try { config = loadConfig(); } catch (exception) { - if (exception.code === 'ENOENT') { - configLogger.error('Configuration file not found', null, true); + if (exception.code === "ENOENT") { + configLogger.error("Configuration file not found", null, true); process.exit(1); } else if (e instanceof Error) { configLogger.error(e.message); @@ -122,22 +144,24 @@ function loadConfigBoot(): Config { throw exception; } - configLogger.succ('Loaded'); + configLogger.succ("Loaded"); return config; } async function connectDb(): Promise { - const dbLogger = bootLogger.createSubLogger('db'); + const dbLogger = bootLogger.createSubLogger("db"); // Try to connect to DB try { - dbLogger.info('Connecting...'); + dbLogger.info("Connecting..."); await initDb(); - const v = await db.query('SHOW server_version').then(x => x[0].server_version); + const v = await db + .query("SHOW server_version") + .then((x) => x[0].server_version); dbLogger.succ(`Connected: v${v}`); } catch (e) { - dbLogger.error('Cannot connect', null, true); + dbLogger.error("Cannot connect", null, true); dbLogger.error(e); process.exit(1); } @@ -145,20 +169,20 @@ async function connectDb(): Promise { async function spawnWorkers(limit: number = 1) { const workers = Math.min(limit, os.cpus().length); - bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`); + bootLogger.info(`Starting ${workers} worker${workers === 1 ? "" : "s"}...`); await Promise.all([...Array(workers)].map(spawnWorker)); - bootLogger.succ('All workers started'); + bootLogger.succ("All workers started"); } function spawnWorker(): Promise { - return new Promise(res => { + return new Promise((res) => { const worker = cluster.fork(); - worker.on('message', message => { - if (message === 'listenFailed') { - bootLogger.error(`The server Listen failed due to the previous error.`); + worker.on("message", (message) => { + if (message === "listenFailed") { + bootLogger.error("The server Listen failed due to the previous error."); process.exit(1); } - if (message !== 'ready') return; + if (message !== "ready") return; res(); }); }); diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index 8038e2563..70442b096 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -1,5 +1,5 @@ -import cluster from 'node:cluster'; -import { initDb } from '../db/postgre.js'; +import cluster from "node:cluster"; +import { initDb } from "../db/postgre.js"; /** * Init worker process @@ -8,13 +8,13 @@ export async function workerMain() { await initDb(); // start server - await import('../server/index.js').then(x => x.default()); + await import("../server/index.js").then((x) => x.default()); // start job queue - import('../queue/index.js').then(x => x.default()); + import("../queue/index.js").then((x) => x.default()); if (cluster.isWorker) { // Send a 'ready' message to parent process - process.send!('ready'); + process.send!("ready"); } } diff --git a/packages/backend/src/config/index.ts b/packages/backend/src/config/index.ts index 3e53b0003..ae197b09c 100644 --- a/packages/backend/src/config/index.ts +++ b/packages/backend/src/config/index.ts @@ -1,3 +1,3 @@ -import load from './load.js'; +import load from "./load.js"; export default load(); diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index c479ccc40..9b8ee5edb 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -2,11 +2,11 @@ * Config loader */ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import * as yaml from 'js-yaml'; -import type { Source, Mixin } from './types.js'; +import * as fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import * as yaml from "js-yaml"; +import type { Source, Mixin } from "./types.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -19,14 +19,20 @@ const dir = `${_dirname}/../../../../.config`; /** * Path of configuration file */ -const path = process.env.NODE_ENV === 'test' - ? `${dir}/test.yml` - : `${dir}/default.yml`; +const path = + process.env.NODE_ENV === "test" ? `${dir}/test.yml` : `${dir}/default.yml`; export default function load() { - const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8')); - const clientManifest = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/_client_dist_/manifest.json`, 'utf-8')); - const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; + const meta = JSON.parse( + fs.readFileSync(`${_dirname}/../../../../built/meta.json`, "utf-8"), + ); + const clientManifest = JSON.parse( + fs.readFileSync( + `${_dirname}/../../../../built/_client_dist_/manifest.json`, + "utf-8", + ), + ); + const config = yaml.load(fs.readFileSync(path, "utf-8")) as Source; const mixin = {} as Mixin; @@ -34,19 +40,19 @@ export default function load() { config.url = url.origin; - config.port = config.port || parseInt(process.env.PORT || '', 10); + config.port = config.port || parseInt(process.env.PORT || "", 10); mixin.version = meta.version; mixin.host = url.host; mixin.hostname = url.hostname; - mixin.scheme = url.protocol.replace(/:$/, ''); - mixin.wsScheme = mixin.scheme.replace('http', 'ws'); + mixin.scheme = url.protocol.replace(/:$/, ""); + mixin.wsScheme = mixin.scheme.replace("http", "ws"); mixin.wsUrl = `${mixin.wsScheme}://${mixin.host}`; mixin.apiUrl = `${mixin.scheme}://${mixin.host}/api`; mixin.authUrl = `${mixin.scheme}://${mixin.host}/auth`; mixin.driveUrl = `${mixin.scheme}://${mixin.host}/files`; mixin.userAgent = `Calckey/${meta.version} (${config.url})`; - mixin.clientEntry = clientManifest['src/init.ts']; + mixin.clientEntry = clientManifest["src/init.ts"]; if (!config.redis.prefix) config.redis.prefix = mixin.host; diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index 9872b0eeb..e9c42c08f 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -47,7 +47,7 @@ export type Source = { id: string; - outgoingAddressFamily?: 'ipv4' | 'ipv6' | 'dual'; + outgoingAddressFamily?: "ipv4" | "ipv6" | "dual"; deliverJobConcurrency?: number; inboxJobConcurrency?: number; @@ -64,6 +64,12 @@ export type Source = { mediaProxy?: string; proxyRemoteFiles?: boolean; + twa: { + nameSpace?: string; + packageName?: string; + sha256CertFingerprints?: string[]; + }; + // Managed hosting stuff maxUserSignups?: number; isManagedHosting?: boolean; @@ -81,7 +87,6 @@ export type Source = { user?: string; pass?: string; useImplicitSslTls?: boolean; - }; objectStorage: { managed?: boolean; diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts index 172edca0d..82a093100 100644 --- a/packages/backend/src/const.ts +++ b/packages/backend/src/const.ts @@ -1,55 +1,63 @@ -import config from '@/config/index.js'; +import config from "@/config/index.js"; -export const MAX_NOTE_TEXT_LENGTH = config.maxNoteLength != null ? config.maxNoteLength : 3000; +export const MAX_NOTE_TEXT_LENGTH = + config.maxNoteLength != null ? config.maxNoteLength : 3000; // <- should we increase this? export const SECOND = 1000; -export const SEC = 1000; +export const SEC = 1000; // why do we need this duplicate here? export const MINUTE = 60 * SEC; -export const MIN = 60 * SEC; +export const MIN = 60 * SEC; // why do we need this duplicate here? export const HOUR = 60 * MIN; export const DAY = 24 * HOUR; -export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min -export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days +export const USER_ONLINE_THRESHOLD = 10 * MINUTE; +export const USER_ACTIVE_THRESHOLD = 3 * DAY; -// ブラウザで直接表示することを許可するファイルの種類のリスト -// ここに含まれないものは application/octet-stream としてレスポンスされる -// SVGはXSSを生むので許可しない +// List of file types allowed to be viewed directly in the browser +// Anything not included here will be responded as application/octet-stream +// SVG is not allowed because it generates XSS <- we need to fix this and later allow it to be viewed directly export const FILE_TYPE_BROWSERSAFE = [ // Images - 'image/png', - 'image/gif', - 'image/jpeg', - 'image/webp', - 'image/apng', - 'image/bmp', - 'image/tiff', - 'image/x-icon', + "image/png", + "image/gif", // TODO: deprecated, but still used by old notes, new gifs should be converted to webp in the future + "image/jpeg", + "image/webp", // TODO: make this the default image format + "image/apng", + "image/bmp", + "image/tiff", + "image/x-icon", + "image/avif", // not as good supported now, but its good to introduce initial support for the future // OggS - 'audio/opus', - 'video/ogg', - 'audio/ogg', - 'application/ogg', + "audio/opus", + "video/ogg", + "audio/ogg", + "application/ogg", // ISO/IEC base media file format - 'video/quicktime', - 'video/mp4', - 'audio/mp4', - 'video/x-m4v', - 'audio/x-m4a', - 'video/3gpp', - 'video/3gpp2', + "video/quicktime", + "video/mp4", // TODO: we need to check for av1 later + "video/vnd.avi", // also av1 + "audio/mp4", + "video/x-m4v", + "audio/x-m4a", + "video/3gpp", + "video/3gpp2", + "video/3gp2", + "audio/3gpp", + "audio/3gpp2", + "audio/3gp2", - 'video/mpeg', - 'audio/mpeg', + "video/mpeg", + "audio/mpeg", - 'video/webm', - 'audio/webm', + "video/webm", + "audio/webm", - 'audio/aac', - 'audio/x-flac', - 'audio/vnd.wave', + "audio/aac", + "audio/x-flac", + "audio/flac", + "audio/vnd.wave", ]; /* https://github.com/sindresorhus/file-type/blob/main/supported.js diff --git a/packages/backend/src/daemons/janitor.ts b/packages/backend/src/daemons/janitor.ts index f2a1bfcc2..2050d54d4 100644 --- a/packages/backend/src/daemons/janitor.ts +++ b/packages/backend/src/daemons/janitor.ts @@ -1,13 +1,13 @@ // TODO: 消したい const interval = 30 * 60 * 1000; -import { AttestationChallenges } from '@/models/index.js'; -import { LessThan } from 'typeorm'; +import { AttestationChallenges } from "@/models/index.js"; +import { LessThan } from "typeorm"; /** * Clean up database occasionally */ -export default function() { +export default function () { async function tick() { await AttestationChallenges.delete({ createdAt: LessThan(new Date(new Date().getTime() - 5 * 60 * 1000)), diff --git a/packages/backend/src/daemons/queue-stats.ts b/packages/backend/src/daemons/queue-stats.ts index 1535abc6a..381b52a91 100644 --- a/packages/backend/src/daemons/queue-stats.ts +++ b/packages/backend/src/daemons/queue-stats.ts @@ -1,5 +1,5 @@ -import Xev from 'xev'; -import { deliverQueue, inboxQueue } from '../queue/queues.js'; +import Xev from "xev"; +import { deliverQueue, inboxQueue } from "../queue/queues.js"; const ev = new Xev(); @@ -8,21 +8,21 @@ const interval = 10000; /** * Report queue stats regularly */ -export default function() { +export default function () { const log = [] as any[]; - ev.on('requestQueueStatsLog', x => { + ev.on("requestQueueStatsLog", (x) => { ev.emit(`queueStatsLog:${x.id}`, log.slice(0, x.length || 50)); }); let activeDeliverJobs = 0; let activeInboxJobs = 0; - deliverQueue.on('global:active', () => { + deliverQueue.on("global:active", () => { activeDeliverJobs++; }); - inboxQueue.on('global:active', () => { + inboxQueue.on("global:active", () => { activeInboxJobs++; }); @@ -45,7 +45,7 @@ export default function() { }, }; - ev.emit('queueStats', stats); + ev.emit("queueStats", stats); log.unshift(stats); if (log.length > 200) log.pop(); diff --git a/packages/backend/src/daemons/server-stats.ts b/packages/backend/src/daemons/server-stats.ts index faf4e6e4a..b0bf1288f 100644 --- a/packages/backend/src/daemons/server-stats.ts +++ b/packages/backend/src/daemons/server-stats.ts @@ -1,6 +1,6 @@ -import si from 'systeminformation'; -import Xev from 'xev'; -import * as osUtils from 'os-utils'; +import si from "systeminformation"; +import Xev from "xev"; +import * as osUtils from "os-utils"; const ev = new Xev(); @@ -12,10 +12,10 @@ const round = (num: number) => Math.round(num * 10) / 10; /** * Report server stats regularly */ -export default function() { +export default function () { const log = [] as any[]; - ev.on('requestServerStatsLog', x => { + ev.on("requestServerStatsLog", (x) => { ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50)); }); @@ -40,7 +40,7 @@ export default function() { w: round(Math.max(0, fsStats.wIO_sec ?? 0)), }, }; - ev.emit('serverStats', stats); + ev.emit("serverStats", stats); log.unshift(stats); if (log.length > 200) log.pop(); } diff --git a/packages/backend/src/db/elasticsearch.ts b/packages/backend/src/db/elasticsearch.ts index d98c5d180..2640e7f91 100644 --- a/packages/backend/src/db/elasticsearch.ts +++ b/packages/backend/src/db/elasticsearch.ts @@ -1,12 +1,12 @@ -import * as elasticsearch from '@elastic/elasticsearch'; -import config from '@/config/index.js'; +import * as elasticsearch from "@elastic/elasticsearch"; +import config from "@/config/index.js"; const index = { settings: { analysis: { analyzer: { ngram: { - tokenizer: 'ngram', + tokenizer: "ngram", }, }, }, @@ -14,16 +14,16 @@ const index = { mappings: { properties: { text: { - type: 'text', + type: "text", index: true, - analyzer: 'ngram', + analyzer: "ngram", }, userId: { - type: 'keyword', + type: "keyword", index: true, }, userHost: { - type: 'keyword', + type: "keyword", index: true, }, }, @@ -31,26 +31,35 @@ const index = { }; // Init ElasticSearch connection -const client = config.elasticsearch ? new elasticsearch.Client({ - node: `${config.elasticsearch.ssl ? 'https://' : 'http://'}${config.elasticsearch.host}:${config.elasticsearch.port}`, - auth: (config.elasticsearch.user && config.elasticsearch.pass) ? { - username: config.elasticsearch.user, - password: config.elasticsearch.pass, - } : undefined, - pingTimeout: 30000, -}) : null; +const client = config.elasticsearch + ? new elasticsearch.Client({ + node: `${config.elasticsearch.ssl ? "https://" : "http://"}${ + config.elasticsearch.host + }:${config.elasticsearch.port}`, + auth: + config.elasticsearch.user && config.elasticsearch.pass + ? { + username: config.elasticsearch.user, + password: config.elasticsearch.pass, + } + : undefined, + pingTimeout: 30000, + }) + : null; if (client) { - client.indices.exists({ - index: config.elasticsearch.index || 'misskey_note', - }).then(exist => { - if (!exist.body) { - client.indices.create({ - index: config.elasticsearch.index || 'misskey_note', - body: index, - }); - } - }); + client.indices + .exists({ + index: config.elasticsearch.index || "misskey_note", + }) + .then((exist) => { + if (!exist.body) { + client.indices.create({ + index: config.elasticsearch.index || "misskey_note", + body: index, + }); + } + }); } export default client; diff --git a/packages/backend/src/db/logger.ts b/packages/backend/src/db/logger.ts index 22f4c6b1b..28ec65dd2 100644 --- a/packages/backend/src/db/logger.ts +++ b/packages/backend/src/db/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger.js'; +import Logger from "@/services/logger.js"; -export const dbLogger = new Logger('db'); +export const dbLogger = new Logger("db"); diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index 94d55e431..f95bd2594 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -1,87 +1,89 @@ // https://github.com/typeorm/typeorm/issues/2400 -import pg from 'pg'; +import pg from "pg"; pg.types.setTypeParser(20, Number); -import { Logger, DataSource } from 'typeorm'; -import * as highlight from 'cli-highlight'; -import config from '@/config/index.js'; +import type { Logger } from "typeorm"; +import { DataSource } from "typeorm"; +import * as highlight from "cli-highlight"; +import config from "@/config/index.js"; -import { User } from '@/models/entities/user.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFolder } from '@/models/entities/drive-folder.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { App } from '@/models/entities/app.js'; -import { PollVote } from '@/models/entities/poll-vote.js'; -import { Note } from '@/models/entities/note.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import { NoteWatching } from '@/models/entities/note-watching.js'; -import { NoteThreadMuting } from '@/models/entities/note-thread-muting.js'; -import { NoteUnread } from '@/models/entities/note-unread.js'; -import { Notification } from '@/models/entities/notification.js'; -import { Meta } from '@/models/entities/meta.js'; -import { Following } from '@/models/entities/following.js'; -import { Instance } from '@/models/entities/instance.js'; -import { Muting } from '@/models/entities/muting.js'; -import { SwSubscription } from '@/models/entities/sw-subscription.js'; -import { Blocking } from '@/models/entities/blocking.js'; -import { UserList } from '@/models/entities/user-list.js'; -import { UserListJoining } from '@/models/entities/user-list-joining.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; -import { Hashtag } from '@/models/entities/hashtag.js'; -import { NoteFavorite } from '@/models/entities/note-favorite.js'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; -import { RegistrationTicket } from '@/models/entities/registration-tickets.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { Signin } from '@/models/entities/signin.js'; -import { AuthSession } from '@/models/entities/auth-session.js'; -import { FollowRequest } from '@/models/entities/follow-request.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { UserNotePining } from '@/models/entities/user-note-pining.js'; -import { Poll } from '@/models/entities/poll.js'; -import { UserKeypair } from '@/models/entities/user-keypair.js'; -import { UserPublickey } from '@/models/entities/user-publickey.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { UserSecurityKey } from '@/models/entities/user-security-key.js'; -import { AttestationChallenge } from '@/models/entities/attestation-challenge.js'; -import { Page } from '@/models/entities/page.js'; -import { PageLike } from '@/models/entities/page-like.js'; -import { GalleryPost } from '@/models/entities/gallery-post.js'; -import { GalleryLike } from '@/models/entities/gallery-like.js'; -import { ModerationLog } from '@/models/entities/moderation-log.js'; -import { UsedUsername } from '@/models/entities/used-username.js'; -import { Announcement } from '@/models/entities/announcement.js'; -import { AnnouncementRead } from '@/models/entities/announcement-read.js'; -import { Clip } from '@/models/entities/clip.js'; -import { ClipNote } from '@/models/entities/clip-note.js'; -import { Antenna } from '@/models/entities/antenna.js'; -import { AntennaNote } from '@/models/entities/antenna-note.js'; -import { PromoNote } from '@/models/entities/promo-note.js'; -import { PromoRead } from '@/models/entities/promo-read.js'; -import { Relay } from '@/models/entities/relay.js'; -import { MutedNote } from '@/models/entities/muted-note.js'; -import { Channel } from '@/models/entities/channel.js'; -import { ChannelFollowing } from '@/models/entities/channel-following.js'; -import { ChannelNotePining } from '@/models/entities/channel-note-pining.js'; -import { RegistryItem } from '@/models/entities/registry-item.js'; -import { Ad } from '@/models/entities/ad.js'; -import { PasswordResetRequest } from '@/models/entities/password-reset-request.js'; -import { UserPending } from '@/models/entities/user-pending.js'; -import { Webhook } from '@/models/entities/webhook.js'; -import { UserIp } from '@/models/entities/user-ip.js'; +import { User } from "@/models/entities/user.js"; +import { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFolder } from "@/models/entities/drive-folder.js"; +import { AccessToken } from "@/models/entities/access-token.js"; +import { App } from "@/models/entities/app.js"; +import { PollVote } from "@/models/entities/poll-vote.js"; +import { Note } from "@/models/entities/note.js"; +import { NoteReaction } from "@/models/entities/note-reaction.js"; +import { NoteWatching } from "@/models/entities/note-watching.js"; +import { NoteThreadMuting } from "@/models/entities/note-thread-muting.js"; +import { NoteUnread } from "@/models/entities/note-unread.js"; +import { Notification } from "@/models/entities/notification.js"; +import { Meta } from "@/models/entities/meta.js"; +import { Following } from "@/models/entities/following.js"; +import { Instance } from "@/models/entities/instance.js"; +import { Muting } from "@/models/entities/muting.js"; +import { SwSubscription } from "@/models/entities/sw-subscription.js"; +import { Blocking } from "@/models/entities/blocking.js"; +import { UserList } from "@/models/entities/user-list.js"; +import { UserListJoining } from "@/models/entities/user-list-joining.js"; +import { UserGroup } from "@/models/entities/user-group.js"; +import { UserGroupJoining } from "@/models/entities/user-group-joining.js"; +import { UserGroupInvitation } from "@/models/entities/user-group-invitation.js"; +import { Hashtag } from "@/models/entities/hashtag.js"; +import { NoteFavorite } from "@/models/entities/note-favorite.js"; +import { AbuseUserReport } from "@/models/entities/abuse-user-report.js"; +import { RegistrationTicket } from "@/models/entities/registration-tickets.js"; +import { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { Signin } from "@/models/entities/signin.js"; +import { AuthSession } from "@/models/entities/auth-session.js"; +import { FollowRequest } from "@/models/entities/follow-request.js"; +import { Emoji } from "@/models/entities/emoji.js"; +import { UserNotePining } from "@/models/entities/user-note-pining.js"; +import { Poll } from "@/models/entities/poll.js"; +import { UserKeypair } from "@/models/entities/user-keypair.js"; +import { UserPublickey } from "@/models/entities/user-publickey.js"; +import { UserProfile } from "@/models/entities/user-profile.js"; +import { UserSecurityKey } from "@/models/entities/user-security-key.js"; +import { AttestationChallenge } from "@/models/entities/attestation-challenge.js"; +import { Page } from "@/models/entities/page.js"; +import { PageLike } from "@/models/entities/page-like.js"; +import { GalleryPost } from "@/models/entities/gallery-post.js"; +import { GalleryLike } from "@/models/entities/gallery-like.js"; +import { ModerationLog } from "@/models/entities/moderation-log.js"; +import { UsedUsername } from "@/models/entities/used-username.js"; +import { Announcement } from "@/models/entities/announcement.js"; +import { AnnouncementRead } from "@/models/entities/announcement-read.js"; +import { Clip } from "@/models/entities/clip.js"; +import { ClipNote } from "@/models/entities/clip-note.js"; +import { Antenna } from "@/models/entities/antenna.js"; +import { AntennaNote } from "@/models/entities/antenna-note.js"; +import { PromoNote } from "@/models/entities/promo-note.js"; +import { PromoRead } from "@/models/entities/promo-read.js"; +import { Relay } from "@/models/entities/relay.js"; +import { MutedNote } from "@/models/entities/muted-note.js"; +import { Channel } from "@/models/entities/channel.js"; +import { ChannelFollowing } from "@/models/entities/channel-following.js"; +import { ChannelNotePining } from "@/models/entities/channel-note-pining.js"; +import { RegistryItem } from "@/models/entities/registry-item.js"; +import { Ad } from "@/models/entities/ad.js"; +import { PasswordResetRequest } from "@/models/entities/password-reset-request.js"; +import { UserPending } from "@/models/entities/user-pending.js"; +import { Webhook } from "@/models/entities/webhook.js"; +import { UserIp } from "@/models/entities/user-ip.js"; -import { entities as charts } from '@/services/chart/entities.js'; -import { envOption } from '../env.js'; -import { dbLogger } from './logger.js'; -import { redisClient } from './redis.js'; +import { entities as charts } from "@/services/chart/entities.js"; +import { envOption } from "../env.js"; +import { dbLogger } from "./logger.js"; +import { redisClient } from "./redis.js"; -const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false); +const sqlLogger = dbLogger.createSubLogger("sql", "gray", false); class MyCustomLogger implements Logger { private highlight(sql: string) { return highlight.highlight(sql, { - language: 'sql', ignoreIllegals: true, + language: "sql", + ignoreIllegals: true, }); } @@ -178,10 +180,10 @@ export const entities = [ ...charts, ]; -const log = process.env.NODE_ENV !== 'production'; +const log = process.env.NODE_ENV !== "production"; export const db = new DataSource({ - type: 'postgres', + type: "postgres", host: config.db.host, port: config.db.port, username: config.db.user, @@ -191,24 +193,26 @@ export const db = new DataSource({ statement_timeout: 1000 * 10, ...config.db.extra, }, - synchronize: process.env.NODE_ENV === 'test', - dropSchema: process.env.NODE_ENV === 'test', - cache: !config.db.disableCache ? { - type: 'ioredis', - options: { - host: config.redis.host, - port: config.redis.port, - family: config.redis.family == null ? 0 : config.redis.family, - password: config.redis.pass, - keyPrefix: `${config.redis.prefix}:query:`, - db: config.redis.db || 0, - }, - } : false, + synchronize: process.env.NODE_ENV === "test", + dropSchema: process.env.NODE_ENV === "test", + cache: !config.db.disableCache + ? { + type: "ioredis", + options: { + host: config.redis.host, + port: config.redis.port, + family: config.redis.family == null ? 0 : config.redis.family, + password: config.redis.pass, + keyPrefix: `${config.redis.prefix}:query:`, + db: config.redis.db || 0, + }, + } + : false, logging: log, logger: log ? new MyCustomLogger() : undefined, maxQueryExecutionTime: 300, entities: entities, - migrations: ['../../migration/*.js'], + migrations: ["../../migration/*.js"], }); export async function initDb(force = false) { @@ -247,7 +251,7 @@ export async function resetDb() { if (i === 3) { throw e; } else { - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 1000)); continue; } } diff --git a/packages/backend/src/db/redis.ts b/packages/backend/src/db/redis.ts index 7d0843a59..6ad3de386 100644 --- a/packages/backend/src/db/redis.ts +++ b/packages/backend/src/db/redis.ts @@ -1,5 +1,5 @@ -import Redis from 'ioredis'; -import config from '@/config/index.js'; +import Redis from "ioredis"; +import config from "@/config/index.js"; export function createConnection() { return new Redis({ diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts index 1b678edc4..a788a0fba 100644 --- a/packages/backend/src/env.ts +++ b/packages/backend/src/env.ts @@ -10,11 +10,16 @@ const envOption = { }; for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { - if (process.env['MK_' + key.replace(/[A-Z]/g, letter => `_${letter}`).toUpperCase()]) envOption[key] = true; + if ( + process.env[ + `MK_${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}` + ] + ) + envOption[key] = true; } -if (process.env.NODE_ENV === 'test') envOption.disableClustering = true; -if (process.env.NODE_ENV === 'test') envOption.quiet = true; -if (process.env.NODE_ENV === 'test') envOption.noDaemons = true; +if (process.env.NODE_ENV === "test") envOption.disableClustering = true; +if (process.env.NODE_ENV === "test") envOption.quiet = true; +if (process.env.NODE_ENV === "test") envOption.noDaemons = true; export { envOption }; diff --git a/packages/backend/src/global.d.ts b/packages/backend/src/global.d.ts index 7343aa199..503e26eb6 100644 --- a/packages/backend/src/global.d.ts +++ b/packages/backend/src/global.d.ts @@ -1 +1,2 @@ +// rome-ignore lint/suspicious/noExplicitAny: i have no idea type FIXME = any; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index bd9c0098b..278f630f7 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -2,12 +2,12 @@ * Misskey Entry Point! */ -import { EventEmitter } from 'node:events'; -import boot from './boot/index.js'; +import { EventEmitter } from "node:events"; +import boot from "./boot/index.js"; Error.stackTraceLimit = Infinity; EventEmitter.defaultMaxListeners = 128; -boot().catch(err => { +boot().catch((err) => { console.error(err); }); diff --git a/packages/backend/src/mfm/from-html.ts b/packages/backend/src/mfm/from-html.ts index 7751bac56..7c956e905 100644 --- a/packages/backend/src/mfm/from-html.ts +++ b/packages/backend/src/mfm/from-html.ts @@ -1,6 +1,6 @@ -import { URL } from 'node:url'; -import * as parse5 from 'parse5'; -import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js'; +import { URL } from "node:url"; +import * as parse5 from "parse5"; +import * as TreeAdapter from "../../node_modules/parse5/dist/tree-adapters/default.js"; const treeAdapter = TreeAdapter.defaultTreeAdapter; @@ -9,11 +9,11 @@ const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; export function fromHtml(html: string, hashtagNames?: string[]): string { // some AP servers like Pixelfed use br tags as well as newlines - html = html.replace(/\r?\n/gi, '\n'); + html = html.replace(/\r?\n/gi, "\n"); const dom = parse5.parseFragment(html); - let text = ''; + let text = ""; for (const n of dom.childNodes) { analyze(n); @@ -23,14 +23,14 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { function getText(node: TreeAdapter.Node): string { if (treeAdapter.isTextNode(node)) return node.value; - if (!treeAdapter.isElementNode(node)) return ''; - if (node.nodeName === 'br') return '\n'; + if (!treeAdapter.isElementNode(node)) return ""; + if (node.nodeName === "br") return "\n"; if (node.childNodes) { - return node.childNodes.map(n => getText(n)).join(''); + return node.childNodes.map((n) => getText(n)).join(""); } - return ''; + return ""; } function appendChildren(childNodes: TreeAdapter.ChildNode[]): void { @@ -51,42 +51,46 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { if (!treeAdapter.isElementNode(node)) return; switch (node.nodeName) { - case 'br': { - text += '\n'; + case "br": { + text += "\n"; break; } - case 'a': - { + case "a": { const txt = getText(node); - const rel = node.attrs.find(x => x.name === 'rel'); - const href = node.attrs.find(x => x.name === 'href'); + const rel = node.attrs.find((x) => x.name === "rel"); + const href = node.attrs.find((x) => x.name === "href"); // ハッシュタグ - if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) { + if ( + hashtagNames && + href && + hashtagNames.map((x) => x.toLowerCase()).includes(txt.toLowerCase()) + ) { text += txt; - // メンション - } else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) { - const part = txt.split('@'); + // メンション + } else if (txt.startsWith("@") && !rel?.value.match(/^me /)) { + const part = txt.split("@"); if (part.length === 2 && href) { //#region ホスト名部分が省略されているので復元する - const acct = `${txt}@${(new URL(href.value)).hostname}`; + const acct = `${txt}@${new URL(href.value).hostname}`; text += acct; //#endregion } else if (part.length === 3) { text += txt; } - // その他 + // その他 } else { const generateLink = () => { - if (!href && !txt) { - return ''; + if (!(href || txt)) { + return ""; } if (!href) { return txt; } - if (!txt || txt === href.value) { // #6383: Missing text node + if (!txt || txt === href.value) { + // #6383: Missing text node if (href.value.match(urlRegexFull)) { return href.value; } else { @@ -94,7 +98,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { } } if (href.value.match(urlRegex) && !href.value.match(urlRegexFull)) { - return `[${txt}](<${href.value}>)`; // #6846 + return `[${txt}](<${href.value}>)`; // #6846 } else { return `[${txt}](${href.value})`; } @@ -105,55 +109,53 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { break; } - case 'h1': - { - text += '【'; + case "h1": { + text += "【"; appendChildren(node.childNodes); - text += '】\n'; + text += "】\n"; break; } - case 'b': - case 'strong': - { - text += '**'; + case "b": + case "strong": { + text += "**"; appendChildren(node.childNodes); - text += '**'; + text += "**"; break; } - case 'small': - { - text += ''; + case "small": { + text += ""; appendChildren(node.childNodes); - text += ''; + text += ""; break; } - case 's': - case 'del': - { - text += '~~'; + case "s": + case "del": { + text += "~~"; appendChildren(node.childNodes); - text += '~~'; + text += "~~"; break; } - case 'i': - case 'em': - { - text += ''; + case "i": + case "em": { + text += ""; appendChildren(node.childNodes); - text += ''; + text += ""; break; } // block code (
)
-			case 'pre': {
-				if (node.childNodes.length === 1 && node.childNodes[0].nodeName === 'code') {
-					text += '\n```\n';
+			case "pre": {
+				if (
+					node.childNodes.length === 1 &&
+					node.childNodes[0].nodeName === "code"
+				) {
+					text += "\n```\n";
 					text += getText(node.childNodes[0]);
-					text += '\n```\n';
+					text += "\n```\n";
 				} else {
 					appendChildren(node.childNodes);
 				}
@@ -161,50 +163,48 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
 			}
 
 			// inline code ()
-			case 'code': {
-				text += '`';
+			case "code": {
+				text += "`";
 				appendChildren(node.childNodes);
-				text += '`';
+				text += "`";
 				break;
 			}
 
-			case 'blockquote': {
+			case "blockquote": {
 				const t = getText(node);
 				if (t) {
-					text += '\n> ';
-					text += t.split('\n').join('\n> ');
+					text += "\n> ";
+					text += t.split("\n").join("\n> ");
 				}
 				break;
 			}
 
-			case 'p':
-			case 'h2':
-			case 'h3':
-			case 'h4':
-			case 'h5':
-			case 'h6':
-			{
-				text += '\n\n';
+			case "p":
+			case "h2":
+			case "h3":
+			case "h4":
+			case "h5":
+			case "h6": {
+				text += "\n\n";
 				appendChildren(node.childNodes);
 				break;
 			}
 
 			// other block elements
-			case 'div':
-			case 'header':
-			case 'footer':
-			case 'article':
-			case 'li':
-			case 'dt':
-			case 'dd':
-			{
-				text += '\n';
+			case "div":
+			case "header":
+			case "footer":
+			case "article":
+			case "li":
+			case "dt":
+			case "dd": {
+				text += "\n";
 				appendChildren(node.childNodes);
 				break;
 			}
 
-			default:	// includes inline elements
-			{
+			default: {
+				// includes inline elements
 				appendChildren(node.childNodes);
 				break;
 			}
diff --git a/packages/backend/src/mfm/to-html.ts b/packages/backend/src/mfm/to-html.ts
index 42747142b..8d8a4a888 100644
--- a/packages/backend/src/mfm/to-html.ts
+++ b/packages/backend/src/mfm/to-html.ts
@@ -1,65 +1,71 @@
-import { JSDOM } from 'jsdom';
-import * as mfm from 'mfm-js';
-import config from '@/config/index.js';
-import { intersperse } from '@/prelude/array.js';
-import { IMentionedRemoteUsers } from '@/models/entities/note.js';
+import { JSDOM } from "jsdom";
+import type * as mfm from "mfm-js";
+import config from "@/config/index.js";
+import { intersperse } from "@/prelude/array.js";
+import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
 
-export function toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
+export function toHtml(
+	nodes: mfm.MfmNode[] | null,
+	mentionedRemoteUsers: IMentionedRemoteUsers = [],
+) {
 	if (nodes == null) {
 		return null;
 	}
 
-	const { window } = new JSDOM('');
+	const { window } = new JSDOM("");
 
 	const doc = window.document;
 
 	function appendChildren(children: mfm.MfmNode[], targetElement: any): void {
 		if (children) {
-			for (const child of children.map(x => (handlers as any)[x.type](x))) targetElement.appendChild(child);
+			for (const child of children.map((x) => (handlers as any)[x.type](x)))
+				targetElement.appendChild(child);
 		}
 	}
 
-	const handlers: { [K in mfm.MfmNode['type']]: (node: mfm.NodeType) => any } = {
+	const handlers: {
+		[K in mfm.MfmNode["type"]]: (node: mfm.NodeType) => any;
+	} = {
 		bold(node) {
-			const el = doc.createElement('b');
+			const el = doc.createElement("b");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		small(node) {
-			const el = doc.createElement('small');
+			const el = doc.createElement("small");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		strike(node) {
-			const el = doc.createElement('del');
+			const el = doc.createElement("del");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		italic(node) {
-			const el = doc.createElement('i');
+			const el = doc.createElement("i");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		fn(node) {
-			const el = doc.createElement('i');
+			const el = doc.createElement("i");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		blockCode(node) {
-			const pre = doc.createElement('pre');
-			const inner = doc.createElement('code');
+			const pre = doc.createElement("pre");
+			const inner = doc.createElement("code");
 			inner.textContent = node.props.code;
 			pre.appendChild(inner);
 			return pre;
 		},
 
 		center(node) {
-			const el = doc.createElement('div');
+			const el = doc.createElement("div");
 			appendChildren(node.children, el);
 			return el;
 		},
@@ -73,81 +79,90 @@ export function toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMenti
 		},
 
 		hashtag(node) {
-			const a = doc.createElement('a');
+			const a = doc.createElement("a");
 			a.href = `${config.url}/tags/${node.props.hashtag}`;
 			a.textContent = `#${node.props.hashtag}`;
-			a.setAttribute('rel', 'tag');
+			a.setAttribute("rel", "tag");
 			return a;
 		},
 
 		inlineCode(node) {
-			const el = doc.createElement('code');
+			const el = doc.createElement("code");
 			el.textContent = node.props.code;
 			return el;
 		},
 
 		mathInline(node) {
-			const el = doc.createElement('code');
+			const el = doc.createElement("code");
 			el.textContent = node.props.formula;
 			return el;
 		},
 
 		mathBlock(node) {
-			const el = doc.createElement('code');
+			const el = doc.createElement("code");
 			el.textContent = node.props.formula;
 			return el;
 		},
 
 		link(node) {
-			const a = doc.createElement('a');
+			const a = doc.createElement("a");
 			a.href = node.props.url;
 			appendChildren(node.children, a);
 			return a;
 		},
 
 		mention(node) {
-			const a = doc.createElement('a');
+			const a = doc.createElement("a");
 			const { username, host, acct } = node.props;
-			const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
-			a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`;
-			a.className = 'u-url mention';
+			const remoteUserInfo = mentionedRemoteUsers.find(
+				(remoteUser) =>
+					remoteUser.username === username && remoteUser.host === host,
+			);
+			a.href = remoteUserInfo
+				? remoteUserInfo.url
+					? remoteUserInfo.url
+					: remoteUserInfo.uri
+				: `${config.url}/${acct}`;
+			a.className = "u-url mention";
 			a.textContent = acct;
 			return a;
 		},
 
 		quote(node) {
-			const el = doc.createElement('blockquote');
+			const el = doc.createElement("blockquote");
 			appendChildren(node.children, el);
 			return el;
 		},
 
 		text(node) {
-			const el = doc.createElement('span');
-			const nodes = node.props.text.split(/\r\n|\r|\n/).map(x => doc.createTextNode(x));
+			const el = doc.createElement("span");
+			const nodes = node.props.text
+				.split(/\r\n|\r|\n/)
+				.map((x) => doc.createTextNode(x));
 
-			for (const x of intersperse('br', nodes)) {
-				el.appendChild(x === 'br' ? doc.createElement('br') : x);
+			for (const x of intersperse("br", nodes)) {
+				el.appendChild(x === "br" ? doc.createElement("br") : x);
 			}
 
 			return el;
 		},
 
 		url(node) {
-			const a = doc.createElement('a');
+			const a = doc.createElement("a");
 			a.href = node.props.url;
 			a.textContent = node.props.url;
 			return a;
 		},
 
 		search(node) {
-			const a = doc.createElement('a');
+			const a = doc.createElement("a");
 			a.href = `https://search.annoyingorange.xyz/search?q=${node.props.query}`;
 			a.textContent = node.props.content;
 			return a;
 		},
 
 		plain(node) {
-			const el = doc.createElement('span');
+			const el = doc.createElement("span");
 			appendChildren(node.children, el);
 			return el;
 		},
diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts
index c32cee86c..5b7767a10 100644
--- a/packages/backend/src/misc/acct.ts
+++ b/packages/backend/src/misc/acct.ts
@@ -4,8 +4,8 @@ export type Acct = {
 };
 
 export function parse(acct: string): Acct {
-	if (acct.startsWith('@')) acct = acct.substr(1);
-	const split = acct.split('@', 2);
+	if (acct.startsWith("@")) acct = acct.substr(1);
+	const split = acct.split("@", 2);
 	return { username: split[0], host: split[1] || null };
 }
 
diff --git a/packages/backend/src/misc/antenna-cache.ts b/packages/backend/src/misc/antenna-cache.ts
index 97249c146..7f199c396 100644
--- a/packages/backend/src/misc/antenna-cache.ts
+++ b/packages/backend/src/misc/antenna-cache.ts
@@ -1,6 +1,6 @@
-import { Antennas } from '@/models/index.js';
-import { Antenna } from '@/models/entities/antenna.js';
-import { subscriber } from '@/db/redis.js';
+import { Antennas } from "@/models/index.js";
+import type { Antenna } from "@/models/entities/antenna.js";
+import { subscriber } from "@/db/redis.js";
 
 let antennasFetched = false;
 let antennas: Antenna[] = [];
@@ -14,20 +14,20 @@ export async function getAntennas() {
 	return antennas;
 }
 
-subscriber.on('message', async (_, data) => {
+subscriber.on("message", async (_, data) => {
 	const obj = JSON.parse(data);
 
-	if (obj.channel === 'internal') {
+	if (obj.channel === "internal") {
 		const { type, body } = obj.message;
 		switch (type) {
-			case 'antennaCreated':
+			case "antennaCreated":
 				antennas.push(body);
 				break;
-			case 'antennaUpdated':
-				antennas[antennas.findIndex(a => a.id === body.id)] = body;
+			case "antennaUpdated":
+				antennas[antennas.findIndex((a) => a.id === body.id)] = body;
 				break;
-			case 'antennaDeleted':
-				antennas = antennas.filter(a => a.id !== body.id);
+			case "antennaDeleted":
+				antennas = antennas.filter((a) => a.id !== body.id);
 				break;
 			default:
 				break;
diff --git a/packages/backend/src/misc/api-permissions.ts b/packages/backend/src/misc/api-permissions.ts
index 160cdf9fd..9e040262f 100644
--- a/packages/backend/src/misc/api-permissions.ts
+++ b/packages/backend/src/misc/api-permissions.ts
@@ -1,35 +1,35 @@
 export const kinds = [
-	'read:account',
-	'write:account',
-	'read:blocks',
-	'write:blocks',
-	'read:drive',
-	'write:drive',
-	'read:favorites',
-	'write:favorites',
-	'read:following',
-	'write:following',
-	'read:messaging',
-	'write:messaging',
-	'read:mutes',
-	'write:mutes',
-	'write:notes',
-	'read:notifications',
-	'write:notifications',
-	'read:reactions',
-	'write:reactions',
-	'write:votes',
-	'read:pages',
-	'write:pages',
-	'write:page-likes',
-	'read:page-likes',
-	'read:user-groups',
-	'write:user-groups',
-	'read:channels',
-	'write:channels',
-	'read:gallery',
-	'write:gallery',
-	'read:gallery-likes',
-	'write:gallery-likes',
+	"read:account",
+	"write:account",
+	"read:blocks",
+	"write:blocks",
+	"read:drive",
+	"write:drive",
+	"read:favorites",
+	"write:favorites",
+	"read:following",
+	"write:following",
+	"read:messaging",
+	"write:messaging",
+	"read:mutes",
+	"write:mutes",
+	"write:notes",
+	"read:notifications",
+	"write:notifications",
+	"read:reactions",
+	"write:reactions",
+	"write:votes",
+	"read:pages",
+	"write:pages",
+	"write:page-likes",
+	"read:page-likes",
+	"read:user-groups",
+	"write:user-groups",
+	"read:channels",
+	"write:channels",
+	"read:gallery",
+	"write:gallery",
+	"read:gallery-likes",
+	"write:gallery-likes",
 ];
 // IF YOU ADD KINDS(PERMISSIONS), YOU MUST ADD TRANSLATIONS (under _permissions).
diff --git a/packages/backend/src/misc/app-lock.ts b/packages/backend/src/misc/app-lock.ts
index b5089cc6a..05bcf5424 100644
--- a/packages/backend/src/misc/app-lock.ts
+++ b/packages/backend/src/misc/app-lock.ts
@@ -1,16 +1,15 @@
-import { redisClient } from '../db/redis.js';
-import { promisify } from 'node:util';
-import redisLock from 'redis-lock';
+import { redisClient } from "../db/redis.js";
+import { promisify } from "node:util";
+import redisLock from "redis-lock";
 
 /**
  * Retry delay (ms) for lock acquisition
  */
 const retryDelay = 100;
 
-const lock: (key: string, timeout?: number) => Promise<() => void>
-	= redisClient
+const lock: (key: string, timeout?: number) => Promise<() => void> = redisClient
 	? promisify(redisLock(redisClient, retryDelay))
-	: async () => () => { };
+	: async () => () => {};
 
 /**
  * Get AP Object lock
@@ -22,7 +21,10 @@ export function getApLock(uri: string, timeout = 30 * 1000) {
 	return lock(`ap-object:${uri}`, timeout);
 }
 
-export function getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000) {
+export function getFetchInstanceMetadataLock(
+	host: string,
+	timeout = 30 * 1000,
+) {
 	return lock(`instance:${host}`, timeout);
 }
 
diff --git a/packages/backend/src/misc/before-shutdown.ts b/packages/backend/src/misc/before-shutdown.ts
index 93ac7a1f3..082041835 100644
--- a/packages/backend/src/misc/before-shutdown.ts
+++ b/packages/backend/src/misc/before-shutdown.ts
@@ -1,6 +1,6 @@
 // https://gist.github.com/nfantone/1eaa803772025df69d07f4dbf5df7e58
 
-'use strict';
+"use strict";
 
 /**
  * @callback BeforeShutdownListener
@@ -11,7 +11,7 @@
  * System signals the app will listen to initiate shutdown.
  * @const {string[]}
  */
-const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
+const SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
 
 /**
  * Time in milliseconds to wait before forcing shutdown.
@@ -31,7 +31,10 @@ const shutdownListeners: ((signalOrEvent: string) => void)[] = [];
  * @param  {string[]} signals System signals to listen to.
  * @param  {function(string)} fn Function to execute on shutdown.
  */
-const processOnce = (signals: string[], fn: (signalOrEvent: string) => void) => {
+const processOnce = (
+	signals: string[],
+	fn: (signalOrEvent: string) => void,
+) => {
 	for (const sig of signals) {
 		process.once(sig, fn);
 	}
@@ -44,7 +47,9 @@ const processOnce = (signals: string[], fn: (signalOrEvent: string) => void) =>
 const forceExitAfter = (timeout: number) => () => {
 	setTimeout(() => {
 		// Force shutdown after timeout
-		console.warn(`Could not close resources gracefully after ${timeout}ms: forcing shutdown`);
+		console.warn(
+			`Could not close resources gracefully after ${timeout}ms: forcing shutdown`,
+		);
 		return process.exit(1);
 	}, timeout).unref();
 };
@@ -56,7 +61,7 @@ const forceExitAfter = (timeout: number) => () => {
  * @param {string} signalOrEvent The exit signal or event name received on the process.
  */
 async function shutdownHandler(signalOrEvent: string) {
-	if (process.env.NODE_ENV === 'test') return process.exit(0);
+	if (process.env.NODE_ENV === "test") return process.exit(0);
 
 	console.warn(`Shutting down: received [${signalOrEvent}] signal`);
 
@@ -65,7 +70,11 @@ async function shutdownHandler(signalOrEvent: string) {
 			await listener(signalOrEvent);
 		} catch (err) {
 			if (err instanceof Error) {
-				console.warn(`A shutdown handler failed before completing with: ${err.message || err}`);
+				console.warn(
+					`A shutdown handler failed before completing with: ${
+						err.message || err
+					}`,
+				);
 			}
 		}
 	}
diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts
index e5b911ed3..9abebc91c 100644
--- a/packages/backend/src/misc/cache.ts
+++ b/packages/backend/src/misc/cache.ts
@@ -1,8 +1,8 @@
 export class Cache {
-	public cache: Map;
+	public cache: Map;
 	private lifetime: number;
 
-	constructor(lifetime: Cache['lifetime']) {
+	constructor(lifetime: Cache["lifetime"]) {
 		this.cache = new Map();
 		this.lifetime = lifetime;
 	}
@@ -17,7 +17,7 @@ export class Cache {
 	public get(key: string | null): T | undefined {
 		const cached = this.cache.get(key);
 		if (cached == null) return undefined;
-		if ((Date.now() - cached.date) > this.lifetime) {
+		if (Date.now() - cached.date > this.lifetime) {
 			this.cache.delete(key);
 			return undefined;
 		}
@@ -32,7 +32,11 @@ export class Cache {
 	 * キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します
 	 * optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします
 	 */
-	public async fetch(key: string | null, fetcher: () => Promise, validator?: (cachedValue: T) => boolean): Promise {
+	public async fetch(
+		key: string | null,
+		fetcher: () => Promise,
+		validator?: (cachedValue: T) => boolean,
+	): Promise {
 		const cachedValue = this.get(key);
 		if (cachedValue !== undefined) {
 			if (validator) {
@@ -56,7 +60,11 @@ export class Cache {
 	 * キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します
 	 * optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします
 	 */
-	public async fetchMaybe(key: string | null, fetcher: () => Promise, validator?: (cachedValue: T) => boolean): Promise {
+	public async fetchMaybe(
+		key: string | null,
+		fetcher: () => Promise,
+		validator?: (cachedValue: T) => boolean,
+	): Promise {
 		const cachedValue = this.get(key);
 		if (cachedValue !== undefined) {
 			if (validator) {
diff --git a/packages/backend/src/misc/captcha.ts b/packages/backend/src/misc/captcha.ts
index 947ab27e2..8ea4abedb 100644
--- a/packages/backend/src/misc/captcha.ts
+++ b/packages/backend/src/misc/captcha.ts
@@ -1,51 +1,67 @@
-import fetch from 'node-fetch';
-import { URLSearchParams } from 'node:url';
-import { getAgentByUrl } from './fetch.js';
-import config from '@/config/index.js';
+import fetch from "node-fetch";
+import { URLSearchParams } from "node:url";
+import { getAgentByUrl } from "./fetch.js";
+import config from "@/config/index.js";
 
 export async function verifyRecaptcha(secret: string, response: string) {
-	const result = await getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(e => {
+	const result = await getCaptchaResponse(
+		"https://www.recaptcha.net/recaptcha/api/siteverify",
+		secret,
+		response,
+	).catch((e) => {
 		throw new Error(`recaptcha-request-failed: ${e.message}`);
 	});
 
 	if (result.success !== true) {
-		const errorCodes = result['error-codes'] ? result['error-codes']?.join(', ') : '';
+		const errorCodes = result["error-codes"]
+			? result["error-codes"]?.join(", ")
+			: "";
 		throw new Error(`recaptcha-failed: ${errorCodes}`);
 	}
 }
 
 export async function verifyHcaptcha(secret: string, response: string) {
-	const result = await getCaptchaResponse('https://hcaptcha.com/siteverify', secret, response).catch(e => {
+	const result = await getCaptchaResponse(
+		"https://hcaptcha.com/siteverify",
+		secret,
+		response,
+	).catch((e) => {
 		throw new Error(`hcaptcha-request-failed: ${e.message}`);
 	});
 
 	if (result.success !== true) {
-		const errorCodes = result['error-codes'] ? result['error-codes']?.join(', ') : '';
+		const errorCodes = result["error-codes"]
+			? result["error-codes"]?.join(", ")
+			: "";
 		throw new Error(`hcaptcha-failed: ${errorCodes}`);
 	}
 }
 
 type CaptchaResponse = {
 	success: boolean;
-	'error-codes'?: string[];
+	"error-codes"?: string[];
 };
 
-async function getCaptchaResponse(url: string, secret: string, response: string): Promise {
+async function getCaptchaResponse(
+	url: string,
+	secret: string,
+	response: string,
+): Promise {
 	const params = new URLSearchParams({
 		secret,
 		response,
 	});
 
 	const res = await fetch(url, {
-		method: 'POST',
+		method: "POST",
 		body: params,
 		headers: {
-			'User-Agent': config.userAgent,
+			"User-Agent": config.userAgent,
 		},
 		// TODO
 		//timeout: 10 * 1000,
 		agent: getAgentByUrl,
-	}).catch(e => {
+	}).catch((e) => {
 		throw new Error(`${e.message || e}`);
 	});
 
@@ -53,5 +69,5 @@ async function getCaptchaResponse(url: string, secret: string, response: string)
 		throw new Error(`${res.status}`);
 	}
 
-	return await res.json() as CaptchaResponse;
+	return (await res.json()) as CaptchaResponse;
 }
diff --git a/packages/backend/src/misc/check-hit-antenna.ts b/packages/backend/src/misc/check-hit-antenna.ts
index d9cedee7d..aa38d9e27 100644
--- a/packages/backend/src/misc/check-hit-antenna.ts
+++ b/packages/backend/src/misc/check-hit-antenna.ts
@@ -1,90 +1,121 @@
-import { Antenna } from '@/models/entities/antenna.js';
-import { Note } from '@/models/entities/note.js';
-import { User } from '@/models/entities/user.js';
-import { UserListJoinings, UserGroupJoinings, Blockings } from '@/models/index.js';
-import { getFullApAccount } from './convert-host.js';
-import * as Acct from '@/misc/acct.js';
-import { Packed } from './schema.js';
-import { Cache } from './cache.js';
+import type { Antenna } from "@/models/entities/antenna.js";
+import type { Note } from "@/models/entities/note.js";
+import type { User } from "@/models/entities/user.js";
+import {
+	UserListJoinings,
+	UserGroupJoinings,
+	Blockings,
+} from "@/models/index.js";
+import { getFullApAccount } from "./convert-host.js";
+import * as Acct from "@/misc/acct.js";
+import type { Packed } from "./schema.js";
+import { Cache } from "./cache.js";
 
-const blockingCache = new Cache(1000 * 60 * 5);
+const blockingCache = new Cache(1000 * 60 * 5);
 
 // NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
 
 /**
  * noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
  */
-export async function checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { id: User['id']; username: string; host: string | null; }, noteUserFollowers?: User['id'][], antennaUserFollowing?: User['id'][]): Promise {
-	if (note.visibility === 'specified') return false;
+export async function checkHitAntenna(
+	antenna: Antenna,
+	note: Note | Packed<"Note">,
+	noteUser: { id: User["id"]; username: string; host: string | null },
+	noteUserFollowers?: User["id"][],
+	antennaUserFollowing?: User["id"][],
+): Promise {
+	if (note.visibility === "specified") return false;
 
 	// アンテナ作成者がノート作成者にブロックされていたらスキップ
-	const blockings = await blockingCache.fetch(noteUser.id, () => Blockings.findBy({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId)));
-	if (blockings.some(blocking => blocking === antenna.userId)) return false;
+	const blockings = await blockingCache.fetch(noteUser.id, () =>
+		Blockings.findBy({ blockerId: noteUser.id }).then((res) =>
+			res.map((x) => x.blockeeId),
+		),
+	);
+	if (blockings.some((blocking) => blocking === antenna.userId)) return false;
 
-	if (note.visibility === 'followers') {
-		if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId)) return false;
-		if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) return false;
+	if (note.visibility === "followers") {
+		if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
+			return false;
+		if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
+			return false;
 	}
 
 	if (!antenna.withReplies && note.replyId != null) return false;
 
-	if (antenna.src === 'home') {
-		if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId)) return false;
-		if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) return false;
-	} else if (antenna.src === 'list') {
-		const listUsers = (await UserListJoinings.findBy({
-			userListId: antenna.userListId!,
-		})).map(x => x.userId);
+	if (antenna.src === "home") {
+		if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
+			return false;
+		if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
+			return false;
+	} else if (antenna.src === "list") {
+		const listUsers = (
+			await UserListJoinings.findBy({
+				userListId: antenna.userListId!,
+			})
+		).map((x) => x.userId);
 
 		if (!listUsers.includes(note.userId)) return false;
-	} else if (antenna.src === 'group') {
-		const joining = await UserGroupJoinings.findOneByOrFail({ id: antenna.userGroupJoiningId! });
+	} else if (antenna.src === "group") {
+		const joining = await UserGroupJoinings.findOneByOrFail({
+			id: antenna.userGroupJoiningId!,
+		});
 
-		const groupUsers = (await UserGroupJoinings.findBy({
-			userGroupId: joining.userGroupId,
-		})).map(x => x.userId);
+		const groupUsers = (
+			await UserGroupJoinings.findBy({
+				userGroupId: joining.userGroupId,
+			})
+		).map((x) => x.userId);
 
 		if (!groupUsers.includes(note.userId)) return false;
-	} else if (antenna.src === 'users') {
-		const accts = antenna.users.map(x => {
+	} else if (antenna.src === "users") {
+		const accts = antenna.users.map((x) => {
 			const { username, host } = Acct.parse(x);
 			return getFullApAccount(username, host).toLowerCase();
 		});
-		if (!accts.includes(getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
+		if (
+			!accts.includes(
+				getFullApAccount(noteUser.username, noteUser.host).toLowerCase(),
+			)
+		)
+			return false;
 	}
 
 	const keywords = antenna.keywords
 		// Clean up
-		.map(xs => xs.filter(x => x !== ''))
-		.filter(xs => xs.length > 0);
+		.map((xs) => xs.filter((x) => x !== ""))
+		.filter((xs) => xs.length > 0);
 
 	if (keywords.length > 0) {
 		if (note.text == null) return false;
 
-		const matched = keywords.some(and =>
-			and.every(keyword =>
+		const matched = keywords.some((and) =>
+			and.every((keyword) =>
 				antenna.caseSensitive
 					? note.text!.includes(keyword)
-					: note.text!.toLowerCase().includes(keyword.toLowerCase())
-			));
+					: note.text!.toLowerCase().includes(keyword.toLowerCase()),
+			),
+		);
 
 		if (!matched) return false;
 	}
 
 	const excludeKeywords = antenna.excludeKeywords
 		// Clean up
-		.map(xs => xs.filter(x => x !== ''))
-		.filter(xs => xs.length > 0);
+		.map((xs) => xs.filter((x) => x !== ""))
+		.filter((xs) => xs.length > 0);
 
 	if (excludeKeywords.length > 0) {
 		if (note.text == null) return false;
 
-		const matched = excludeKeywords.some(and =>
-			and.every(keyword =>
+		const matched = excludeKeywords.some((and) =>
+			and.every((keyword) =>
 				antenna.caseSensitive
 					? note.text!.includes(keyword)
-					: note.text!.toLowerCase().includes(keyword.toLowerCase())
-			));
+					: note.text!.toLowerCase().includes(keyword.toLowerCase()),
+			),
+		);
 
 		if (matched) return false;
 	}
diff --git a/packages/backend/src/misc/check-word-mute.ts b/packages/backend/src/misc/check-word-mute.ts
index d7662820a..ffdf3caf8 100644
--- a/packages/backend/src/misc/check-word-mute.ts
+++ b/packages/backend/src/misc/check-word-mute.ts
@@ -1,28 +1,32 @@
-import RE2 from 're2';
-import { Note } from '@/models/entities/note.js';
-import { User } from '@/models/entities/user.js';
+import RE2 from "re2";
+import type { Note } from "@/models/entities/note.js";
+import type { User } from "@/models/entities/user.js";
 
 type NoteLike = {
-	userId: Note['userId'];
-	text: Note['text'];
+	userId: Note["userId"];
+	text: Note["text"];
 };
 
 type UserLike = {
-	id: User['id'];
+	id: User["id"];
 };
 
-export async function checkWordMute(note: NoteLike, me: UserLike | null | undefined, mutedWords: Array): Promise {
+export async function checkWordMute(
+	note: NoteLike,
+	me: UserLike | null | undefined,
+	mutedWords: Array,
+): Promise {
 	// 自分自身
-	if (me && (note.userId === me.id)) return false;
+	if (me && note.userId === me.id) return false;
 
 	if (mutedWords.length > 0) {
-		const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
+		const text = ((note.cw ?? "") + "\n" + (note.text ?? "")).trim();
 
-		if (text === '') return false;
+		if (text === "") return false;
 
-		const matched = mutedWords.some(filter => {
+		const matched = mutedWords.some((filter) => {
 			if (Array.isArray(filter)) {
-				return filter.every(keyword => text.includes(keyword));
+				return filter.every((keyword) => text.includes(keyword));
 			} else {
 				// represents RegExp
 				const regexp = filter.match(/^\/(.+)\/(.*)$/);
diff --git a/packages/backend/src/misc/clone.ts b/packages/backend/src/misc/clone.ts
index 16fad2412..4322e2e28 100644
--- a/packages/backend/src/misc/clone.ts
+++ b/packages/backend/src/misc/clone.ts
@@ -1,10 +1,16 @@
 // structredCloneが遅いため
 // SEE: http://var.blog.jp/archives/86038606.html
 
-type Cloneable = string | number | boolean | null | { [key: string]: Cloneable } | Cloneable[];
+type Cloneable =
+	| string
+	| number
+	| boolean
+	| null
+	| { [key: string]: Cloneable }
+	| Cloneable[];
 
 export function deepClone(x: T): T {
-	if (typeof x === 'object') {
+	if (typeof x === "object") {
 		if (x === null) return x;
 		if (Array.isArray(x)) return x.map(deepClone) as T;
 		const obj = {} as Record;
diff --git a/packages/backend/src/misc/content-disposition.ts b/packages/backend/src/misc/content-disposition.ts
index b2aec471d..25d6f5817 100644
--- a/packages/backend/src/misc/content-disposition.ts
+++ b/packages/backend/src/misc/content-disposition.ts
@@ -1,6 +1,9 @@
-import cd from 'content-disposition';
+import cd from "content-disposition";
 
-export function contentDisposition(type: 'inline' | 'attachment', filename: string): string {
-	const fallback = filename.replace(/[^\w.-]/g, '_');
+export function contentDisposition(
+	type: "inline" | "attachment",
+	filename: string,
+): string {
+	const fallback = filename.replace(/[^\w.-]/g, "_");
 	return cd(filename, { type, fallback });
 }
diff --git a/packages/backend/src/misc/convert-host.ts b/packages/backend/src/misc/convert-host.ts
index 7eb940a7e..856ce3c12 100644
--- a/packages/backend/src/misc/convert-host.ts
+++ b/packages/backend/src/misc/convert-host.ts
@@ -1,9 +1,11 @@
-import { URL } from 'node:url';
-import config from '@/config/index.js';
-import { toASCII } from 'punycode';
+import { URL } from "node:url";
+import config from "@/config/index.js";
+import { toASCII } from "punycode";
 
 export function getFullApAccount(username: string, host: string | null) {
-	return host ? `${username}@${toPuny(host)}` : `${username}@${toPuny(config.host)}`;
+	return host
+		? `${username}@${toPuny(host)}`
+		: `${username}@${toPuny(config.host)}`;
 }
 
 export function isSelfHost(host: string) {
diff --git a/packages/backend/src/misc/count-same-renotes.ts b/packages/backend/src/misc/count-same-renotes.ts
index b7f8ce90c..45a6c1d35 100644
--- a/packages/backend/src/misc/count-same-renotes.ts
+++ b/packages/backend/src/misc/count-same-renotes.ts
@@ -1,14 +1,18 @@
-import { Notes } from '@/models/index.js';
+import { Notes } from "@/models/index.js";
 
-export async function countSameRenotes(userId: string, renoteId: string, excludeNoteId: string | undefined): Promise {
+export async function countSameRenotes(
+	userId: string,
+	renoteId: string,
+	excludeNoteId: string | undefined,
+): Promise {
 	// 指定したユーザーの指定したノートのリノートがいくつあるか数える
-	const query = Notes.createQueryBuilder('note')
-		.where('note.userId = :userId', { userId })
-		.andWhere('note.renoteId = :renoteId', { renoteId });
+	const query = Notes.createQueryBuilder("note")
+		.where("note.userId = :userId", { userId })
+		.andWhere("note.renoteId = :renoteId", { renoteId });
 
 	// 指定した投稿を除く
 	if (excludeNoteId) {
-		query.andWhere('note.id != :excludeNoteId', { excludeNoteId });
+		query.andWhere("note.id != :excludeNoteId", { excludeNoteId });
 	}
 
 	return await query.getCount();
diff --git a/packages/backend/src/misc/create-temp.ts b/packages/backend/src/misc/create-temp.ts
index fa88769de..16c85ee7b 100644
--- a/packages/backend/src/misc/create-temp.ts
+++ b/packages/backend/src/misc/create-temp.ts
@@ -1,4 +1,4 @@
-import * as tmp from 'tmp';
+import * as tmp from "tmp";
 
 export function createTemp(): Promise<[string, () => void]> {
 	return new Promise<[string, () => void]>((res, rej) => {
@@ -18,7 +18,7 @@ export function createTempDir(): Promise<[string, () => void]> {
 			(e, path, cleanup) => {
 				if (e) return rej(e);
 				res([path, cleanup]);
-			}
+			},
 		);
 	});
 }
diff --git a/packages/backend/src/misc/detect-url-mime.ts b/packages/backend/src/misc/detect-url-mime.ts
index cd143cf2f..9f0e4325d 100644
--- a/packages/backend/src/misc/detect-url-mime.ts
+++ b/packages/backend/src/misc/detect-url-mime.ts
@@ -1,6 +1,6 @@
-import { createTemp } from './create-temp.js';
-import { downloadUrl } from './download-url.js';
-import { detectType } from './get-file-info.js';
+import { createTemp } from "./create-temp.js";
+import { downloadUrl } from "./download-url.js";
+import { detectType } from "./get-file-info.js";
 
 export async function detectUrlMime(url: string) {
 	const [path, cleanup] = await createTemp();
diff --git a/packages/backend/src/misc/download-text-file.ts b/packages/backend/src/misc/download-text-file.ts
index c62c70ee3..9d3821b20 100644
--- a/packages/backend/src/misc/download-text-file.ts
+++ b/packages/backend/src/misc/download-text-file.ts
@@ -1,10 +1,10 @@
-import * as fs from 'node:fs';
-import * as util from 'node:util';
-import Logger from '@/services/logger.js';
-import { createTemp } from './create-temp.js';
-import { downloadUrl } from './download-url.js';
+import * as fs from "node:fs";
+import * as util from "node:util";
+import Logger from "@/services/logger.js";
+import { createTemp } from "./create-temp.js";
+import { downloadUrl } from "./download-url.js";
 
-const logger = new Logger('download-text-file');
+const logger = new Logger("download-text-file");
 
 export async function downloadTextFile(url: string): Promise {
 	// Create temp file
@@ -16,7 +16,7 @@ export async function downloadTextFile(url: string): Promise {
 		// write content at URL to temp file
 		await downloadUrl(url, path);
 
-		const text = await util.promisify(fs.readFile)(path, 'utf8');
+		const text = await util.promisify(fs.readFile)(path, "utf8");
 
 		return text;
 	} finally {
diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts
index 7c57b140e..7fafb635b 100644
--- a/packages/backend/src/misc/download-url.ts
+++ b/packages/backend/src/misc/download-url.ts
@@ -1,18 +1,18 @@
-import * as fs from 'node:fs';
-import * as stream from 'node:stream';
-import * as util from 'node:util';
-import got, * as Got from 'got';
-import { httpAgent, httpsAgent, StatusError } from './fetch.js';
-import config from '@/config/index.js';
-import chalk from 'chalk';
-import Logger from '@/services/logger.js';
-import IPCIDR from 'ip-cidr';
-import PrivateIp from 'private-ip';
+import * as fs from "node:fs";
+import * as stream from "node:stream";
+import * as util from "node:util";
+import got, * as Got from "got";
+import { httpAgent, httpsAgent, StatusError } from "./fetch.js";
+import config from "@/config/index.js";
+import chalk from "chalk";
+import Logger from "@/services/logger.js";
+import IPCIDR from "ip-cidr";
+import PrivateIp from "private-ip";
 
 const pipeline = util.promisify(stream.pipeline);
 
 export async function downloadUrl(url: string, path: string): Promise {
-	const logger = new Logger('download');
+	const logger = new Logger("download");
 
 	logger.info(`Downloading ${chalk.cyan(url)} ...`);
 
@@ -20,55 +20,69 @@ export async function downloadUrl(url: string, path: string): Promise {
 	const operationTimeout = 60 * 1000;
 	const maxSize = config.maxFileSize || 262144000;
 
-	const req = got.stream(url, {
-		headers: {
-			'User-Agent': config.userAgent,
-		},
-		timeout: {
-			lookup: timeout,
-			connect: timeout,
-			secureConnect: timeout,
-			socket: timeout,	// read timeout
-			response: timeout,
-			send: timeout,
-			request: operationTimeout,	// whole operation timeout
-		},
-		agent: {
-			http: httpAgent,
-			https: httpsAgent,
-		},
-		http2: false,	// default
-		retry: {
-			limit: 0,
-		},
-	}).on('response', (res: Got.Response) => {
-		if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !config.proxy && res.ip) {
-			if (isPrivateIp(res.ip)) {
-				logger.warn(`Blocked address: ${res.ip}`);
-				req.destroy();
+	const req = got
+		.stream(url, {
+			headers: {
+				"User-Agent": config.userAgent,
+			},
+			timeout: {
+				lookup: timeout,
+				connect: timeout,
+				secureConnect: timeout,
+				socket: timeout, // read timeout
+				response: timeout,
+				send: timeout,
+				request: operationTimeout, // whole operation timeout
+			},
+			agent: {
+				http: httpAgent,
+				https: httpsAgent,
+			},
+			http2: false, // default
+			retry: {
+				limit: 0,
+			},
+		})
+		.on("response", (res: Got.Response) => {
+			if (
+				(process.env.NODE_ENV === "production" ||
+					process.env.NODE_ENV === "test") &&
+				!config.proxy &&
+				res.ip
+			) {
+				if (isPrivateIp(res.ip)) {
+					logger.warn(`Blocked address: ${res.ip}`);
+					req.destroy();
+				}
 			}
-		}
 
-		const contentLength = res.headers['content-length'];
-		if (contentLength != null) {
-			const size = Number(contentLength);
-			if (size > maxSize) {
-				logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
+			const contentLength = res.headers["content-length"];
+			if (contentLength != null) {
+				const size = Number(contentLength);
+				if (size > maxSize) {
+					logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
+					req.destroy();
+				}
+			}
+		})
+		.on("downloadProgress", (progress: Got.Progress) => {
+			if (progress.transferred > maxSize) {
+				logger.warn(
+					`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`,
+				);
 				req.destroy();
 			}
-		}
-	}).on('downloadProgress', (progress: Got.Progress) => {
-		if (progress.transferred > maxSize) {
-			logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
-			req.destroy();
-		}
-	});
+		});
 
 	try {
 		await pipeline(req, fs.createWriteStream(path));
 	} catch (e) {
 		if (e instanceof Got.HTTPError) {
-			throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage);
+			throw new StatusError(
+				`${e.response.statusCode} ${e.response.statusMessage}`,
+				e.response.statusCode,
+				e.response.statusMessage,
+			);
 		} else {
 			throw e;
 		}
diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts
index ca224971c..573034f6b 100644
--- a/packages/backend/src/misc/emoji-regex.ts
+++ b/packages/backend/src/misc/emoji-regex.ts
@@ -1,4 +1,4 @@
-import twemoji from 'twemoji-parser/dist/lib/regex.js';
+import twemoji from "twemoji-parser/dist/lib/regex.js";
 const twemojiRegex = twemoji.default;
 
 export const emojiRegex = new RegExp(`(${twemojiRegex.source})`);
diff --git a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts
index a0319d8dd..7de32e6d6 100644
--- a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts
+++ b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts
@@ -1,10 +1,10 @@
-import * as mfm from 'mfm-js';
-import { unique } from '@/prelude/array.js';
+import * as mfm from "mfm-js";
+import { unique } from "@/prelude/array.js";
 
 export function extractCustomEmojisFromMfm(nodes: mfm.MfmNode[]): string[] {
 	const emojiNodes = mfm.extract(nodes, (node) => {
-		return (node.type === 'emojiCode' && node.props.name.length <= 100);
+		return node.type === "emojiCode" && node.props.name.length <= 100;
 	});
 
-	return unique(emojiNodes.map(x => x.props.name));
+	return unique(emojiNodes.map((x) => x.props.name));
 }
diff --git a/packages/backend/src/misc/extract-hashtags.ts b/packages/backend/src/misc/extract-hashtags.ts
index 0b0418eef..826e36221 100644
--- a/packages/backend/src/misc/extract-hashtags.ts
+++ b/packages/backend/src/misc/extract-hashtags.ts
@@ -1,9 +1,9 @@
-import * as mfm from 'mfm-js';
-import { unique } from '@/prelude/array.js';
+import * as mfm from "mfm-js";
+import { unique } from "@/prelude/array.js";
 
 export function extractHashtags(nodes: mfm.MfmNode[]): string[] {
-	const hashtagNodes = mfm.extract(nodes, (node) => node.type === 'hashtag');
-	const hashtags = unique(hashtagNodes.map(x => x.props.hashtag));
+	const hashtagNodes = mfm.extract(nodes, (node) => node.type === "hashtag");
+	const hashtags = unique(hashtagNodes.map((x) => x.props.hashtag));
 
 	return hashtags;
 }
diff --git a/packages/backend/src/misc/extract-mentions.ts b/packages/backend/src/misc/extract-mentions.ts
index cc19b161a..259f78e57 100644
--- a/packages/backend/src/misc/extract-mentions.ts
+++ b/packages/backend/src/misc/extract-mentions.ts
@@ -1,11 +1,13 @@
 // test is located in test/extract-mentions
 
-import * as mfm from 'mfm-js';
+import * as mfm from "mfm-js";
 
-export function extractMentions(nodes: mfm.MfmNode[]): mfm.MfmMention['props'][] {
+export function extractMentions(
+	nodes: mfm.MfmNode[],
+): mfm.MfmMention["props"][] {
 	// TODO: 重複を削除
-	const mentionNodes = mfm.extract(nodes, (node) => node.type === 'mention');
-	const mentions = mentionNodes.map(x => x.props);
+	const mentionNodes = mfm.extract(nodes, (node) => node.type === "mention");
+	const mentions = mentionNodes.map((x) => x.props);
 
 	return mentions;
 }
diff --git a/packages/backend/src/misc/fetch-meta.ts b/packages/backend/src/misc/fetch-meta.ts
index 3e74118f0..32c45813c 100644
--- a/packages/backend/src/misc/fetch-meta.ts
+++ b/packages/backend/src/misc/fetch-meta.ts
@@ -1,16 +1,16 @@
-import { db } from '@/db/postgre.js';
-import { Meta } from '@/models/entities/meta.js';
+import { db } from "@/db/postgre.js";
+import { Meta } from "@/models/entities/meta.js";
 
 let cache: Meta;
 
 export async function fetchMeta(noCache = false): Promise {
 	if (!noCache && cache) return cache;
 
-	return await db.transaction(async transactionalEntityManager => {
+	return await db.transaction(async (transactionalEntityManager) => {
 		// New IDs are prioritized because multiple records may have been created due to past bugs.
 		const metas = await transactionalEntityManager.find(Meta, {
 			order: {
-				id: 'DESC',
+				id: "DESC",
 			},
 		});
 
@@ -25,11 +25,13 @@ export async function fetchMeta(noCache = false): Promise {
 				.upsert(
 					Meta,
 					{
-						id: 'x',
+						id: "x",
 					},
-					['id'],
+					["id"],
 				)
-				.then((x) => transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]));
+				.then((x) =>
+					transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]),
+				);
 
 			cache = saved;
 			return saved;
@@ -38,7 +40,7 @@ export async function fetchMeta(noCache = false): Promise {
 }
 
 setInterval(() => {
-	fetchMeta(true).then(meta => {
+	fetchMeta(true).then((meta) => {
 		cache = meta;
 	});
 }, 1000 * 10);
diff --git a/packages/backend/src/misc/fetch-proxy-account.ts b/packages/backend/src/misc/fetch-proxy-account.ts
index b61bba264..a277db6fb 100644
--- a/packages/backend/src/misc/fetch-proxy-account.ts
+++ b/packages/backend/src/misc/fetch-proxy-account.ts
@@ -1,9 +1,11 @@
-import { fetchMeta } from './fetch-meta.js';
-import { ILocalUser } from '@/models/entities/user.js';
-import { Users } from '@/models/index.js';
+import { fetchMeta } from "./fetch-meta.js";
+import type { ILocalUser } from "@/models/entities/user.js";
+import { Users } from "@/models/index.js";
 
 export async function fetchProxyAccount(): Promise {
 	const meta = await fetchMeta();
 	if (meta.proxyAccountId == null) return null;
-	return await Users.findOneByOrFail({ id: meta.proxyAccountId }) as ILocalUser;
+	return (await Users.findOneByOrFail({
+		id: meta.proxyAccountId,
+	})) as ILocalUser;
 }
diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts
index af6bf2fca..0e673ba3a 100644
--- a/packages/backend/src/misc/fetch.ts
+++ b/packages/backend/src/misc/fetch.ts
@@ -1,40 +1,63 @@
-import * as http from 'node:http';
-import * as https from 'node:https';
-import { URL } from 'node:url';
-import CacheableLookup from 'cacheable-lookup';
-import fetch from 'node-fetch';
-import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
-import config from '@/config/index.js';
+import * as http from "node:http";
+import * as https from "node:https";
+import type { URL } from "node:url";
+import CacheableLookup from "cacheable-lookup";
+import fetch from "node-fetch";
+import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
+import config from "@/config/index.js";
 
-export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record) {
+export async function getJson(
+	url: string,
+	accept = "application/json, */*",
+	timeout = 10000,
+	headers?: Record,
+) {
 	const res = await getResponse({
 		url,
-		method: 'GET',
-		headers: Object.assign({
-			'User-Agent': config.userAgent,
-			Accept: accept,
-		}, headers || {}),
+		method: "GET",
+		headers: Object.assign(
+			{
+				"User-Agent": config.userAgent,
+				Accept: accept,
+			},
+			headers || {},
+		),
 		timeout,
 	});
 
 	return await res.json();
 }
 
-export async function getHtml(url: string, accept = 'text/html, */*', timeout = 10000, headers?: Record) {
+export async function getHtml(
+	url: string,
+	accept = "text/html, */*",
+	timeout = 10000,
+	headers?: Record,
+) {
 	const res = await getResponse({
 		url,
-		method: 'GET',
-		headers: Object.assign({
-			'User-Agent': config.userAgent,
-			Accept: accept,
-		}, headers || {}),
+		method: "GET",
+		headers: Object.assign(
+			{
+				"User-Agent": config.userAgent,
+				Accept: accept,
+			},
+			headers || {},
+		),
 		timeout,
 	});
 
 	return await res.text();
 }
 
-export async function getResponse(args: { url: string, method: string, body?: string, headers: Record, timeout?: number, size?: number }) {
+export async function getResponse(args: {
+	url: string;
+	method: string;
+	body?: string;
+	headers: Record;
+	timeout?: number;
+	size?: number;
+}) {
 	const timeout = args.timeout || 10 * 1000;
 
 	const controller = new AbortController();
@@ -53,16 +76,20 @@ export async function getResponse(args: { url: string, method: string, body?: st
 	});
 
 	if (!res.ok) {
-		throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
+		throw new StatusError(
+			`${res.status} ${res.statusText}`,
+			res.status,
+			res.statusText,
+		);
 	}
 
 	return res;
 }
 
 const cache = new CacheableLookup({
-	maxTtl: 3600,	// 1hours
-	errorTtl: 30,	// 30secs
-	lookup: false,	// nativeのdns.lookupにfallbackしない
+	maxTtl: 3600, // 1hours
+	errorTtl: 30, // 30secs
+	lookup: false, // nativeのdns.lookupにfallbackしない
 });
 
 /**
@@ -90,13 +117,13 @@ const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
  */
 export const httpAgent = config.proxy
 	? new HttpProxyAgent({
-		keepAlive: true,
-		keepAliveMsecs: 30 * 1000,
-		maxSockets,
-		maxFreeSockets: 256,
-		scheduling: 'lifo',
-		proxy: config.proxy,
-	})
+			keepAlive: true,
+			keepAliveMsecs: 30 * 1000,
+			maxSockets,
+			maxFreeSockets: 256,
+			scheduling: "lifo",
+			proxy: config.proxy,
+	  })
 	: _http;
 
 /**
@@ -104,13 +131,13 @@ export const httpAgent = config.proxy
  */
 export const httpsAgent = config.proxy
 	? new HttpsProxyAgent({
-		keepAlive: true,
-		keepAliveMsecs: 30 * 1000,
-		maxSockets,
-		maxFreeSockets: 256,
-		scheduling: 'lifo',
-		proxy: config.proxy,
-	})
+			keepAlive: true,
+			keepAliveMsecs: 30 * 1000,
+			maxSockets,
+			maxFreeSockets: 256,
+			scheduling: "lifo",
+			proxy: config.proxy,
+	  })
 	: _https;
 
 /**
@@ -120,9 +147,9 @@ export const httpsAgent = config.proxy
  */
 export function getAgentByUrl(url: URL, bypassProxy = false) {
 	if (bypassProxy || (config.proxyBypassHosts || []).includes(url.hostname)) {
-		return url.protocol === 'http:' ? _http : _https;
+		return url.protocol === "http:" ? _http : _https;
 	} else {
-		return url.protocol === 'http:' ? httpAgent : httpsAgent;
+		return url.protocol === "http:" ? httpAgent : httpsAgent;
 	}
 }
 
@@ -133,9 +160,12 @@ export class StatusError extends Error {
 
 	constructor(message: string, statusCode: number, statusMessage?: string) {
 		super(message);
-		this.name = 'StatusError';
+		this.name = "StatusError";
 		this.statusCode = statusCode;
 		this.statusMessage = statusMessage;
-		this.isClientError = typeof this.statusCode === 'number' && this.statusCode >= 400 && this.statusCode < 500;
+		this.isClientError =
+			typeof this.statusCode === "number" &&
+			this.statusCode >= 400 &&
+			this.statusCode < 500;
 	}
 }
diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts
index fcf476857..b7cc0965a 100644
--- a/packages/backend/src/misc/gen-id.ts
+++ b/packages/backend/src/misc/gen-id.ts
@@ -1,21 +1,27 @@
-import { ulid } from 'ulid';
-import { genAid } from './id/aid.js';
-import { genMeid } from './id/meid.js';
-import { genMeidg } from './id/meidg.js';
-import { genObjectId } from './id/object-id.js';
-import config from '@/config/index.js';
+import { ulid } from "ulid";
+import { genAid } from "./id/aid.js";
+import { genMeid } from "./id/meid.js";
+import { genMeidg } from "./id/meidg.js";
+import { genObjectId } from "./id/object-id.js";
+import config from "@/config/index.js";
 
 const metohd = config.id.toLowerCase();
 
 export function genId(date?: Date): string {
-	if (!date || (date > new Date())) date = new Date();
+	if (!date || date > new Date()) date = new Date();
 
 	switch (metohd) {
-		case 'aid': return genAid(date);
-		case 'meid': return genMeid(date);
-		case 'meidg': return genMeidg(date);
-		case 'ulid': return ulid(date.getTime());
-		case 'objectid': return genObjectId(date);
-		default: throw new Error('unrecognized id generation method');
+		case "aid":
+			return genAid(date);
+		case "meid":
+			return genMeid(date);
+		case "meidg":
+			return genMeidg(date);
+		case "ulid":
+			return ulid(date.getTime());
+		case "objectid":
+			return genObjectId(date);
+		default:
+			throw new Error("unrecognized id generation method");
 	}
 }
diff --git a/packages/backend/src/misc/gen-identicon.ts b/packages/backend/src/misc/gen-identicon.ts
index 322ffee22..79297f8f2 100644
--- a/packages/backend/src/misc/gen-identicon.ts
+++ b/packages/backend/src/misc/gen-identicon.ts
@@ -3,37 +3,37 @@
  * https://en.wikipedia.org/wiki/Identicon
  */
 
-import { WriteStream } from 'node:fs';
-import * as p from 'pureimage';
-import gen from 'random-seed';
+import type { WriteStream } from "node:fs";
+import * as p from "pureimage";
+import gen from "random-seed";
 
 const size = 128; // px
 const n = 5; // resolution
-const margin = (size / 4);
+const margin = size / 4;
 const colors = [
-	['#FF512F', '#DD2476'],
-	['#FF61D2', '#FE9090'],
-	['#72FFB6', '#10D164'],
-	['#FD8451', '#FFBD6F'],
-	['#305170', '#6DFC6B'],
-	['#00C0FF', '#4218B8'],
-	['#009245', '#FCEE21'],
-	['#0100EC', '#FB36F4'],
-	['#FDABDD', '#374A5A'],
-	['#38A2D7', '#561139'],
-	['#121C84', '#8278DA'],
-	['#5761B2', '#1FC5A8'],
-	['#FFDB01', '#0E197D'],
-	['#FF3E9D', '#0E1F40'],
-	['#766eff', '#00d4ff'],
-	['#9bff6e', '#00d4ff'],
-	['#ff6e94', '#00d4ff'],
-	['#ffa96e', '#00d4ff'],
-	['#ffa96e', '#ff009d'],
-	['#ffdd6e', '#ff009d'],
+	["#FF512F", "#DD2476"],
+	["#FF61D2", "#FE9090"],
+	["#72FFB6", "#10D164"],
+	["#FD8451", "#FFBD6F"],
+	["#305170", "#6DFC6B"],
+	["#00C0FF", "#4218B8"],
+	["#009245", "#FCEE21"],
+	["#0100EC", "#FB36F4"],
+	["#FDABDD", "#374A5A"],
+	["#38A2D7", "#561139"],
+	["#121C84", "#8278DA"],
+	["#5761B2", "#1FC5A8"],
+	["#FFDB01", "#0E197D"],
+	["#FF3E9D", "#0E1F40"],
+	["#766eff", "#00d4ff"],
+	["#9bff6e", "#00d4ff"],
+	["#ff6e94", "#00d4ff"],
+	["#ffa96e", "#00d4ff"],
+	["#ffa96e", "#ff009d"],
+	["#ffdd6e", "#ff009d"],
 ];
 
-const actualSize = size - (margin * 2);
+const actualSize = size - margin * 2;
 const cellSize = actualSize / n;
 const sideN = Math.floor(n / 2);
 
@@ -43,7 +43,7 @@ const sideN = Math.floor(n / 2);
 export function genIdenticon(seed: string, stream: WriteStream): Promise {
 	const rand = gen.create(seed);
 	const canvas = p.make(size, size, undefined);
-	const ctx = canvas.getContext('2d');
+	const ctx = canvas.getContext("2d");
 
 	const bgColors = colors[rand(colors.length)];
 
@@ -55,7 +55,7 @@ export function genIdenticon(seed: string, stream: WriteStream): Promise {
 	ctx.beginPath();
 	ctx.fillRect(0, 0, size, size);
 
-	ctx.fillStyle = '#ffffff';
+	ctx.fillStyle = "#ffffff";
 
 	// side bitmap (filled by false)
 	const side: boolean[][] = new Array(sideN);
@@ -66,7 +66,6 @@ export function genIdenticon(seed: string, stream: WriteStream): Promise {
 	// 1*n (filled by false)
 	const center: boolean[] = new Array(n).fill(false);
 
-	// eslint:disable-next-line:prefer-for-of
 	for (let x = 0; x < side.length; x++) {
 		for (let y = 0; y < side[x].length; y++) {
 			side[x][y] = rand(3) === 0;
@@ -80,17 +79,17 @@ export function genIdenticon(seed: string, stream: WriteStream): Promise {
 	// Draw
 	for (let x = 0; x < n; x++) {
 		for (let y = 0; y < n; y++) {
-			const isXCenter = x === ((n - 1) / 2);
+			const isXCenter = x === (n - 1) / 2;
 			if (isXCenter && !center[y]) continue;
 
-			const isLeftSide = x < ((n - 1) / 2);
+			const isLeftSide = x < (n - 1) / 2;
 			if (isLeftSide && !side[x][y]) continue;
 
-			const isRightSide = x > ((n - 1) / 2);
+			const isRightSide = x > (n - 1) / 2;
 			if (isRightSide && !side[sideN - (x - sideN)][y]) continue;
 
-			const actualX = margin + (cellSize * x);
-			const actualY = margin + (cellSize * y);
+			const actualX = margin + cellSize * x;
+			const actualY = margin + cellSize * y;
 			ctx.beginPath();
 			ctx.fillRect(actualX, actualY, cellSize, cellSize);
 		}
diff --git a/packages/backend/src/misc/gen-key-pair.ts b/packages/backend/src/misc/gen-key-pair.ts
index e2ad59850..8ae4175e3 100644
--- a/packages/backend/src/misc/gen-key-pair.ts
+++ b/packages/backend/src/misc/gen-key-pair.ts
@@ -1,34 +1,40 @@
-import * as crypto from 'node:crypto';
-import * as util from 'node:util';
+import * as crypto from "node:crypto";
+import * as util from "node:util";
 
 const generateKeyPair = util.promisify(crypto.generateKeyPair);
 
 export async function genRsaKeyPair(modulusLength = 2048) {
-	return await generateKeyPair('rsa', {
+	return await generateKeyPair("rsa", {
 		modulusLength,
 		publicKeyEncoding: {
-			type: 'spki',
-			format: 'pem',
+			type: "spki",
+			format: "pem",
 		},
 		privateKeyEncoding: {
-			type: 'pkcs8',
-			format: 'pem',
+			type: "pkcs8",
+			format: "pem",
 			cipher: undefined,
 			passphrase: undefined,
 		},
 	});
 }
 
-export async function genEcKeyPair(namedCurve: 'prime256v1' | 'secp384r1' | 'secp521r1' | 'curve25519' = 'prime256v1') {
-	return await generateKeyPair('ec', {
+export async function genEcKeyPair(
+	namedCurve:
+		| "prime256v1"
+		| "secp384r1"
+		| "secp521r1"
+		| "curve25519" = "prime256v1",
+) {
+	return await generateKeyPair("ec", {
 		namedCurve,
 		publicKeyEncoding: {
-			type: 'spki',
-			format: 'pem',
+			type: "spki",
+			format: "pem",
 		},
 		privateKeyEncoding: {
-			type: 'pkcs8',
-			format: 'pem',
+			type: "pkcs8",
+			format: "pem",
 			cipher: undefined,
 			passphrase: undefined,
 		},
diff --git a/packages/backend/src/misc/get-file-info.ts b/packages/backend/src/misc/get-file-info.ts
index b4922779a..a63de286e 100644
--- a/packages/backend/src/misc/get-file-info.ts
+++ b/packages/backend/src/misc/get-file-info.ts
@@ -1,18 +1,18 @@
-import * as fs from 'node:fs';
-import * as crypto from 'node:crypto';
-import { join } from 'node:path';
-import * as stream from 'node:stream';
-import * as util from 'node:util';
-import { FSWatcher } from 'chokidar';
-import { fileTypeFromFile } from 'file-type';
-import FFmpeg from 'fluent-ffmpeg';
-import isSvg from 'is-svg';
-import probeImageSize from 'probe-image-size';
-import { type predictionType } from 'nsfwjs';
-import sharp from 'sharp';
-import { encode } from 'blurhash';
-import { detectSensitive } from '@/services/detect-sensitive.js';
-import { createTempDir } from './create-temp.js';
+import * as fs from "node:fs";
+import * as crypto from "node:crypto";
+import { join } from "node:path";
+import * as stream from "node:stream";
+import * as util from "node:util";
+import { FSWatcher } from "chokidar";
+import { fileTypeFromFile } from "file-type";
+import FFmpeg from "fluent-ffmpeg";
+import isSvg from "is-svg";
+import probeImageSize from "probe-image-size";
+import { type predictionType } from "nsfwjs";
+import sharp from "sharp";
+import { encode } from "blurhash";
+import { detectSensitive } from "@/services/detect-sensitive.js";
+import { createTempDir } from "./create-temp.js";
 
 const pipeline = util.promisify(stream.pipeline);
 
@@ -33,24 +33,27 @@ export type FileInfo = {
 };
 
 const TYPE_OCTET_STREAM = {
-	mime: 'application/octet-stream',
+	mime: "application/octet-stream",
 	ext: null,
 };
 
 const TYPE_SVG = {
-	mime: 'image/svg+xml',
-	ext: 'svg',
+	mime: "image/svg+xml",
+	ext: "svg",
 };
 
 /**
  * Get file information
  */
-export async function getFileInfo(path: string, opts: {
-	skipSensitiveDetection: boolean;
-	sensitiveThreshold?: number;
-	sensitiveThresholdForPorn?: number;
-	enableSensitiveMediaDetectionForVideos?: boolean;
-}): Promise {
+export async function getFileInfo(
+	path: string,
+	opts: {
+		skipSensitiveDetection: boolean;
+		sensitiveThreshold?: number;
+		sensitiveThresholdForPorn?: number;
+		enableSensitiveMediaDetectionForVideos?: boolean;
+	},
+): Promise {
 	const warnings = [] as string[];
 
 	const size = await getFileSize(path);
@@ -63,24 +66,37 @@ export async function getFileInfo(path: string, opts: {
 	let height: number | undefined;
 	let orientation: number | undefined;
 
-	if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/bmp', 'image/tiff', 'image/svg+xml', 'image/vnd.adobe.photoshop', 'image/avif'].includes(type.mime)) {
-		const imageSize = await detectImageSize(path).catch(e => {
+	if (
+		[
+			"image/jpeg",
+			"image/gif",
+			"image/png",
+			"image/apng",
+			"image/webp",
+			"image/bmp",
+			"image/tiff",
+			"image/svg+xml",
+			"image/vnd.adobe.photoshop",
+			"image/avif",
+		].includes(type.mime)
+	) {
+		const imageSize = await detectImageSize(path).catch((e) => {
 			warnings.push(`detectImageSize failed: ${e}`);
 			return undefined;
 		});
 
 		// うまく判定できない画像は octet-stream にする
 		if (!imageSize) {
-			warnings.push('cannot detect image dimensions');
+			warnings.push("cannot detect image dimensions");
 			type = TYPE_OCTET_STREAM;
-		} else if (imageSize.wUnits === 'px') {
+		} else if (imageSize.wUnits === "px") {
 			width = imageSize.width;
 			height = imageSize.height;
 			orientation = imageSize.orientation;
 
 			// 制限を超えている画像は octet-stream にする
 			if (imageSize.width > 16383 || imageSize.height > 16383) {
-				warnings.push('image dimensions exceeds limits');
+				warnings.push("image dimensions exceeds limits");
 				type = TYPE_OCTET_STREAM;
 			}
 		} else {
@@ -90,8 +106,18 @@ export async function getFileInfo(path: string, opts: {
 
 	let blurhash: string | undefined;
 
-	if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/svg+xml', 'image/avif'].includes(type.mime)) {
-		blurhash = await getBlurhash(path).catch(e => {
+	if (
+		[
+			"image/jpeg",
+			"image/gif",
+			"image/png",
+			"image/apng",
+			"image/webp",
+			"image/svg+xml",
+			"image/avif",
+		].includes(type.mime)
+	) {
+		blurhash = await getBlurhash(path).catch((e) => {
 			warnings.push(`getBlurhash failed: ${e}`);
 			return undefined;
 		});
@@ -107,11 +133,14 @@ export async function getFileInfo(path: string, opts: {
 			opts.sensitiveThreshold ?? 0.5,
 			opts.sensitiveThresholdForPorn ?? 0.75,
 			opts.enableSensitiveMediaDetectionForVideos ?? false,
-		).then(value => {
-			[sensitive, porn] = value;
-		}, error => {
-			warnings.push(`detectSensitivity failed: ${error}`);
-		});
+		).then(
+			(value) => {
+				[sensitive, porn] = value;
+			},
+			(error) => {
+				warnings.push(`detectSensitivity failed: ${error}`);
+			},
+		);
 	}
 
 	return {
@@ -128,71 +157,100 @@ export async function getFileInfo(path: string, opts: {
 	};
 }
 
-async function detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
+async function detectSensitivity(
+	source: string,
+	mime: string,
+	sensitiveThreshold: number,
+	sensitiveThresholdForPorn: number,
+	analyzeVideo: boolean,
+): Promise<[sensitive: boolean, porn: boolean]> {
 	let sensitive = false;
 	let porn = false;
 
-	function judgePrediction(result: readonly predictionType[]): [sensitive: boolean, porn: boolean] {
+	function judgePrediction(
+		result: readonly predictionType[],
+	): [sensitive: boolean, porn: boolean] {
 		let sensitive = false;
 		let porn = false;
 
-		if ((result.find(x => x.className === 'Sexy')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
-		if ((result.find(x => x.className === 'Hentai')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
-		if ((result.find(x => x.className === 'Porn')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
+		if (
+			(result.find((x) => x.className === "Sexy")?.probability ?? 0) >
+			sensitiveThreshold
+		)
+			sensitive = true;
+		if (
+			(result.find((x) => x.className === "Hentai")?.probability ?? 0) >
+			sensitiveThreshold
+		)
+			sensitive = true;
+		if (
+			(result.find((x) => x.className === "Porn")?.probability ?? 0) >
+			sensitiveThreshold
+		)
+			sensitive = true;
 
-		if ((result.find(x => x.className === 'Porn')?.probability ?? 0) > sensitiveThresholdForPorn) porn = true;
+		if (
+			(result.find((x) => x.className === "Porn")?.probability ?? 0) >
+			sensitiveThresholdForPorn
+		)
+			porn = true;
 
 		return [sensitive, porn];
 	}
 
-	if (['image/jpeg', 'image/png', 'image/webp'].includes(mime)) {
+	if (["image/jpeg", "image/png", "image/webp"].includes(mime)) {
 		const result = await detectSensitive(source);
 		if (result) {
 			[sensitive, porn] = judgePrediction(result);
 		}
-	} else if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
+	} else if (
+		analyzeVideo &&
+		(mime === "image/apng" || mime.startsWith("video/"))
+	) {
 		const [outDir, disposeOutDir] = await createTempDir();
 		try {
 			const command = FFmpeg()
 				.input(source)
 				.inputOptions([
-					'-skip_frame', 'nokey', // 可能ならキーフレームのみを取得してほしいとする(そうなるとは限らない)
-					'-lowres', '3', // 元の画質でデコードする必要はないので 1/8 画質でデコードしてもよいとする(そうなるとは限らない)
+					"-skip_frame",
+					"nokey", // 可能ならキーフレームのみを取得してほしいとする(そうなるとは限らない)
+					"-lowres",
+					"3", // 元の画質でデコードする必要はないので 1/8 画質でデコードしてもよいとする(そうなるとは限らない)
 				])
 				.noAudio()
 				.videoFilters([
 					{
-						filter: 'select', // フレームのフィルタリング
+						filter: "select", // フレームのフィルタリング
 						options: {
-							e: 'eq(pict_type,PICT_TYPE_I)', // I-Frame のみをフィルタする(VP9 とかはデコードしてみないとわからないっぽい)
+							e: "eq(pict_type,PICT_TYPE_I)", // I-Frame のみをフィルタする(VP9 とかはデコードしてみないとわからないっぽい)
 						},
 					},
 					{
-						filter: 'blackframe', // 暗いフレームの検出
+						filter: "blackframe", // 暗いフレームの検出
 						options: {
-							amount: '0', // 暗さに関わらず全てのフレームで測定値を取る
+							amount: "0", // 暗さに関わらず全てのフレームで測定値を取る
 						},
 					},
 					{
-						filter: 'metadata',
+						filter: "metadata",
 						options: {
-							mode: 'select', // フレーム選択モード
-							key: 'lavfi.blackframe.pblack', // フレームにおける暗部の百分率(前のフィルタからのメタデータを参照する)
-							value: '50',
-							function: 'less', // 50% 未満のフレームを選択する(50% 以上暗部があるフレームだと誤検知を招くかもしれないので)
+							mode: "select", // フレーム選択モード
+							key: "lavfi.blackframe.pblack", // フレームにおける暗部の百分率(前のフィルタからのメタデータを参照する)
+							value: "50",
+							function: "less", // 50% 未満のフレームを選択する(50% 以上暗部があるフレームだと誤検知を招くかもしれないので)
 						},
 					},
 					{
-						filter: 'scale',
+						filter: "scale",
 						options: {
 							w: 299,
 							h: 299,
 						},
 					},
 				])
-				.format('image2')
-				.output(join(outDir, '%d.png'))
-				.outputOptions(['-vsync', '0']); // 可変フレームレートにすることで穴埋めをさせない
+				.format("image2")
+				.output(join(outDir, "%d.png"))
+				.outputOptions(["-vsync", "0"]); // 可変フレームレートにすることで穴埋めをさせない
 			const results: ReturnType[] = [];
 			let frameIndex = 0;
 			let targetIndex = 0;
@@ -213,8 +271,12 @@ async function detectSensitivity(source: string, mime: string, sensitiveThreshol
 					fs.promises.unlink(path);
 				}
 			}
-			sensitive = results.filter(x => x[0]).length >= Math.ceil(results.length * sensitiveThreshold);
-			porn = results.filter(x => x[1]).length >= Math.ceil(results.length * sensitiveThresholdForPorn);
+			sensitive =
+				results.filter((x) => x[0]).length >=
+				Math.ceil(results.length * sensitiveThreshold);
+			porn =
+				results.filter((x) => x[1]).length >=
+				Math.ceil(results.length * sensitiveThresholdForPorn);
 		} finally {
 			disposeOutDir();
 		}
@@ -223,35 +285,39 @@ async function detectSensitivity(source: string, mime: string, sensitiveThreshol
 	return [sensitive, porn];
 }
 
-async function* asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator {
+async function* asyncIterateFrames(
+	cwd: string,
+	command: FFmpeg.FfmpegCommand,
+): AsyncGenerator {
 	const watcher = new FSWatcher({
 		cwd,
 		disableGlobbing: true,
 	});
 	let finished = false;
-	command.once('end', () => {
+	command.once("end", () => {
 		finished = true;
 		watcher.close();
 	});
 	command.run();
-	for (let i = 1; true; i++) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
+	for (let i = 1; true; i++) {
 		const current = `${i}.png`;
 		const next = `${i + 1}.png`;
 		const framePath = join(cwd, current);
 		if (await exists(join(cwd, next))) {
 			yield framePath;
-		} else if (!finished) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
+		} else if (!finished) {
 			watcher.add(next);
 			await new Promise((resolve, reject) => {
-				watcher.on('add', function onAdd(path) {
-					if (path === next) { // 次フレームの書き出しが始まっているなら、現在フレームの書き出しは終わっている
+				watcher.on("add", function onAdd(path) {
+					if (path === next) {
+						// 次フレームの書き出しが始まっているなら、現在フレームの書き出しは終わっている
 						watcher.unwatch(current);
-						watcher.off('add', onAdd);
+						watcher.off("add", onAdd);
 						resolve();
 					}
 				});
-				command.once('end', resolve); // 全てのフレームを処理し終わったなら、最終フレームである現在フレームの書き出しは終わっている
-				command.once('error', reject);
+				command.once("end", resolve); // 全てのフレームを処理し終わったなら、最終フレームである現在フレームの書き出しは終わっている
+				command.once("error", reject);
 			});
 			yield framePath;
 		} else if (await exists(framePath)) {
@@ -263,7 +329,10 @@ async function* asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand):
 }
 
 function exists(path: string): Promise {
-	return fs.promises.access(path).then(() => true, () => false);
+	return fs.promises.access(path).then(
+		() => true,
+		() => false,
+	);
 }
 
 /**
@@ -283,7 +352,7 @@ export async function detectType(path: string): Promise<{
 
 	if (type) {
 		// XMLはSVGかもしれない
-		if (type.mime === 'application/xml' && await checkSvg(path)) {
+		if (type.mime === "application/xml" && (await checkSvg(path))) {
 			return TYPE_SVG;
 		}
 
@@ -327,7 +396,7 @@ export async function getFileSize(path: string): Promise {
  * Calculate MD5 hash
  */
 async function calcHash(path: string): Promise {
-	const hash = crypto.createHash('md5').setEncoding('hex');
+	const hash = crypto.createHash("md5").setEncoding("hex");
 	await pipeline(fs.createReadStream(path), hash);
 	return hash.read();
 }
@@ -356,7 +425,7 @@ function getBlurhash(path: string): Promise {
 		sharp(path)
 			.raw()
 			.ensureAlpha()
-			.resize(64, 64, { fit: 'inside' })
+			.resize(64, 64, { fit: "inside" })
 			.toBuffer((err, buffer, { width, height }) => {
 				if (err) return reject(err);
 
diff --git a/packages/backend/src/misc/get-ip-hash.ts b/packages/backend/src/misc/get-ip-hash.ts
index 379325bb1..3bafaee5d 100644
--- a/packages/backend/src/misc/get-ip-hash.ts
+++ b/packages/backend/src/misc/get-ip-hash.ts
@@ -1,9 +1,14 @@
-import IPCIDR from 'ip-cidr';
+import IPCIDR from "ip-cidr";
 
 export function getIpHash(ip: string) {
-	// because a single person may control many IPv6 addresses,
-	// only a /64 subnet prefix of any IP will be taken into account.
-	// (this means for IPv4 the entire address is used)
-	const prefix = IPCIDR.createAddress(ip).mask(64);
-	return 'ip-' + BigInt('0b' + prefix).toString(36);
+	try {
+		// because a single person may control many IPv6 addresses,
+		// only a /64 subnet prefix of any IP will be taken into account.
+		// (this means for IPv4 the entire address is used)
+		const prefix = IPCIDR.createAddress(ip).mask(64);
+		return `ip-${BigInt(`0b${prefix}`).toString(36)}`;
+	} catch (e) {
+		const prefix = IPCIDR.createAddress(ip.replace(/:[0-9]+$/, "")).mask(64);
+		return `ip-${BigInt(`0b${prefix}`).toString(36)}`;
+	}
 }
diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts
index 96267400a..446e3fc14 100644
--- a/packages/backend/src/misc/get-note-summary.ts
+++ b/packages/backend/src/misc/get-note-summary.ts
@@ -1,21 +1,21 @@
-import { Packed } from './schema.js';
+import type { Packed } from "./schema.js";
 
 /**
  * 投稿を表す文字列を取得します。
  * @param {*} note (packされた)投稿
  */
-export const getNoteSummary = (note: Packed<'Note'>): string => {
+export const getNoteSummary = (note: Packed<"Note">): string => {
 	if (note.deletedAt) {
-		return `(❌⛔)`;
+		return "❌";
 	}
 
-	let summary = '';
+	let summary = "";
 
 	// 本文
 	if (note.cw != null) {
 		summary += note.cw;
 	} else {
-		summary += note.text ? note.text : '';
+		summary += note.text ? note.text : "";
 	}
 
 	// ファイルが添付されているとき
@@ -25,7 +25,7 @@ export const getNoteSummary = (note: Packed<'Note'>): string => {
 
 	// 投票が添付されているとき
 	if (note.poll) {
-		summary += ` (📊)`;
+		summary += " (📊)";
 	}
 
 	/*
diff --git a/packages/backend/src/misc/get-reaction-emoji.ts b/packages/backend/src/misc/get-reaction-emoji.ts
index c2e0b9858..71521c4ae 100644
--- a/packages/backend/src/misc/get-reaction-emoji.ts
+++ b/packages/backend/src/misc/get-reaction-emoji.ts
@@ -1,16 +1,28 @@
-export default function(reaction: string): string {
+export default function (reaction: string): string {
 	switch (reaction) {
-		case 'like': return '👍';
-		case 'love': return '❤️';
-		case 'laugh': return '😆';
-		case 'hmm': return '🤔';
-		case 'surprise': return '😮';
-		case 'congrats': return '🎉';
-		case 'angry': return '💢';
-		case 'confused': return '😥';
-		case 'rip': return '😇';
-		case 'pudding': return '🍮';
-		case 'star': return '⭐';
-		default: return reaction;
+		case "like":
+			return "👍";
+		case "love":
+			return "❤️";
+		case "laugh":
+			return "😆";
+		case "hmm":
+			return "🤔";
+		case "surprise":
+			return "😮";
+		case "congrats":
+			return "🎉";
+		case "angry":
+			return "💢";
+		case "confused":
+			return "😥";
+		case "rip":
+			return "😇";
+		case "pudding":
+			return "🍮";
+		case "star":
+			return "⭐";
+		default:
+			return reaction;
 	}
 }
diff --git a/packages/backend/src/misc/hard-limits.ts b/packages/backend/src/misc/hard-limits.ts
index 1039f7335..4ba90293c 100644
--- a/packages/backend/src/misc/hard-limits.ts
+++ b/packages/backend/src/misc/hard-limits.ts
@@ -1,4 +1,3 @@
-
 // If you change DB_* values, you must also change the DB schema.
 
 /**
diff --git a/packages/backend/src/misc/i18n.ts b/packages/backend/src/misc/i18n.ts
index 4fa398763..742bdb0f6 100644
--- a/packages/backend/src/misc/i18n.ts
+++ b/packages/backend/src/misc/i18n.ts
@@ -13,7 +13,7 @@ export class I18n> {
 	// なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも
 	public t(key: string, args?: Record): string {
 		try {
-			let str = key.split('.').reduce((o, i) => o[i], this.locale) as string;
+			let str = key.split(".").reduce((o, i) => o[i], this.locale) as string;
 
 			if (args) {
 				for (const [k, v] of Object.entries(args)) {
diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts
index 87e688826..a12360360 100644
--- a/packages/backend/src/misc/id/aid.ts
+++ b/packages/backend/src/misc/id/aid.ts
@@ -1,7 +1,7 @@
 // AID
 // 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
 
-import * as crypto from 'node:crypto';
+import * as crypto from "node:crypto";
 
 const TIME2000 = 946684800000;
 let counter = crypto.randomBytes(2).readUInt16LE(0);
@@ -10,16 +10,16 @@ function getTime(time: number) {
 	time = time - TIME2000;
 	if (time < 0) time = 0;
 
-	return time.toString(36).padStart(8, '0');
+	return time.toString(36).padStart(8, "0");
 }
 
 function getNoise() {
-	return counter.toString(36).padStart(2, '0').slice(-2);
+	return counter.toString(36).padStart(2, "0").slice(-2);
 }
 
 export function genAid(date: Date): string {
 	const t = date.getTime();
-	if (isNaN(t)) throw 'Failed to create AID: Invalid Date';
+	if (isNaN(t)) throw "Failed to create AID: Invalid Date";
 	counter++;
 	return getTime(t) + getNoise();
 }
diff --git a/packages/backend/src/misc/id/meid.ts b/packages/backend/src/misc/id/meid.ts
index 30bbdf169..ee78eb8d1 100644
--- a/packages/backend/src/misc/id/meid.ts
+++ b/packages/backend/src/misc/id/meid.ts
@@ -1,4 +1,4 @@
-const CHARS = '0123456789abcdef';
+const CHARS = "0123456789abcdef";
 
 function getTime(time: number) {
 	if (time < 0) time = 0;
@@ -12,7 +12,7 @@ function getTime(time: number) {
 }
 
 function getRandom() {
-	let str = '';
+	let str = "";
 
 	for (let i = 0; i < 12; i++) {
 		str += CHARS[Math.floor(Math.random() * CHARS.length)];
diff --git a/packages/backend/src/misc/id/meidg.ts b/packages/backend/src/misc/id/meidg.ts
index d4aaaea1b..4fd39a8b4 100644
--- a/packages/backend/src/misc/id/meidg.ts
+++ b/packages/backend/src/misc/id/meidg.ts
@@ -1,4 +1,4 @@
-const CHARS = '0123456789abcdef';
+const CHARS = "0123456789abcdef";
 
 //  4bit Fixed hex value 'g'
 // 44bit UNIX Time ms in Hex
@@ -14,7 +14,7 @@ function getTime(time: number) {
 }
 
 function getRandom() {
-	let str = '';
+	let str = "";
 
 	for (let i = 0; i < 12; i++) {
 		str += CHARS[Math.floor(Math.random() * CHARS.length)];
@@ -24,5 +24,5 @@ function getRandom() {
 }
 
 export function genMeidg(date: Date): string {
-	return 'g' + getTime(date.getTime()) + getRandom();
+	return `g${getTime(date.getTime())}${getRandom()}`;
 }
diff --git a/packages/backend/src/misc/id/object-id.ts b/packages/backend/src/misc/id/object-id.ts
index 392ea4330..45822f0ac 100644
--- a/packages/backend/src/misc/id/object-id.ts
+++ b/packages/backend/src/misc/id/object-id.ts
@@ -1,4 +1,4 @@
-const CHARS = '0123456789abcdef';
+const CHARS = "0123456789abcdef";
 
 function getTime(time: number) {
 	if (time < 0) time = 0;
@@ -12,7 +12,7 @@ function getTime(time: number) {
 }
 
 function getRandom() {
-	let str = '';
+	let str = "";
 
 	for (let i = 0; i < 16; i++) {
 		str += CHARS[Math.floor(Math.random() * CHARS.length)];
diff --git a/packages/backend/src/misc/identifiable-error.ts b/packages/backend/src/misc/identifiable-error.ts
index 2d7c6bd0c..be6eb5bd8 100644
--- a/packages/backend/src/misc/identifiable-error.ts
+++ b/packages/backend/src/misc/identifiable-error.ts
@@ -7,7 +7,7 @@ export class IdentifiableError extends Error {
 
 	constructor(id: string, message?: string) {
 		super(message);
-		this.message = message || '';
+		this.message = message || "";
 		this.id = id;
 	}
 }
diff --git a/packages/backend/src/misc/is-duplicate-key-value-error.ts b/packages/backend/src/misc/is-duplicate-key-value-error.ts
index 04ff191e4..18d22bb77 100644
--- a/packages/backend/src/misc/is-duplicate-key-value-error.ts
+++ b/packages/backend/src/misc/is-duplicate-key-value-error.ts
@@ -1,3 +1,3 @@
 export function isDuplicateKeyValueError(e: unknown | Error): boolean {
-	return (e as any).message && (e as Error).message.startsWith('duplicate key value');
+	return (e as Error).message?.startsWith("duplicate key value");
 }
diff --git a/packages/backend/src/misc/is-instance-muted.ts b/packages/backend/src/misc/is-instance-muted.ts
index a74ba524e..1547d4555 100644
--- a/packages/backend/src/misc/is-instance-muted.ts
+++ b/packages/backend/src/misc/is-instance-muted.ts
@@ -1,15 +1,21 @@
-import { Packed } from './schema.js';
+import type { Packed } from "./schema.js";
 
-export function isInstanceMuted(note: Packed<'Note'>, mutedInstances: Set): boolean {
-	if (mutedInstances.has(note?.user?.host ?? '')) return true;
-	if (mutedInstances.has(note?.reply?.user?.host ?? '')) return true;
-	if (mutedInstances.has(note?.renote?.user?.host ?? '')) return true;
+export function isInstanceMuted(
+	note: Packed<"Note">,
+	mutedInstances: Set,
+): boolean {
+	if (mutedInstances.has(note?.user?.host ?? "")) return true;
+	if (mutedInstances.has(note?.reply?.user?.host ?? "")) return true;
+	if (mutedInstances.has(note?.renote?.user?.host ?? "")) return true;
 
 	return false;
 }
 
-export function isUserFromMutedInstance(notif: Packed<'Notification'>, mutedInstances: Set): boolean {
-	if (mutedInstances.has(notif?.user?.host ?? '')) return true;
+export function isUserFromMutedInstance(
+	notif: Packed<"Notification">,
+	mutedInstances: Set,
+): boolean {
+	if (mutedInstances.has(notif?.user?.host ?? "")) return true;
 
 	return false;
 }
diff --git a/packages/backend/src/misc/is-mime-image.ts b/packages/backend/src/misc/is-mime-image.ts
index 9d6e28f15..a8ba62ec2 100644
--- a/packages/backend/src/misc/is-mime-image.ts
+++ b/packages/backend/src/misc/is-mime-image.ts
@@ -1,8 +1,20 @@
-import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
+import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
 
 const dictionary = {
-	'safe-file': FILE_TYPE_BROWSERSAFE,
-	'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/svg+xml', 'image/avif'],
+	"safe-file": FILE_TYPE_BROWSERSAFE,
+	"sharp-convertible-image": [
+		"image/jpeg",
+		"image/png",
+		"image/gif",
+		"image/apng",
+		"image/vnd.mozilla.apng",
+		"image/webp",
+		"image/svg+xml",
+		"image/avif",
+	],
 };
 
-export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);
+export const isMimeImage = (
+	mime: string,
+	type: keyof typeof dictionary,
+): boolean => dictionary[type].includes(mime);
diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts
index 779f548b0..fe83a56a5 100644
--- a/packages/backend/src/misc/is-quote.ts
+++ b/packages/backend/src/misc/is-quote.ts
@@ -1,5 +1,10 @@
-import { Note } from '@/models/entities/note.js';
+import type { Note } from "@/models/entities/note.js";
 
-export default function(note: Note): boolean {
-	return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0));
+export default function (note: Note): boolean {
+	return (
+		note.renoteId != null &&
+		(note.text != null ||
+			note.hasPoll ||
+			(note.fileIds != null && note.fileIds.length > 0))
+	);
 }
diff --git a/packages/backend/src/misc/is-user-related.ts b/packages/backend/src/misc/is-user-related.ts
index dc7bfbf0a..64591cfef 100644
--- a/packages/backend/src/misc/is-user-related.ts
+++ b/packages/backend/src/misc/is-user-related.ts
@@ -1,7 +1,7 @@
 export function isUserRelated(note: any, ids: Set): boolean {
 	if (ids.has(note.userId)) return true; // note author is muted
-	if (note.mentions && note.mentions.some((user: string) => ids.has(user))) return true; // any of mentioned users are muted
-	if (note.reply && isUserRelated(note.reply, ids))  return true; // also check reply target
+	if (note.mentions?.some((user: string) => ids.has(user))) return true; // any of mentioned users are muted
+	if (note.reply && isUserRelated(note.reply, ids)) return true; // also check reply target
 	if (note.renote && isUserRelated(note.renote, ids)) return true; // also check renote target
 	return false;
 }
diff --git a/packages/backend/src/misc/keypair-store.ts b/packages/backend/src/misc/keypair-store.ts
index 1183b9a78..4551bfd98 100644
--- a/packages/backend/src/misc/keypair-store.ts
+++ b/packages/backend/src/misc/keypair-store.ts
@@ -1,10 +1,12 @@
-import { UserKeypairs } from '@/models/index.js';
-import { User } from '@/models/entities/user.js';
-import { UserKeypair } from '@/models/entities/user-keypair.js';
-import { Cache } from './cache.js';
+import { UserKeypairs } from "@/models/index.js";
+import type { User } from "@/models/entities/user.js";
+import type { UserKeypair } from "@/models/entities/user-keypair.js";
+import { Cache } from "./cache.js";
 
 const cache = new Cache(Infinity);
 
-export async function getUserKeypair(userId: User['id']): Promise {
-	return await cache.fetch(userId, () => UserKeypairs.findOneByOrFail({ userId: userId }));
+export async function getUserKeypair(userId: User["id"]): Promise {
+	return await cache.fetch(userId, () =>
+		UserKeypairs.findOneByOrFail({ userId: userId }),
+	);
 }
diff --git a/packages/backend/src/misc/langmap.ts b/packages/backend/src/misc/langmap.ts
index 5ee85e6c0..106130d3c 100644
--- a/packages/backend/src/misc/langmap.ts
+++ b/packages/backend/src/misc/langmap.ts
@@ -1,666 +1,666 @@
 // TODO: sharedに置いてフロントエンドのと統合したい
 export const langmap = {
-	'ach': {
-		nativeName: 'Lwo',
+	ach: {
+		nativeName: "Lwo",
 	},
-	'ady': {
-		nativeName: 'Адыгэбзэ',
+	ady: {
+		nativeName: "Адыгэбзэ",
 	},
-	'af': {
-		nativeName: 'Afrikaans',
+	af: {
+		nativeName: "Afrikaans",
 	},
-	'af-NA': {
-		nativeName: 'Afrikaans (Namibia)',
+	"af-NA": {
+		nativeName: "Afrikaans (Namibia)",
 	},
-	'af-ZA': {
-		nativeName: 'Afrikaans (South Africa)',
+	"af-ZA": {
+		nativeName: "Afrikaans (South Africa)",
 	},
-	'ak': {
-		nativeName: 'Tɕɥi',
+	ak: {
+		nativeName: "Tɕɥi",
 	},
-	'ar': {
-		nativeName: 'العربية',
+	ar: {
+		nativeName: "العربية",
 	},
-	'ar-AR': {
-		nativeName: 'العربية',
+	"ar-AR": {
+		nativeName: "العربية",
 	},
-	'ar-MA': {
-		nativeName: 'العربية',
+	"ar-MA": {
+		nativeName: "العربية",
 	},
-	'ar-SA': {
-		nativeName: 'العربية (السعودية)',
+	"ar-SA": {
+		nativeName: "العربية (السعودية)",
 	},
-	'ay-BO': {
-		nativeName: 'Aymar aru',
+	"ay-BO": {
+		nativeName: "Aymar aru",
 	},
-	'az': {
-		nativeName: 'Azərbaycan dili',
+	az: {
+		nativeName: "Azərbaycan dili",
 	},
-	'az-AZ': {
-		nativeName: 'Azərbaycan dili',
+	"az-AZ": {
+		nativeName: "Azərbaycan dili",
 	},
-	'be-BY': {
-		nativeName: 'Беларуская',
+	"be-BY": {
+		nativeName: "Беларуская",
 	},
-	'bg': {
-		nativeName: 'Български',
+	bg: {
+		nativeName: "Български",
 	},
-	'bg-BG': {
-		nativeName: 'Български',
+	"bg-BG": {
+		nativeName: "Български",
 	},
-	'bn': {
-		nativeName: 'বাংলা',
+	bn: {
+		nativeName: "বাংলা",
 	},
-	'bn-IN': {
-		nativeName: 'বাংলা (ভারত)',
+	"bn-IN": {
+		nativeName: "বাংলা (ভারত)",
 	},
-	'bn-BD': {
-		nativeName: 'বাংলা(বাংলাদেশ)',
+	"bn-BD": {
+		nativeName: "বাংলা(বাংলাদেশ)",
 	},
-	'br': {
-		nativeName: 'Brezhoneg',
+	br: {
+		nativeName: "Brezhoneg",
 	},
-	'bs-BA': {
-		nativeName: 'Bosanski',
+	"bs-BA": {
+		nativeName: "Bosanski",
 	},
-	'ca': {
-		nativeName: 'Català',
+	ca: {
+		nativeName: "Català",
 	},
-	'ca-ES': {
-		nativeName: 'Català',
+	"ca-ES": {
+		nativeName: "Català",
 	},
-	'cak': {
-		nativeName: 'Maya Kaqchikel',
+	cak: {
+		nativeName: "Maya Kaqchikel",
 	},
-	'ck-US': {
-		nativeName: 'ᏣᎳᎩ (tsalagi)',
+	"ck-US": {
+		nativeName: "ᏣᎳᎩ (tsalagi)",
 	},
-	'cs': {
-		nativeName: 'Čeština',
+	cs: {
+		nativeName: "Čeština",
 	},
-	'cs-CZ': {
-		nativeName: 'Čeština',
+	"cs-CZ": {
+		nativeName: "Čeština",
 	},
-	'cy': {
-		nativeName: 'Cymraeg',
+	cy: {
+		nativeName: "Cymraeg",
 	},
-	'cy-GB': {
-		nativeName: 'Cymraeg',
+	"cy-GB": {
+		nativeName: "Cymraeg",
 	},
-	'da': {
-		nativeName: 'Dansk',
+	da: {
+		nativeName: "Dansk",
 	},
-	'da-DK': {
-		nativeName: 'Dansk',
+	"da-DK": {
+		nativeName: "Dansk",
 	},
-	'de': {
-		nativeName: 'Deutsch',
+	de: {
+		nativeName: "Deutsch",
 	},
-	'de-AT': {
-		nativeName: 'Deutsch (Österreich)',
+	"de-AT": {
+		nativeName: "Deutsch (Österreich)",
 	},
-	'de-DE': {
-		nativeName: 'Deutsch (Deutschland)',
+	"de-DE": {
+		nativeName: "Deutsch (Deutschland)",
 	},
-	'de-CH': {
-		nativeName: 'Deutsch (Schweiz)',
+	"de-CH": {
+		nativeName: "Deutsch (Schweiz)",
 	},
-	'dsb': {
-		nativeName: 'Dolnoserbšćina',
+	dsb: {
+		nativeName: "Dolnoserbšćina",
 	},
-	'el': {
-		nativeName: 'Ελληνικά',
+	el: {
+		nativeName: "Ελληνικά",
 	},
-	'el-GR': {
-		nativeName: 'Ελληνικά',
+	"el-GR": {
+		nativeName: "Ελληνικά",
 	},
-	'en': {
-		nativeName: 'English',
+	en: {
+		nativeName: "English",
 	},
-	'en-GB': {
-		nativeName: 'English (UK)',
+	"en-GB": {
+		nativeName: "English (UK)",
 	},
-	'en-AU': {
-		nativeName: 'English (Australia)',
+	"en-AU": {
+		nativeName: "English (Australia)",
 	},
-	'en-CA': {
-		nativeName: 'English (Canada)',
+	"en-CA": {
+		nativeName: "English (Canada)",
 	},
-	'en-IE': {
-		nativeName: 'English (Ireland)',
+	"en-IE": {
+		nativeName: "English (Ireland)",
 	},
-	'en-IN': {
-		nativeName: 'English (India)',
+	"en-IN": {
+		nativeName: "English (India)",
 	},
-	'en-PI': {
-		nativeName: 'English (Pirate)',
+	"en-PI": {
+		nativeName: "English (Pirate)",
 	},
-	'en-SG': {
-		nativeName: 'English (Singapore)',
+	"en-SG": {
+		nativeName: "English (Singapore)",
 	},
-	'en-UD': {
-		nativeName: 'English (Upside Down)',
+	"en-UD": {
+		nativeName: "English (Upside Down)",
 	},
-	'en-US': {
-		nativeName: 'English (US)',
+	"en-US": {
+		nativeName: "English (US)",
 	},
-	'en-ZA': {
-		nativeName: 'English (South Africa)',
+	"en-ZA": {
+		nativeName: "English (South Africa)",
 	},
-	'en@pirate': {
-		nativeName: 'English (Pirate)',
+	"en@pirate": {
+		nativeName: "English (Pirate)",
 	},
-	'eo': {
-		nativeName: 'Esperanto',
+	eo: {
+		nativeName: "Esperanto",
 	},
-	'eo-EO': {
-		nativeName: 'Esperanto',
+	"eo-EO": {
+		nativeName: "Esperanto",
 	},
-	'es': {
-		nativeName: 'Español',
+	es: {
+		nativeName: "Español",
 	},
-	'es-AR': {
-		nativeName: 'Español (Argentine)',
+	"es-AR": {
+		nativeName: "Español (Argentine)",
 	},
-	'es-419': {
-		nativeName: 'Español (Latinoamérica)',
+	"es-419": {
+		nativeName: "Español (Latinoamérica)",
 	},
-	'es-CL': {
-		nativeName: 'Español (Chile)',
+	"es-CL": {
+		nativeName: "Español (Chile)",
 	},
-	'es-CO': {
-		nativeName: 'Español (Colombia)',
+	"es-CO": {
+		nativeName: "Español (Colombia)",
 	},
-	'es-EC': {
-		nativeName: 'Español (Ecuador)',
+	"es-EC": {
+		nativeName: "Español (Ecuador)",
 	},
-	'es-ES': {
-		nativeName: 'Español (España)',
+	"es-ES": {
+		nativeName: "Español (España)",
 	},
-	'es-LA': {
-		nativeName: 'Español (Latinoamérica)',
+	"es-LA": {
+		nativeName: "Español (Latinoamérica)",
 	},
-	'es-NI': {
-		nativeName: 'Español (Nicaragua)',
+	"es-NI": {
+		nativeName: "Español (Nicaragua)",
 	},
-	'es-MX': {
-		nativeName: 'Español (México)',
+	"es-MX": {
+		nativeName: "Español (México)",
 	},
-	'es-US': {
-		nativeName: 'Español (Estados Unidos)',
+	"es-US": {
+		nativeName: "Español (Estados Unidos)",
 	},
-	'es-VE': {
-		nativeName: 'Español (Venezuela)',
+	"es-VE": {
+		nativeName: "Español (Venezuela)",
 	},
-	'et': {
-		nativeName: 'eesti keel',
+	et: {
+		nativeName: "eesti keel",
 	},
-	'et-EE': {
-		nativeName: 'Eesti (Estonia)',
+	"et-EE": {
+		nativeName: "Eesti (Estonia)",
 	},
-	'eu': {
-		nativeName: 'Euskara',
+	eu: {
+		nativeName: "Euskara",
 	},
-	'eu-ES': {
-		nativeName: 'Euskara',
+	"eu-ES": {
+		nativeName: "Euskara",
 	},
-	'fa': {
-		nativeName: 'فارسی',
+	fa: {
+		nativeName: "فارسی",
 	},
-	'fa-IR': {
-		nativeName: 'فارسی',
+	"fa-IR": {
+		nativeName: "فارسی",
 	},
-	'fb-LT': {
-		nativeName: 'Leet Speak',
+	"fb-LT": {
+		nativeName: "Leet Speak",
 	},
-	'ff': {
-		nativeName: 'Fulah',
+	ff: {
+		nativeName: "Fulah",
 	},
-	'fi': {
-		nativeName: 'Suomi',
+	fi: {
+		nativeName: "Suomi",
 	},
-	'fi-FI': {
-		nativeName: 'Suomi',
+	"fi-FI": {
+		nativeName: "Suomi",
 	},
-	'fo': {
-		nativeName: 'Føroyskt',
+	fo: {
+		nativeName: "Føroyskt",
 	},
-	'fo-FO': {
-		nativeName: 'Føroyskt (Færeyjar)',
+	"fo-FO": {
+		nativeName: "Føroyskt (Færeyjar)",
 	},
-	'fr': {
-		nativeName: 'Français',
+	fr: {
+		nativeName: "Français",
 	},
-	'fr-CA': {
-		nativeName: 'Français (Canada)',
+	"fr-CA": {
+		nativeName: "Français (Canada)",
 	},
-	'fr-FR': {
-		nativeName: 'Français (France)',
+	"fr-FR": {
+		nativeName: "Français (France)",
 	},
-	'fr-BE': {
-		nativeName: 'Français (Belgique)',
+	"fr-BE": {
+		nativeName: "Français (Belgique)",
 	},
-	'fr-CH': {
-		nativeName: 'Français (Suisse)',
+	"fr-CH": {
+		nativeName: "Français (Suisse)",
 	},
-	'fy-NL': {
-		nativeName: 'Frysk',
+	"fy-NL": {
+		nativeName: "Frysk",
 	},
-	'ga': {
-		nativeName: 'Gaeilge',
+	ga: {
+		nativeName: "Gaeilge",
 	},
-	'ga-IE': {
-		nativeName: 'Gaeilge',
+	"ga-IE": {
+		nativeName: "Gaeilge",
 	},
-	'gd': {
-		nativeName: 'Gàidhlig',
+	gd: {
+		nativeName: "Gàidhlig",
 	},
-	'gl': {
-		nativeName: 'Galego',
+	gl: {
+		nativeName: "Galego",
 	},
-	'gl-ES': {
-		nativeName: 'Galego',
+	"gl-ES": {
+		nativeName: "Galego",
 	},
-	'gn-PY': {
-		nativeName: 'Avañe\'ẽ',
+	"gn-PY": {
+		nativeName: "Avañe'ẽ",
 	},
-	'gu-IN': {
-		nativeName: 'ગુજરાતી',
+	"gu-IN": {
+		nativeName: "ગુજરાતી",
 	},
-	'gv': {
-		nativeName: 'Gaelg',
+	gv: {
+		nativeName: "Gaelg",
 	},
-	'gx-GR': {
-		nativeName: 'Ἑλληνική ἀρχαία',
+	"gx-GR": {
+		nativeName: "Ἑλληνική ἀρχαία",
 	},
-	'he': {
-		nativeName: 'עברית‏',
+	he: {
+		nativeName: "עברית‏",
 	},
-	'he-IL': {
-		nativeName: 'עברית‏',
+	"he-IL": {
+		nativeName: "עברית‏",
 	},
-	'hi': {
-		nativeName: 'हिन्दी',
+	hi: {
+		nativeName: "हिन्दी",
 	},
-	'hi-IN': {
-		nativeName: 'हिन्दी',
+	"hi-IN": {
+		nativeName: "हिन्दी",
 	},
-	'hr': {
-		nativeName: 'Hrvatski',
+	hr: {
+		nativeName: "Hrvatski",
 	},
-	'hr-HR': {
-		nativeName: 'Hrvatski',
+	"hr-HR": {
+		nativeName: "Hrvatski",
 	},
-	'hsb': {
-		nativeName: 'Hornjoserbšćina',
+	hsb: {
+		nativeName: "Hornjoserbšćina",
 	},
-	'ht': {
-		nativeName: 'Kreyòl',
+	ht: {
+		nativeName: "Kreyòl",
 	},
-	'hu': {
-		nativeName: 'Magyar',
+	hu: {
+		nativeName: "Magyar",
 	},
-	'hu-HU': {
-		nativeName: 'Magyar',
+	"hu-HU": {
+		nativeName: "Magyar",
 	},
-	'hy': {
-		nativeName: 'Հայերեն',
+	hy: {
+		nativeName: "Հայերեն",
 	},
-	'hy-AM': {
-		nativeName: 'Հայերեն (Հայաստան)',
+	"hy-AM": {
+		nativeName: "Հայերեն (Հայաստան)",
 	},
-	'id': {
-		nativeName: 'Bahasa Indonesia',
+	id: {
+		nativeName: "Bahasa Indonesia",
 	},
-	'id-ID': {
-		nativeName: 'Bahasa Indonesia',
+	"id-ID": {
+		nativeName: "Bahasa Indonesia",
 	},
-	'is': {
-		nativeName: 'Íslenska',
+	is: {
+		nativeName: "Íslenska",
 	},
-	'is-IS': {
-		nativeName: 'Íslenska (Iceland)',
+	"is-IS": {
+		nativeName: "Íslenska (Iceland)",
 	},
-	'it': {
-		nativeName: 'Italiano',
+	it: {
+		nativeName: "Italiano",
 	},
-	'it-IT': {
-		nativeName: 'Italiano',
+	"it-IT": {
+		nativeName: "Italiano",
 	},
-	'ja': {
-		nativeName: '日本語',
+	ja: {
+		nativeName: "日本語",
 	},
-	'ja-JP': {
-		nativeName: '日本語 (日本)',
+	"ja-JP": {
+		nativeName: "日本語 (日本)",
 	},
-	'jv-ID': {
-		nativeName: 'Basa Jawa',
+	"jv-ID": {
+		nativeName: "Basa Jawa",
 	},
-	'ka-GE': {
-		nativeName: 'ქართული',
+	"ka-GE": {
+		nativeName: "ქართული",
 	},
-	'kk-KZ': {
-		nativeName: 'Қазақша',
+	"kk-KZ": {
+		nativeName: "Қазақша",
 	},
-	'km': {
-		nativeName: 'ភាសាខ្មែរ',
+	km: {
+		nativeName: "ភាសាខ្មែរ",
 	},
-	'kl': {
-		nativeName: 'kalaallisut',
+	kl: {
+		nativeName: "kalaallisut",
 	},
-	'km-KH': {
-		nativeName: 'ភាសាខ្មែរ',
+	"km-KH": {
+		nativeName: "ភាសាខ្មែរ",
 	},
-	'kab': {
-		nativeName: 'Taqbaylit',
+	kab: {
+		nativeName: "Taqbaylit",
 	},
-	'kn': {
-		nativeName: 'ಕನ್ನಡ',
+	kn: {
+		nativeName: "ಕನ್ನಡ",
 	},
-	'kn-IN': {
-		nativeName: 'ಕನ್ನಡ (India)',
+	"kn-IN": {
+		nativeName: "ಕನ್ನಡ (India)",
 	},
-	'ko': {
-		nativeName: '한국어',
+	ko: {
+		nativeName: "한국어",
 	},
-	'ko-KR': {
-		nativeName: '한국어 (한국)',
+	"ko-KR": {
+		nativeName: "한국어 (한국)",
 	},
-	'ku-TR': {
-		nativeName: 'Kurdî',
+	"ku-TR": {
+		nativeName: "Kurdî",
 	},
-	'kw': {
-		nativeName: 'Kernewek',
+	kw: {
+		nativeName: "Kernewek",
 	},
-	'la': {
-		nativeName: 'Latin',
+	la: {
+		nativeName: "Latin",
 	},
-	'la-VA': {
-		nativeName: 'Latin',
+	"la-VA": {
+		nativeName: "Latin",
 	},
-	'lb': {
-		nativeName: 'Lëtzebuergesch',
+	lb: {
+		nativeName: "Lëtzebuergesch",
 	},
-	'li-NL': {
-		nativeName: 'Lèmbörgs',
+	"li-NL": {
+		nativeName: "Lèmbörgs",
 	},
-	'lt': {
-		nativeName: 'Lietuvių',
+	lt: {
+		nativeName: "Lietuvių",
 	},
-	'lt-LT': {
-		nativeName: 'Lietuvių',
+	"lt-LT": {
+		nativeName: "Lietuvių",
 	},
-	'lv': {
-		nativeName: 'Latviešu',
+	lv: {
+		nativeName: "Latviešu",
 	},
-	'lv-LV': {
-		nativeName: 'Latviešu',
+	"lv-LV": {
+		nativeName: "Latviešu",
 	},
-	'mai': {
-		nativeName: 'मैथिली, মৈথিলী',
+	mai: {
+		nativeName: "मैथिली, মৈথিলী",
 	},
-	'mg-MG': {
-		nativeName: 'Malagasy',
+	"mg-MG": {
+		nativeName: "Malagasy",
 	},
-	'mk': {
-		nativeName: 'Македонски',
+	mk: {
+		nativeName: "Македонски",
 	},
-	'mk-MK': {
-		nativeName: 'Македонски (Македонски)',
+	"mk-MK": {
+		nativeName: "Македонски (Македонски)",
 	},
-	'ml': {
-		nativeName: 'മലയാളം',
+	ml: {
+		nativeName: "മലയാളം",
 	},
-	'ml-IN': {
-		nativeName: 'മലയാളം',
+	"ml-IN": {
+		nativeName: "മലയാളം",
 	},
-	'mn-MN': {
-		nativeName: 'Монгол',
+	"mn-MN": {
+		nativeName: "Монгол",
 	},
-	'mr': {
-		nativeName: 'मराठी',
+	mr: {
+		nativeName: "मराठी",
 	},
-	'mr-IN': {
-		nativeName: 'मराठी',
+	"mr-IN": {
+		nativeName: "मराठी",
 	},
-	'ms': {
-		nativeName: 'Bahasa Melayu',
+	ms: {
+		nativeName: "Bahasa Melayu",
 	},
-	'ms-MY': {
-		nativeName: 'Bahasa Melayu',
+	"ms-MY": {
+		nativeName: "Bahasa Melayu",
 	},
-	'mt': {
-		nativeName: 'Malti',
+	mt: {
+		nativeName: "Malti",
 	},
-	'mt-MT': {
-		nativeName: 'Malti',
+	"mt-MT": {
+		nativeName: "Malti",
 	},
-	'my': {
-		nativeName: 'ဗမာစကာ',
+	my: {
+		nativeName: "ဗမာစကာ",
 	},
-	'no': {
-		nativeName: 'Norsk',
+	no: {
+		nativeName: "Norsk",
 	},
-	'nb': {
-		nativeName: 'Norsk (bokmål)',
+	nb: {
+		nativeName: "Norsk (bokmål)",
 	},
-	'nb-NO': {
-		nativeName: 'Norsk (bokmål)',
+	"nb-NO": {
+		nativeName: "Norsk (bokmål)",
 	},
-	'ne': {
-		nativeName: 'नेपाली',
+	ne: {
+		nativeName: "नेपाली",
 	},
-	'ne-NP': {
-		nativeName: 'नेपाली',
+	"ne-NP": {
+		nativeName: "नेपाली",
 	},
-	'nl': {
-		nativeName: 'Nederlands',
+	nl: {
+		nativeName: "Nederlands",
 	},
-	'nl-BE': {
-		nativeName: 'Nederlands (België)',
+	"nl-BE": {
+		nativeName: "Nederlands (België)",
 	},
-	'nl-NL': {
-		nativeName: 'Nederlands (Nederland)',
+	"nl-NL": {
+		nativeName: "Nederlands (Nederland)",
 	},
-	'nn-NO': {
-		nativeName: 'Norsk (nynorsk)',
+	"nn-NO": {
+		nativeName: "Norsk (nynorsk)",
 	},
-	'oc': {
-		nativeName: 'Occitan',
+	oc: {
+		nativeName: "Occitan",
 	},
-	'or-IN': {
-		nativeName: 'ଓଡ଼ିଆ',
+	"or-IN": {
+		nativeName: "ଓଡ଼ିଆ",
 	},
-	'pa': {
-		nativeName: 'ਪੰਜਾਬੀ',
+	pa: {
+		nativeName: "ਪੰਜਾਬੀ",
 	},
-	'pa-IN': {
-		nativeName: 'ਪੰਜਾਬੀ (ਭਾਰਤ ਨੂੰ)',
+	"pa-IN": {
+		nativeName: "ਪੰਜਾਬੀ (ਭਾਰਤ ਨੂੰ)",
 	},
-	'pl': {
-		nativeName: 'Polski',
+	pl: {
+		nativeName: "Polski",
 	},
-	'pl-PL': {
-		nativeName: 'Polski',
+	"pl-PL": {
+		nativeName: "Polski",
 	},
-	'ps-AF': {
-		nativeName: 'پښتو',
+	"ps-AF": {
+		nativeName: "پښتو",
 	},
-	'pt': {
-		nativeName: 'Português',
+	pt: {
+		nativeName: "Português",
 	},
-	'pt-BR': {
-		nativeName: 'Português (Brasil)',
+	"pt-BR": {
+		nativeName: "Português (Brasil)",
 	},
-	'pt-PT': {
-		nativeName: 'Português (Portugal)',
+	"pt-PT": {
+		nativeName: "Português (Portugal)",
 	},
-	'qu-PE': {
-		nativeName: 'Qhichwa',
+	"qu-PE": {
+		nativeName: "Qhichwa",
 	},
-	'rm-CH': {
-		nativeName: 'Rumantsch',
+	"rm-CH": {
+		nativeName: "Rumantsch",
 	},
-	'ro': {
-		nativeName: 'Română',
+	ro: {
+		nativeName: "Română",
 	},
-	'ro-RO': {
-		nativeName: 'Română',
+	"ro-RO": {
+		nativeName: "Română",
 	},
-	'ru': {
-		nativeName: 'Русский',
+	ru: {
+		nativeName: "Русский",
 	},
-	'ru-RU': {
-		nativeName: 'Русский',
+	"ru-RU": {
+		nativeName: "Русский",
 	},
-	'sa-IN': {
-		nativeName: 'संस्कृतम्',
+	"sa-IN": {
+		nativeName: "संस्कृतम्",
 	},
-	'se-NO': {
-		nativeName: 'Davvisámegiella',
+	"se-NO": {
+		nativeName: "Davvisámegiella",
 	},
-	'sh': {
-		nativeName: 'српскохрватски',
+	sh: {
+		nativeName: "српскохрватски",
 	},
-	'si-LK': {
-		nativeName: 'සිංහල',
+	"si-LK": {
+		nativeName: "සිංහල",
 	},
-	'sk': {
-		nativeName: 'Slovenčina',
+	sk: {
+		nativeName: "Slovenčina",
 	},
-	'sk-SK': {
-		nativeName: 'Slovenčina (Slovakia)',
+	"sk-SK": {
+		nativeName: "Slovenčina (Slovakia)",
 	},
-	'sl': {
-		nativeName: 'Slovenščina',
+	sl: {
+		nativeName: "Slovenščina",
 	},
-	'sl-SI': {
-		nativeName: 'Slovenščina',
+	"sl-SI": {
+		nativeName: "Slovenščina",
 	},
-	'so-SO': {
-		nativeName: 'Soomaaliga',
+	"so-SO": {
+		nativeName: "Soomaaliga",
 	},
-	'sq': {
-		nativeName: 'Shqip',
+	sq: {
+		nativeName: "Shqip",
 	},
-	'sq-AL': {
-		nativeName: 'Shqip',
+	"sq-AL": {
+		nativeName: "Shqip",
 	},
-	'sr': {
-		nativeName: 'Српски',
+	sr: {
+		nativeName: "Српски",
 	},
-	'sr-RS': {
-		nativeName: 'Српски (Serbia)',
+	"sr-RS": {
+		nativeName: "Српски (Serbia)",
 	},
-	'su': {
-		nativeName: 'Basa Sunda',
+	su: {
+		nativeName: "Basa Sunda",
 	},
-	'sv': {
-		nativeName: 'Svenska',
+	sv: {
+		nativeName: "Svenska",
 	},
-	'sv-SE': {
-		nativeName: 'Svenska',
+	"sv-SE": {
+		nativeName: "Svenska",
 	},
-	'sw': {
-		nativeName: 'Kiswahili',
+	sw: {
+		nativeName: "Kiswahili",
 	},
-	'sw-KE': {
-		nativeName: 'Kiswahili',
+	"sw-KE": {
+		nativeName: "Kiswahili",
 	},
-	'ta': {
-		nativeName: 'தமிழ்',
+	ta: {
+		nativeName: "தமிழ்",
 	},
-	'ta-IN': {
-		nativeName: 'தமிழ்',
+	"ta-IN": {
+		nativeName: "தமிழ்",
 	},
-	'te': {
-		nativeName: 'తెలుగు',
+	te: {
+		nativeName: "తెలుగు",
 	},
-	'te-IN': {
-		nativeName: 'తెలుగు',
+	"te-IN": {
+		nativeName: "తెలుగు",
 	},
-	'tg': {
-		nativeName: 'забо́ни тоҷикӣ́',
+	tg: {
+		nativeName: "забо́ни тоҷикӣ́",
 	},
-	'tg-TJ': {
-		nativeName: 'тоҷикӣ',
+	"tg-TJ": {
+		nativeName: "тоҷикӣ",
 	},
-	'th': {
-		nativeName: 'ภาษาไทย',
+	th: {
+		nativeName: "ภาษาไทย",
 	},
-	'th-TH': {
-		nativeName: 'ภาษาไทย (ประเทศไทย)',
+	"th-TH": {
+		nativeName: "ภาษาไทย (ประเทศไทย)",
 	},
-	'fil': {
-		nativeName: 'Filipino',
+	fil: {
+		nativeName: "Filipino",
 	},
-	'tlh': {
-		nativeName: 'tlhIngan-Hol',
+	tlh: {
+		nativeName: "tlhIngan-Hol",
 	},
-	'tr': {
-		nativeName: 'Türkçe',
+	tr: {
+		nativeName: "Türkçe",
 	},
-	'tr-TR': {
-		nativeName: 'Türkçe',
+	"tr-TR": {
+		nativeName: "Türkçe",
 	},
-	'tt-RU': {
-		nativeName: 'татарча',
+	"tt-RU": {
+		nativeName: "татарча",
 	},
-	'uk': {
-		nativeName: 'Українська',
+	uk: {
+		nativeName: "Українська",
 	},
-	'uk-UA': {
-		nativeName: 'Українська',
+	"uk-UA": {
+		nativeName: "Українська",
 	},
-	'ur': {
-		nativeName: 'اردو',
+	ur: {
+		nativeName: "اردو",
 	},
-	'ur-PK': {
-		nativeName: 'اردو',
+	"ur-PK": {
+		nativeName: "اردو",
 	},
-	'uz': {
-		nativeName: 'O\'zbek',
+	uz: {
+		nativeName: "O'zbek",
 	},
-	'uz-UZ': {
-		nativeName: 'O\'zbek',
+	"uz-UZ": {
+		nativeName: "O'zbek",
 	},
-	'vi': {
-		nativeName: 'Tiếng Việt',
+	vi: {
+		nativeName: "Tiếng Việt",
 	},
-	'vi-VN': {
-		nativeName: 'Tiếng Việt',
+	"vi-VN": {
+		nativeName: "Tiếng Việt",
 	},
-	'xh-ZA': {
-		nativeName: 'isiXhosa',
+	"xh-ZA": {
+		nativeName: "isiXhosa",
 	},
-	'yi': {
-		nativeName: 'ייִדיש',
+	yi: {
+		nativeName: "ייִדיש",
 	},
-	'yi-DE': {
-		nativeName: 'ייִדיש (German)',
+	"yi-DE": {
+		nativeName: "ייִדיש (German)",
 	},
-	'zh': {
-		nativeName: '中文',
+	zh: {
+		nativeName: "中文",
 	},
-	'zh-Hans': {
-		nativeName: '中文简体',
+	"zh-Hans": {
+		nativeName: "中文简体",
 	},
-	'zh-Hant': {
-		nativeName: '中文繁體',
+	"zh-Hant": {
+		nativeName: "中文繁體",
 	},
-	'zh-CN': {
-		nativeName: '中文(中国大陆)',
+	"zh-CN": {
+		nativeName: "中文(中国大陆)",
 	},
-	'zh-HK': {
-		nativeName: '中文(香港)',
+	"zh-HK": {
+		nativeName: "中文(香港)",
 	},
-	'zh-SG': {
-		nativeName: '中文(新加坡)',
+	"zh-SG": {
+		nativeName: "中文(新加坡)",
 	},
-	'zh-TW': {
-		nativeName: '中文(台灣)',
+	"zh-TW": {
+		nativeName: "中文(台灣)",
 	},
-	'zu-ZA': {
-		nativeName: 'isiZulu',
+	"zu-ZA": {
+		nativeName: "isiZulu",
 	},
 };
diff --git a/packages/backend/src/misc/normalize-for-search.ts b/packages/backend/src/misc/normalize-for-search.ts
index 200540566..6882a1243 100644
--- a/packages/backend/src/misc/normalize-for-search.ts
+++ b/packages/backend/src/misc/normalize-for-search.ts
@@ -2,5 +2,5 @@ export function normalizeForSearch(tag: string): string {
 	// ref.
 	// - https://analytics-note.xyz/programming/unicode-normalization-forms/
 	// - https://maku77.github.io/js/string/normalize.html
-	return tag.normalize('NFKC').toLowerCase();
+	return tag.normalize("NFKC").toLowerCase();
 }
diff --git a/packages/backend/src/misc/nyaize.ts b/packages/backend/src/misc/nyaize.ts
index 500d1db2c..7ec26c1eb 100644
--- a/packages/backend/src/misc/nyaize.ts
+++ b/packages/backend/src/misc/nyaize.ts
@@ -1,15 +1,21 @@
 export function nyaize(text: string): string {
-	return text
-		// ja-JP
-		.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ')
-		// en-US
-		.replace(/(?<=n)a/gi, x => x === 'A' ? 'YA' : 'ya')
-		.replace(/(?<=morn)ing/gi, x => x === 'ING' ? 'YAN' : 'yan')
-		.replace(/(?<=every)one/gi, x => x === 'ONE' ? 'NYAN' : 'nyan')
-		// ko-KR
-		.replace(/[나-낳]/g, match => String.fromCharCode(
-			match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0)
-		))
-		.replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, '다냥')
-		.replace(/(야(?=\?))|(야$)|(야(?= ))/gm, '냥');
+	return (
+		text
+			// ja-JP
+			.replace(/な/g, "にゃ")
+			.replace(/ナ/g, "ニャ")
+			.replace(/ナ/g, "ニャ")
+			// en-US
+			.replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya"))
+			.replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan"))
+			.replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan"))
+			// ko-KR
+			.replace(/[나-낳]/g, (match) =>
+				String.fromCharCode(
+					match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0),
+				),
+			)
+			.replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥")
+			.replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥")
+	);
 }
diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts
index 6a185d09f..3f20f9f10 100644
--- a/packages/backend/src/misc/populate-emojis.ts
+++ b/packages/backend/src/misc/populate-emojis.ts
@@ -1,12 +1,12 @@
-import { In, IsNull } from 'typeorm';
-import { Emojis } from '@/models/index.js';
-import { Emoji } from '@/models/entities/emoji.js';
-import { Note } from '@/models/entities/note.js';
-import { Cache } from './cache.js';
-import { isSelfHost, toPunyNullable } from './convert-host.js';
-import { decodeReaction } from './reaction-lib.js';
-import config from '@/config/index.js';
-import { query } from '@/prelude/url.js';
+import { In, IsNull } from "typeorm";
+import { Emojis } from "@/models/index.js";
+import type { Emoji } from "@/models/entities/emoji.js";
+import type { Note } from "@/models/entities/note.js";
+import { Cache } from "./cache.js";
+import { isSelfHost, toPunyNullable } from "./convert-host.js";
+import { decodeReaction } from "./reaction-lib.js";
+import config from "@/config/index.js";
+import { query } from "@/prelude/url.js";
 
 const cache = new Cache(1000 * 60 * 60 * 12);
 
@@ -18,12 +18,19 @@ type PopulatedEmoji = {
 	url: string;
 };
 
-function normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
+function normalizeHost(
+	src: string | undefined,
+	noteUserHost: string | null,
+): string | null {
 	// クエリに使うホスト
-	let host = src === '.' ? null	// .はローカルホスト (ここがマッチするのはリアクションのみ)
-		: src === undefined ? noteUserHost	// ノートなどでホスト省略表記の場合はローカルホスト (ここがリアクションにマッチすることはない)
-		: isSelfHost(src) ? null	// 自ホスト指定
-		: (src || noteUserHost);	// 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない)
+	let host =
+		src === "."
+			? null // .はローカルホスト (ここがマッチするのはリアクションのみ)
+			: src === undefined
+			? noteUserHost // ノートなどでホスト省略表記の場合はローカルホスト (ここがリアクションにマッチすることはない)
+			: isSelfHost(src)
+			? null // 自ホスト指定
+			: src || noteUserHost; // 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない)
 
 	host = toPunyNullable(host);
 
@@ -48,14 +55,18 @@ function parseEmojiStr(emojiName: string, noteUserHost: string | null) {
  * @param noteUserHost ノートやユーザープロフィールの所有者のホスト
  * @returns 絵文字情報, nullは未マッチを意味する
  */
-export async function populateEmoji(emojiName: string, noteUserHost: string | null): Promise {
+export async function populateEmoji(
+	emojiName: string,
+	noteUserHost: string | null,
+): Promise {
 	const { name, host } = parseEmojiStr(emojiName, noteUserHost);
 	if (name == null) return null;
 
-	const queryOrNull = async () => (await Emojis.findOneBy({
-		name,
-		host: host ?? IsNull(),
-	})) || null;
+	const queryOrNull = async () =>
+		(await Emojis.findOneBy({
+			name,
+			host: host ?? IsNull(),
+		})) || null;
 
 	const emoji = await cache.fetch(`${name} ${host}`, queryOrNull);
 
@@ -63,7 +74,11 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu
 
 	const isLocal = emoji.host == null;
 	const emojiUrl = emoji.publicUrl || emoji.originalUrl; // || emoji.originalUrl してるのは後方互換性のため
-	const url = isLocal ? emojiUrl : `${config.url}/proxy/${encodeURIComponent((new URL(emojiUrl)).pathname)}?${query({ url: emojiUrl })}`;
+	const url = isLocal
+		? emojiUrl
+		: `${config.url}/proxy/${encodeURIComponent(
+				new URL(emojiUrl).pathname,
+		  )}?${query({ url: emojiUrl })}`;
 
 	return {
 		name: emojiName,
@@ -74,51 +89,76 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu
 /**
  * 複数の添付用絵文字情報を解決する (キャシュ付き, 存在しないものは結果から除外される)
  */
-export async function populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise {
-	const emojis = await Promise.all(emojiNames.map(x => populateEmoji(x, noteUserHost)));
+export async function populateEmojis(
+	emojiNames: string[],
+	noteUserHost: string | null,
+): Promise {
+	const emojis = await Promise.all(
+		emojiNames.map((x) => populateEmoji(x, noteUserHost)),
+	);
 	return emojis.filter((x): x is PopulatedEmoji => x != null);
 }
 
 export function aggregateNoteEmojis(notes: Note[]) {
-	let emojis: { name: string | null; host: string | null; }[] = [];
+	let emojis: { name: string | null; host: string | null }[] = [];
 	for (const note of notes) {
-		emojis = emojis.concat(note.emojis
-			.map(e => parseEmojiStr(e, note.userHost)));
+		emojis = emojis.concat(
+			note.emojis.map((e) => parseEmojiStr(e, note.userHost)),
+		);
 		if (note.renote) {
-			emojis = emojis.concat(note.renote.emojis
-				.map(e => parseEmojiStr(e, note.renote!.userHost)));
+			emojis = emojis.concat(
+				note.renote.emojis.map((e) => parseEmojiStr(e, note.renote!.userHost)),
+			);
 			if (note.renote.user) {
-				emojis = emojis.concat(note.renote.user.emojis
-					.map(e => parseEmojiStr(e, note.renote!.userHost)));
+				emojis = emojis.concat(
+					note.renote.user.emojis.map((e) =>
+						parseEmojiStr(e, note.renote!.userHost),
+					),
+				);
 			}
 		}
-		const customReactions = Object.keys(note.reactions).map(x => decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
+		const customReactions = Object.keys(note.reactions)
+			.map((x) => decodeReaction(x))
+			.filter((x) => x.name != null) as typeof emojis;
 		emojis = emojis.concat(customReactions);
 		if (note.user) {
-			emojis = emojis.concat(note.user.emojis
-				.map(e => parseEmojiStr(e, note.userHost)));
+			emojis = emojis.concat(
+				note.user.emojis.map((e) => parseEmojiStr(e, note.userHost)),
+			);
 		}
 	}
-	return emojis.filter(x => x.name != null) as { name: string; host: string | null; }[];
+	return emojis.filter((x) => x.name != null) as {
+		name: string;
+		host: string | null;
+	}[];
 }
 
 /**
  * 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
  */
-export async function prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise {
-	const notCachedEmojis = emojis.filter(emoji => cache.get(`${emoji.name} ${emoji.host}`) == null);
+export async function prefetchEmojis(
+	emojis: { name: string; host: string | null }[],
+): Promise {
+	const notCachedEmojis = emojis.filter(
+		(emoji) => cache.get(`${emoji.name} ${emoji.host}`) == null,
+	);
 	const emojisQuery: any[] = [];
-	const hosts = new Set(notCachedEmojis.map(e => e.host));
+	const hosts = new Set(notCachedEmojis.map((e) => e.host));
 	for (const host of hosts) {
 		emojisQuery.push({
-			name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)),
+			name: In(
+				notCachedEmojis.filter((e) => e.host === host).map((e) => e.name),
+			),
 			host: host ?? IsNull(),
 		});
 	}
-	const _emojis = emojisQuery.length > 0 ? await Emojis.find({
-		where: emojisQuery,
-		select: ['name', 'host', 'originalUrl', 'publicUrl'],
-	}) : [];
+	const _emojis =
+		emojisQuery.length > 0
+			? await Emojis.find({
+					where: emojisQuery,
+					select: ["name", "host", "originalUrl", "publicUrl"],
+			  })
+			: [];
 	for (const emoji of _emojis) {
 		cache.set(`${emoji.name} ${emoji.host}`, emoji);
 	}
diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts
index fefc2781f..c0a5e8e2f 100644
--- a/packages/backend/src/misc/reaction-lib.ts
+++ b/packages/backend/src/misc/reaction-lib.ts
@@ -1,27 +1,26 @@
-/* eslint-disable key-spacing */
-import { emojiRegex } from './emoji-regex.js';
-import { fetchMeta } from './fetch-meta.js';
-import { Emojis } from '@/models/index.js';
-import { toPunyNullable } from './convert-host.js';
-import { IsNull } from 'typeorm';
+import { emojiRegex } from "./emoji-regex.js";
+import { fetchMeta } from "./fetch-meta.js";
+import { Emojis } from "@/models/index.js";
+import { toPunyNullable } from "./convert-host.js";
+import { IsNull } from "typeorm";
 
 const legacies: Record = {
-	'like':     '👍',
-	'love':     '❤', // ここに記述する場合は異体字セレクタを入れない
-	'laugh':    '😆',
-	'hmm':      '🤔',
-	'surprise': '😮',
-	'congrats': '🎉',
-	'angry':    '💢',
-	'confused': '😥',
-	'rip':      '😇',
-	'pudding':  '🍮',
-	'star':     '⭐',
+	like: "👍",
+	love: "❤️", // ここに記述する場合は異体字セレクタを入れない <- not that good because modern browsers just display it as the red heart so just convert it to it to not end up with two seperate reactions of "the same emoji" for the user
+	laugh: "😆",
+	hmm: "🤔",
+	surprise: "😮",
+	congrats: "🎉",
+	angry: "💢",
+	confused: "😥",
+	rip: "😇",
+	pudding: "🍮",
+	star: "⭐",
 };
 
 export async function getFallbackReaction(): Promise {
 	const meta = await fetchMeta();
-	return meta.useStarForReactionFallback ? '⭐' : '👍';
+	return meta.defaultReaction;
 }
 
 export function convertLegacyReactions(reactions: Record) {
@@ -54,7 +53,10 @@ export function convertLegacyReactions(reactions: Record) {
 	return _reactions2;
 }
 
-export async function toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise {
+export async function toDbReaction(
+	reaction?: string | null,
+	reacterHost?: string | null,
+): Promise {
 	if (reaction == null) return await getFallbackReaction();
 
 	reacterHost = toPunyNullable(reacterHost);
@@ -65,11 +67,8 @@ export async function toDbReaction(reaction?: string | null, reacterHost?: strin
 	// Unicode絵文字
 	const match = emojiRegex.exec(reaction);
 	if (match) {
-		// 合字を含む1つの絵文字
 		const unicode = match[0];
-
-		// 異体字セレクタ除去
-		return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, '');
+		return unicode.match("\u200d") ? unicode : unicode.replace(/\ufe0f/g, "");
 	}
 
 	const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
@@ -111,7 +110,7 @@ export function decodeReaction(str: string): DecodedReaction {
 		const host = custom[2] || null;
 
 		return {
-			reaction: `:${name}@${host || '.'}:`,	// ローカル分は@以降を省略するのではなく.にする
+			reaction: `:${name}@${host || "."}:`, // ローカル分は@以降を省略するのではなく.にする
 			name,
 			host,
 		};
diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts
index fdecc278d..35637e6ed 100644
--- a/packages/backend/src/misc/schema.ts
+++ b/packages/backend/src/misc/schema.ts
@@ -6,29 +6,29 @@ import {
 	packedMeDetailedSchema,
 	packedUserDetailedSchema,
 	packedUserSchema,
-} from '@/models/schema/user.js';
-import { packedNoteSchema } from '@/models/schema/note.js';
-import { packedUserListSchema } from '@/models/schema/user-list.js';
-import { packedAppSchema } from '@/models/schema/app.js';
-import { packedMessagingMessageSchema } from '@/models/schema/messaging-message.js';
-import { packedNotificationSchema } from '@/models/schema/notification.js';
-import { packedDriveFileSchema } from '@/models/schema/drive-file.js';
-import { packedDriveFolderSchema } from '@/models/schema/drive-folder.js';
-import { packedFollowingSchema } from '@/models/schema/following.js';
-import { packedMutingSchema } from '@/models/schema/muting.js';
-import { packedBlockingSchema } from '@/models/schema/blocking.js';
-import { packedNoteReactionSchema } from '@/models/schema/note-reaction.js';
-import { packedHashtagSchema } from '@/models/schema/hashtag.js';
-import { packedPageSchema } from '@/models/schema/page.js';
-import { packedUserGroupSchema } from '@/models/schema/user-group.js';
-import { packedNoteFavoriteSchema } from '@/models/schema/note-favorite.js';
-import { packedChannelSchema } from '@/models/schema/channel.js';
-import { packedAntennaSchema } from '@/models/schema/antenna.js';
-import { packedClipSchema } from '@/models/schema/clip.js';
-import { packedFederationInstanceSchema } from '@/models/schema/federation-instance.js';
-import { packedQueueCountSchema } from '@/models/schema/queue.js';
-import { packedGalleryPostSchema } from '@/models/schema/gallery-post.js';
-import { packedEmojiSchema } from '@/models/schema/emoji.js';
+} from "@/models/schema/user.js";
+import { packedNoteSchema } from "@/models/schema/note.js";
+import { packedUserListSchema } from "@/models/schema/user-list.js";
+import { packedAppSchema } from "@/models/schema/app.js";
+import { packedMessagingMessageSchema } from "@/models/schema/messaging-message.js";
+import { packedNotificationSchema } from "@/models/schema/notification.js";
+import { packedDriveFileSchema } from "@/models/schema/drive-file.js";
+import { packedDriveFolderSchema } from "@/models/schema/drive-folder.js";
+import { packedFollowingSchema } from "@/models/schema/following.js";
+import { packedMutingSchema } from "@/models/schema/muting.js";
+import { packedBlockingSchema } from "@/models/schema/blocking.js";
+import { packedNoteReactionSchema } from "@/models/schema/note-reaction.js";
+import { packedHashtagSchema } from "@/models/schema/hashtag.js";
+import { packedPageSchema } from "@/models/schema/page.js";
+import { packedUserGroupSchema } from "@/models/schema/user-group.js";
+import { packedNoteFavoriteSchema } from "@/models/schema/note-favorite.js";
+import { packedChannelSchema } from "@/models/schema/channel.js";
+import { packedAntennaSchema } from "@/models/schema/antenna.js";
+import { packedClipSchema } from "@/models/schema/clip.js";
+import { packedFederationInstanceSchema } from "@/models/schema/federation-instance.js";
+import { packedQueueCountSchema } from "@/models/schema/queue.js";
+import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js";
+import { packedEmojiSchema } from "@/models/schema/emoji.js";
 
 export const refs = {
 	UserLite: packedUserLiteSchema,
@@ -65,23 +65,37 @@ export const refs = {
 
 export type Packed = SchemaType;
 
-type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
-type StringDefToType =
-	T extends 'null' ? null :
-	T extends 'boolean' ? boolean :
-	T extends 'integer' ? number :
-	T extends 'number' ? number :
-	T extends 'string' ? string | Date :
-	T extends 'array' ? ReadonlyArray :
-	T extends 'object' ? Record :
-	any;
+type TypeStringef =
+	| "null"
+	| "boolean"
+	| "integer"
+	| "number"
+	| "string"
+	| "array"
+	| "object"
+	| "any";
+type StringDefToType = T extends "null"
+	? null
+	: T extends "boolean"
+	? boolean
+	: T extends "integer"
+	? number
+	: T extends "number"
+	? number
+	: T extends "string"
+	? string | Date
+	: T extends "array"
+	? ReadonlyArray
+	: T extends "object"
+	? Record
+	: any;
 
 // https://swagger.io/specification/?sbsearch=optional#schema-object
 type OfSchema = {
 	readonly anyOf?: ReadonlyArray;
 	readonly oneOf?: ReadonlyArray;
 	readonly allOf?: ReadonlyArray;
-}
+};
 
 export interface Schema extends OfSchema {
 	readonly type?: TypeStringef;
@@ -89,13 +103,17 @@ export interface Schema extends OfSchema {
 	readonly optional?: boolean;
 	readonly items?: Schema;
 	readonly properties?: Obj;
-	readonly required?: ReadonlyArray, string>>;
+	readonly required?: ReadonlyArray<
+		Extract, string>
+	>;
 	readonly description?: string;
 	readonly example?: any;
 	readonly format?: string;
 	readonly ref?: keyof typeof refs;
 	readonly enum?: ReadonlyArray;
-	readonly default?: (this['type'] extends TypeStringef ? StringDefToType : any) | null;
+	readonly default?:
+		| (this["type"] extends TypeStringef ? StringDefToType : any)
+		| null;
 	readonly maxLength?: number;
 	readonly minLength?: number;
 	readonly maximum?: number;
@@ -104,12 +122,18 @@ export interface Schema extends OfSchema {
 }
 
 type RequiredPropertyNames = {
-	[K in keyof s]:
-		// K is not optional
-		s[K]['optional'] extends false ? K :
-		// K has default value
-		s[K]['default'] extends null | string | number | boolean | Record ? K :
-		never
+	[K in keyof s]: // K is not optional
+	s[K]["optional"] extends false
+		? K
+		: // K has default value
+		s[K]["default"] extends
+				| null
+				| string
+				| number
+				| boolean
+				| Record
+		? K
+		: never;
 }[keyof s];
 
 export type Obj = Record;
@@ -117,56 +141,80 @@ export type Obj = Record;
 // https://github.com/misskey-dev/misskey/issues/8535
 // To avoid excessive stack depth error,
 // deceive TypeScript with UnionToIntersection (or more precisely, `infer` expression within it).
-export type ObjType =
-	UnionToIntersection<
-		{ -readonly [R in RequiredPropertyNames]-?: SchemaType } &
-		{ -readonly [R in RequiredProps]-?: SchemaType } &
-		{ -readonly [P in keyof s]?: SchemaType }
-	>;
+export type ObjType<
+	s extends Obj,
+	RequiredProps extends keyof s,
+> = UnionToIntersection<
+	{
+		-readonly [R in RequiredPropertyNames]-?: SchemaType;
+	} & {
+		-readonly [R in RequiredProps]-?: SchemaType;
+	} & {
+		-readonly [P in keyof s]?: SchemaType;
+	}
+>;
 
 type NullOrUndefined

= - | (p['nullable'] extends true ? null : never) - | (p['optional'] extends true ? undefined : never) + | (p["nullable"] extends true ? null : never) + | (p["optional"] extends true ? undefined : never) | T; // https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection -// Get intersection from union -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +// Get intersection from union +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( + k: infer I, +) => void + ? I + : never; // https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552 // To get union, we use `Foo extends any ? Hoge : never` -type UnionSchemaType = X extends any ? SchemaType : never; -type ArrayUnion = T extends any ? Array : never; +type UnionSchemaType< + a extends readonly any[], + X extends Schema = a[number], +> = X extends any ? SchemaType : never; +type ArrayUnion = T extends any ? Array : never; -export type SchemaTypeDef

= - p['type'] extends 'null' ? null : - p['type'] extends 'integer' ? number : - p['type'] extends 'number' ? number : - p['type'] extends 'string' ? ( - p['enum'] extends readonly string[] ? - p['enum'][number] : - p['format'] extends 'date-time' ? string : // Dateにする?? - string - ) : - p['type'] extends 'boolean' ? boolean : - p['type'] extends 'object' ? ( - p['ref'] extends keyof typeof refs ? Packed : - p['properties'] extends NonNullable ? ObjType[number]> : - p['anyOf'] extends ReadonlyArray ? UnionSchemaType & Partial>> : - p['allOf'] extends ReadonlyArray ? UnionToIntersection> : - any - ) : - p['type'] extends 'array' ? ( - p['items'] extends OfSchema ? ( - p['items']['anyOf'] extends ReadonlyArray ? UnionSchemaType>[] : - p['items']['oneOf'] extends ReadonlyArray ? ArrayUnion>> : - p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] : - never - ) : - p['items'] extends NonNullable ? SchemaTypeDef[] : - any[] - ) : - p['oneOf'] extends ReadonlyArray ? UnionSchemaType : - any; +export type SchemaTypeDef

= p["type"] extends "null" + ? null + : p["type"] extends "integer" + ? number + : p["type"] extends "number" + ? number + : p["type"] extends "string" + ? p["enum"] extends readonly string[] + ? p["enum"][number] + : p["format"] extends "date-time" + ? string + : // Dateにする?? + string + : p["type"] extends "boolean" + ? boolean + : p["type"] extends "object" + ? p["ref"] extends keyof typeof refs + ? Packed + : p["properties"] extends NonNullable + ? ObjType[number]> + : p["anyOf"] extends ReadonlyArray + ? UnionSchemaType & + Partial>> + : p["allOf"] extends ReadonlyArray + ? UnionToIntersection> + : any + : p["type"] extends "array" + ? p["items"] extends OfSchema + ? p["items"]["anyOf"] extends ReadonlyArray + ? UnionSchemaType>[] + : p["items"]["oneOf"] extends ReadonlyArray + ? ArrayUnion>> + : p["items"]["allOf"] extends ReadonlyArray + ? UnionToIntersection>>[] + : never + : p["items"] extends NonNullable + ? SchemaTypeDef[] + : any[] + : p["oneOf"] extends ReadonlyArray + ? UnionSchemaType + : any; export type SchemaType

= NullOrUndefined>; diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts index 8d4fcb1ba..7f5754e1c 100644 --- a/packages/backend/src/misc/secure-rndstr.ts +++ b/packages/backend/src/misc/secure-rndstr.ts @@ -1,16 +1,19 @@ -import * as crypto from 'node:crypto'; +import * as crypto from "node:crypto"; -const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz'; -const LU_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; +const L_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"; +const LU_CHARS = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; export function secureRndstr(length = 32, useLU = true): string { const chars = useLU ? LU_CHARS : L_CHARS; const chars_len = chars.length; - let str = ''; + let str = ""; for (let i = 0; i < length; i++) { - let rand = Math.floor((crypto.randomBytes(1).readUInt8(0) / 0xFF) * chars_len); + let rand = Math.floor( + (crypto.randomBytes(1).readUInt8(0) / 0xff) * chars_len, + ); if (rand === chars_len) { rand = chars_len - 1; } diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts new file mode 100644 index 000000000..6e4623242 --- /dev/null +++ b/packages/backend/src/misc/should-block-instance.ts @@ -0,0 +1,20 @@ +import { fetchMeta } from "@/misc/fetch-meta.js"; +import type { Instance } from "@/models/entities/instance.js"; +import type { Meta } from "@/models/entities/meta.js"; + +/** + * Returns whether a specific host (punycoded) should be blocked. + * + * @param host punycoded instance host + * @param meta a resolved Meta table + * @returns whether the given host should be blocked + */ +export async function shouldBlockInstance( + host: Instance["host"], + meta?: Meta, +): Promise { + const { blockedHosts } = meta ?? (await fetchMeta()); + return blockedHosts.some( + (blockedHost) => host === blockedHost || host.endsWith(`.${blockedHost}`), + ); +} diff --git a/packages/backend/src/misc/show-machine-info.ts b/packages/backend/src/misc/show-machine-info.ts index bc71cfbe9..d3a28cbd3 100644 --- a/packages/backend/src/misc/show-machine-info.ts +++ b/packages/backend/src/misc/show-machine-info.ts @@ -1,13 +1,17 @@ -import * as os from 'node:os'; -import sysUtils from 'systeminformation'; -import Logger from '@/services/logger.js'; +import * as os from "node:os"; +import sysUtils from "systeminformation"; +import type Logger from "@/services/logger.js"; export async function showMachineInfo(parentLogger: Logger) { - const logger = parentLogger.createSubLogger('machine'); + const logger = parentLogger.createSubLogger("machine"); logger.debug(`Hostname: ${os.hostname()}`); logger.debug(`Platform: ${process.platform} Arch: ${process.arch}`); const mem = await sysUtils.mem(); const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1); const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1); - logger.debug(`CPU: ${os.cpus().length} core MEM: ${totalmem}GB (available: ${availmem}GB)`); + logger.debug( + `CPU: ${ + os.cpus().length + } core MEM: ${totalmem}GB (available: ${availmem}GB)`, + ); } diff --git a/packages/backend/src/misc/skipped-instances.ts b/packages/backend/src/misc/skipped-instances.ts index a89ca2e3f..785393022 100644 --- a/packages/backend/src/misc/skipped-instances.ts +++ b/packages/backend/src/misc/skipped-instances.ts @@ -1,8 +1,9 @@ -import { Brackets } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Instances } from '@/models/index.js'; -import { Instance } from '@/models/entities/instance.js'; -import { DAY } from '@/const.js'; +import { Brackets } from "typeorm"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Instances } from "@/models/index.js"; +import type { Instance } from "@/models/entities/instance.js"; +import { DAY } from "@/const.js"; +import { shouldBlockInstance } from "./should-block-instance.js"; // Threshold from last contact after which an instance will be considered // "dead" and should no longer get activities delivered to it. @@ -10,32 +11,39 @@ const deadThreshold = 7 * DAY; /** * Returns the subset of hosts which should be skipped. - * + * * @param hosts array of punycoded instance hosts * @returns array of punycoed instance hosts that should be skipped (subset of hosts parameter) */ -export async function skippedInstances(hosts: Array): Array { +export async function skippedInstances( + hosts: Instance["host"][], +): Promise { // first check for blocked instances since that info may already be in memory - const { blockedHosts } = await fetchMeta(); + const meta = await fetchMeta(); + const shouldSkip = await Promise.all( + hosts.map((host) => shouldBlockInstance(host, meta)), + ); + const skipped = hosts.filter((_, i) => shouldSkip[i]); - const skipped = hosts.filter(host => blockedHosts.includes(host)); // if possible return early and skip accessing the database - if (skipped.length === hosts.length) return hosts; + if (skipped.length === hosts.length) return hosts; const deadTime = new Date(Date.now() - deadThreshold); return skipped.concat( - await Instances.createQueryBuilder('instance') - .where('instance.host in (:...hosts)', { + await Instances.createQueryBuilder("instance") + .where("instance.host in (:...hosts)", { // don't check hosts again that we already know are suspended // also avoids adding duplicates to the list - hosts: hosts.filter(host => !skipped.includes(host)), + hosts: hosts.filter((host) => !skipped.includes(host)), }) - .andWhere(new Brackets(qb => { qb - .where('instance.isSuspended') - })) - .select('host') - .getRawMany() + .andWhere( + new Brackets((qb) => { + qb.where("instance.isSuspended"); + }), + ) + .select("host") + .getRawMany(), ); } @@ -47,7 +55,9 @@ export async function skippedInstances(hosts: Array): Array { const skipped = await skippedInstances([host]); return skipped.length > 0; } diff --git a/packages/backend/src/misc/truncate.ts b/packages/backend/src/misc/truncate.ts index cb120331a..6bc58941a 100644 --- a/packages/backend/src/misc/truncate.ts +++ b/packages/backend/src/misc/truncate.ts @@ -1,8 +1,14 @@ -import { substring } from 'stringz'; +import { substring } from "stringz"; export function truncate(input: string, size: number): string; -export function truncate(input: string | undefined, size: number): string | undefined; -export function truncate(input: string | undefined, size: number): string | undefined { +export function truncate( + input: string | undefined, + size: number, +): string | undefined; +export function truncate( + input: string | undefined, + size: number, +): string | undefined { if (!input) { return input; } else { diff --git a/packages/backend/src/misc/webhook-cache.ts b/packages/backend/src/misc/webhook-cache.ts index 5e72dbd92..1eda5eaec 100644 --- a/packages/backend/src/misc/webhook-cache.ts +++ b/packages/backend/src/misc/webhook-cache.ts @@ -1,6 +1,6 @@ -import { Webhooks } from '@/models/index.js'; -import { Webhook } from '@/models/entities/webhook.js'; -import { subscriber } from '@/db/redis.js'; +import { Webhooks } from "@/models/index.js"; +import type { Webhook } from "@/models/entities/webhook.js"; +import { subscriber } from "@/db/redis.js"; let webhooksFetched = false; let webhooks: Webhook[] = []; @@ -16,31 +16,31 @@ export async function getActiveWebhooks() { return webhooks; } -subscriber.on('message', async (_, data) => { +subscriber.on("message", async (_, data) => { const obj = JSON.parse(data); - if (obj.channel === 'internal') { + if (obj.channel === "internal") { const { type, body } = obj.message; switch (type) { - case 'webhookCreated': + case "webhookCreated": if (body.active) { webhooks.push(body); } break; - case 'webhookUpdated': + case "webhookUpdated": if (body.active) { - const i = webhooks.findIndex(a => a.id === body.id); + const i = webhooks.findIndex((a) => a.id === body.id); if (i > -1) { webhooks[i] = body; } else { webhooks.push(body); } } else { - webhooks = webhooks.filter(a => a.id !== body.id); + webhooks = webhooks.filter((a) => a.id !== body.id); } break; - case 'webhookDeleted': - webhooks = webhooks.filter(a => a.id !== body.id); + case "webhookDeleted": + webhooks = webhooks.filter((a) => a.id !== body.id); break; default: break; diff --git a/packages/backend/src/models/entities/abuse-user-report.ts b/packages/backend/src/models/entities/abuse-user-report.ts index 6ac563552..655fdd3ca 100644 --- a/packages/backend/src/models/entities/abuse-user-report.ts +++ b/packages/backend/src/models/entities/abuse-user-report.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class AbuseUserReport { @@ -15,7 +22,7 @@ export class AbuseUserReport { @Index() @Column(id()) - public targetUserId: User['id']; + public targetUserId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -25,7 +32,7 @@ export class AbuseUserReport { @Index() @Column(id()) - public reporterId: User['id']; + public reporterId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -37,7 +44,7 @@ export class AbuseUserReport { ...id(), nullable: true, }) - public assigneeId: User['id'] | null; + public assigneeId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/access-token.ts b/packages/backend/src/models/entities/access-token.ts index c6e2141a4..83d7bbda8 100644 --- a/packages/backend/src/models/entities/access-token.ts +++ b/packages/backend/src/models/entities/access-token.ts @@ -1,7 +1,14 @@ -import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { User } from './user.js'; -import { App } from './app.js'; -import { id } from '../id.js'; +import { + Entity, + PrimaryColumn, + Index, + Column, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { User } from "./user.js"; +import { App } from "./app.js"; +import { id } from "../id.js"; @Entity() export class AccessToken { @@ -39,7 +46,7 @@ export class AccessToken { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -51,7 +58,7 @@ export class AccessToken { ...id(), nullable: true, }) - public appId: App['id'] | null; + public appId: App["id"] | null; @ManyToOne(type => App, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/ad.ts b/packages/backend/src/models/entities/ad.ts index 36b758f20..fa4297365 100644 --- a/packages/backend/src/models/entities/ad.ts +++ b/packages/backend/src/models/entities/ad.ts @@ -1,5 +1,5 @@ -import { Entity, Index, Column, PrimaryColumn } from 'typeorm'; -import { id } from '../id.js'; +import { Entity, Index, Column, PrimaryColumn } from "typeorm"; +import { id } from "../id.js"; @Entity() export class Ad { diff --git a/packages/backend/src/models/entities/announcement-read.ts b/packages/backend/src/models/entities/announcement-read.ts index e4d256a86..87d0f0e9e 100644 --- a/packages/backend/src/models/entities/announcement-read.ts +++ b/packages/backend/src/models/entities/announcement-read.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Announcement } from './announcement.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Announcement } from "./announcement.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'announcementId'], { unique: true }) @@ -16,7 +23,7 @@ export class AnnouncementRead { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -26,7 +33,7 @@ export class AnnouncementRead { @Index() @Column(id()) - public announcementId: Announcement['id']; + public announcementId: Announcement["id"]; @ManyToOne(type => Announcement, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/announcement.ts b/packages/backend/src/models/entities/announcement.ts index beb2f8246..9d45af014 100644 --- a/packages/backend/src/models/entities/announcement.ts +++ b/packages/backend/src/models/entities/announcement.ts @@ -1,5 +1,5 @@ -import { Entity, Index, Column, PrimaryColumn } from 'typeorm'; -import { id } from '../id.js'; +import { Entity, Index, Column, PrimaryColumn } from "typeorm"; +import { id } from "../id.js"; @Entity() export class Announcement { diff --git a/packages/backend/src/models/entities/antenna-note.ts b/packages/backend/src/models/entities/antenna-note.ts index fcca493fe..c47c796bb 100644 --- a/packages/backend/src/models/entities/antenna-note.ts +++ b/packages/backend/src/models/entities/antenna-note.ts @@ -1,7 +1,14 @@ -import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note.js'; -import { Antenna } from './antenna.js'; -import { id } from '../id.js'; +import { + Entity, + Index, + JoinColumn, + Column, + ManyToOne, + PrimaryColumn, +} from "typeorm"; +import { Note } from "./note.js"; +import { Antenna } from "./antenna.js"; +import { id } from "../id.js"; @Entity() @Index(['noteId', 'antennaId'], { unique: true }) @@ -14,7 +21,7 @@ export class AntennaNote { ...id(), comment: 'The note ID.', }) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -27,7 +34,7 @@ export class AntennaNote { ...id(), comment: 'The antenna ID.', }) - public antennaId: Antenna['id']; + public antennaId: Antenna["id"]; @ManyToOne(type => Antenna, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/antenna.ts b/packages/backend/src/models/entities/antenna.ts index 6c8bb13e5..45d9553e4 100644 --- a/packages/backend/src/models/entities/antenna.ts +++ b/packages/backend/src/models/entities/antenna.ts @@ -1,8 +1,15 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { UserList } from './user-list.js'; -import { UserGroupJoining } from './user-group-joining.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { UserList } from "./user-list.js"; +import { UserGroupJoining } from "./user-group-joining.js"; @Entity() export class Antenna { @@ -19,7 +26,7 @@ export class Antenna { ...id(), comment: 'The owner ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -34,13 +41,13 @@ export class Antenna { public name: string; @Column('enum', { enum: ['home', 'all', 'users', 'list', 'group'] }) - public src: 'home' | 'all' | 'users' | 'list' | 'group'; + public src: "home" | "all" | "users" | "list" | "group"; @Column({ ...id(), nullable: true, }) - public userListId: UserList['id'] | null; + public userListId: UserList["id"] | null; @ManyToOne(type => UserList, { onDelete: 'CASCADE', @@ -52,7 +59,7 @@ export class Antenna { ...id(), nullable: true, }) - public userGroupJoiningId: UserGroupJoining['id'] | null; + public userGroupJoiningId: UserGroupJoining["id"] | null; @ManyToOne(type => UserGroupJoining, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/app.ts b/packages/backend/src/models/entities/app.ts index 46c11548a..bb33eede4 100644 --- a/packages/backend/src/models/entities/app.ts +++ b/packages/backend/src/models/entities/app.ts @@ -1,6 +1,6 @@ -import { Entity, PrimaryColumn, Column, Index, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { Entity, PrimaryColumn, Column, Index, ManyToOne } from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class App { @@ -19,7 +19,7 @@ export class App { nullable: true, comment: 'The owner ID.', }) - public userId: User['id'] | null; + public userId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/attestation-challenge.ts b/packages/backend/src/models/entities/attestation-challenge.ts index c40df2329..7a87d42be 100644 --- a/packages/backend/src/models/entities/attestation-challenge.ts +++ b/packages/backend/src/models/entities/attestation-challenge.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + JoinColumn, + Column, + ManyToOne, + Index, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class AttestationChallenge { @@ -9,7 +16,7 @@ export class AttestationChallenge { @Index() @PrimaryColumn(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/auth-session.ts b/packages/backend/src/models/entities/auth-session.ts index 295d1b486..b762f8462 100644 --- a/packages/backend/src/models/entities/auth-session.ts +++ b/packages/backend/src/models/entities/auth-session.ts @@ -1,7 +1,14 @@ -import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { User } from './user.js'; -import { App } from './app.js'; -import { id } from '../id.js'; +import { + Entity, + PrimaryColumn, + Index, + Column, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { User } from "./user.js"; +import { App } from "./app.js"; +import { id } from "../id.js"; @Entity() export class AuthSession { @@ -23,7 +30,7 @@ export class AuthSession { ...id(), nullable: true, }) - public userId: User['id'] | null; + public userId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -33,7 +40,7 @@ export class AuthSession { public user: User | null; @Column(id()) - public appId: App['id']; + public appId: App["id"]; @ManyToOne(type => App, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/blocking.ts b/packages/backend/src/models/entities/blocking.ts index 4ac73a00b..3a44a4d65 100644 --- a/packages/backend/src/models/entities/blocking.ts +++ b/packages/backend/src/models/entities/blocking.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['blockerId', 'blockeeId'], { unique: true }) @@ -19,7 +26,7 @@ export class Blocking { ...id(), comment: 'The blockee user ID.', }) - public blockeeId: User['id']; + public blockeeId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -32,7 +39,7 @@ export class Blocking { ...id(), comment: 'The blocker user ID.', }) - public blockerId: User['id']; + public blockerId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/channel-following.ts b/packages/backend/src/models/entities/channel-following.ts index 029dd6cf1..04ec193e1 100644 --- a/packages/backend/src/models/entities/channel-following.ts +++ b/packages/backend/src/models/entities/channel-following.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { Channel } from './channel.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { Channel } from "./channel.js"; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) @@ -20,7 +27,7 @@ export class ChannelFollowing { ...id(), comment: 'The followee channel ID.', }) - public followeeId: Channel['id']; + public followeeId: Channel["id"]; @ManyToOne(type => Channel, { onDelete: 'CASCADE', @@ -33,7 +40,7 @@ export class ChannelFollowing { ...id(), comment: 'The follower user ID.', }) - public followerId: User['id']; + public followerId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/channel-note-pining.ts b/packages/backend/src/models/entities/channel-note-pining.ts index 23be3b69d..bd13f4ca3 100644 --- a/packages/backend/src/models/entities/channel-note-pining.ts +++ b/packages/backend/src/models/entities/channel-note-pining.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note.js'; -import { Channel } from './channel.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { Note } from "./note.js"; +import { Channel } from "./channel.js"; +import { id } from "../id.js"; @Entity() @Index(['channelId', 'noteId'], { unique: true }) @@ -16,7 +23,7 @@ export class ChannelNotePining { @Index() @Column(id()) - public channelId: Channel['id']; + public channelId: Channel["id"]; @ManyToOne(type => Channel, { onDelete: 'CASCADE', @@ -25,7 +32,7 @@ export class ChannelNotePining { public channel: Channel | null; @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/channel.ts b/packages/backend/src/models/entities/channel.ts index abf6668bd..7f9851dbf 100644 --- a/packages/backend/src/models/entities/channel.ts +++ b/packages/backend/src/models/entities/channel.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { DriveFile } from './drive-file.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { DriveFile } from "./drive-file.js"; @Entity() export class Channel { @@ -26,7 +33,7 @@ export class Channel { nullable: true, comment: 'The owner ID.', }) - public userId: User['id'] | null; + public userId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'SET NULL', @@ -51,7 +58,7 @@ export class Channel { nullable: true, comment: 'The ID of banner Channel.', }) - public bannerId: DriveFile['id'] | null; + public bannerId: DriveFile["id"] | null; @ManyToOne(type => DriveFile, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/clip-note.ts b/packages/backend/src/models/entities/clip-note.ts index 6f3688550..bc51daaf4 100644 --- a/packages/backend/src/models/entities/clip-note.ts +++ b/packages/backend/src/models/entities/clip-note.ts @@ -1,7 +1,14 @@ -import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note.js'; -import { Clip } from './clip.js'; -import { id } from '../id.js'; +import { + Entity, + Index, + JoinColumn, + Column, + ManyToOne, + PrimaryColumn, +} from "typeorm"; +import { Note } from "./note.js"; +import { Clip } from "./clip.js"; +import { id } from "../id.js"; @Entity() @Index(['noteId', 'clipId'], { unique: true }) @@ -14,7 +21,7 @@ export class ClipNote { ...id(), comment: 'The note ID.', }) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -27,7 +34,7 @@ export class ClipNote { ...id(), comment: 'The clip ID.', }) - public clipId: Clip['id']; + public clipId: Clip["id"]; @ManyToOne(type => Clip, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/clip.ts b/packages/backend/src/models/entities/clip.ts index 1386684c3..10591cbee 100644 --- a/packages/backend/src/models/entities/clip.ts +++ b/packages/backend/src/models/entities/clip.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class Clip { @@ -17,7 +24,7 @@ export class Clip { ...id(), comment: 'The owner ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index d410b1d42..1fa91b1a9 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { id } from '../id.js'; -import { User } from './user.js'; -import { DriveFolder } from './drive-folder.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { id } from "../id.js"; +import { User } from "./user.js"; +import { DriveFolder } from "./drive-folder.js"; @Entity() @Index(['userId', 'folderId', 'id']) @@ -21,7 +28,7 @@ export class DriveFile { nullable: true, comment: 'The owner ID.', }) - public userId: User['id'] | null; + public userId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'SET NULL', @@ -77,7 +84,12 @@ export class DriveFile { default: {}, comment: 'The any properties of the DriveFile. For example, it includes image width/height.', }) - public properties: { width?: number; height?: number; orientation?: number; avgColor?: string }; + public properties: { + width?: number; + height?: number; + orientation?: number; + avgColor?: string; + }; @Column('boolean') public storedInternal: boolean; @@ -141,7 +153,7 @@ export class DriveFile { nullable: true, comment: 'The parent folder ID. If null, it means the DriveFile is located in root.', }) - public folderId: DriveFolder['id'] | null; + public folderId: DriveFolder["id"] | null; @ManyToOne(type => DriveFolder, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/drive-folder.ts b/packages/backend/src/models/entities/drive-folder.ts index d4022c6eb..77031ce4e 100644 --- a/packages/backend/src/models/entities/drive-folder.ts +++ b/packages/backend/src/models/entities/drive-folder.ts @@ -1,6 +1,13 @@ -import { JoinColumn, ManyToOne, Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + JoinColumn, + ManyToOne, + Entity, + PrimaryColumn, + Index, + Column, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class DriveFolder { @@ -25,7 +32,7 @@ export class DriveFolder { nullable: true, comment: 'The owner ID.', }) - public userId: User['id'] | null; + public userId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -39,7 +46,7 @@ export class DriveFolder { nullable: true, comment: 'The parent folder ID. If null, it means the DriveFolder is located in root.', }) - public parentId: DriveFolder['id'] | null; + public parentId: DriveFolder["id"] | null; @ManyToOne(type => DriveFolder, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/emoji.ts b/packages/backend/src/models/entities/emoji.ts index 7332dd185..f251de897 100644 --- a/packages/backend/src/models/entities/emoji.ts +++ b/packages/backend/src/models/entities/emoji.ts @@ -1,5 +1,5 @@ -import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id.js'; +import { PrimaryColumn, Entity, Index, Column } from "typeorm"; +import { id } from "../id.js"; @Entity() @Index(['name', 'host'], { unique: true }) diff --git a/packages/backend/src/models/entities/follow-request.ts b/packages/backend/src/models/entities/follow-request.ts index 89946f6d3..658fed5a5 100644 --- a/packages/backend/src/models/entities/follow-request.ts +++ b/packages/backend/src/models/entities/follow-request.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) @@ -18,7 +25,7 @@ export class FollowRequest { ...id(), comment: 'The followee user ID.', }) - public followeeId: User['id']; + public followeeId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -31,7 +38,7 @@ export class FollowRequest { ...id(), comment: 'The follower user ID.', }) - public followerId: User['id']; + public followerId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/following.ts b/packages/backend/src/models/entities/following.ts index b283ca7e8..11f633fcd 100644 --- a/packages/backend/src/models/entities/following.ts +++ b/packages/backend/src/models/entities/following.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) @@ -19,7 +26,7 @@ export class Following { ...id(), comment: 'The followee user ID.', }) - public followeeId: User['id']; + public followeeId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -32,7 +39,7 @@ export class Following { ...id(), comment: 'The follower user ID.', }) - public followerId: User['id']; + public followerId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/gallery-like.ts b/packages/backend/src/models/entities/gallery-like.ts index 4ce166d19..e74e3c3ce 100644 --- a/packages/backend/src/models/entities/gallery-like.ts +++ b/packages/backend/src/models/entities/gallery-like.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { GalleryPost } from './gallery-post.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { GalleryPost } from "./gallery-post.js"; @Entity() @Index(['userId', 'postId'], { unique: true }) @@ -14,7 +21,7 @@ export class GalleryLike { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -23,7 +30,7 @@ export class GalleryLike { public user: User | null; @Column(id()) - public postId: GalleryPost['id']; + public postId: GalleryPost["id"]; @ManyToOne(type => GalleryPost, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/gallery-post.ts b/packages/backend/src/models/entities/gallery-post.ts index 774cb946e..a79bb8835 100644 --- a/packages/backend/src/models/entities/gallery-post.ts +++ b/packages/backend/src/models/entities/gallery-post.ts @@ -1,7 +1,14 @@ -import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { DriveFile } from './drive-file.js'; +import { + Entity, + Index, + JoinColumn, + Column, + PrimaryColumn, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import type { DriveFile } from "./drive-file.js"; @Entity() export class GalleryPost { @@ -35,7 +42,7 @@ export class GalleryPost { ...id(), comment: 'The ID of author.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -48,7 +55,7 @@ export class GalleryPost { ...id(), array: true, default: '{}', }) - public fileIds: DriveFile['id'][]; + public fileIds: DriveFile["id"][]; @Index() @Column('boolean', { diff --git a/packages/backend/src/models/entities/hashtag.ts b/packages/backend/src/models/entities/hashtag.ts index 6bd991f62..06fa004be 100644 --- a/packages/backend/src/models/entities/hashtag.ts +++ b/packages/backend/src/models/entities/hashtag.ts @@ -1,6 +1,6 @@ -import { Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { Entity, PrimaryColumn, Index, Column } from "typeorm"; +import type { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class Hashtag { @@ -17,7 +17,7 @@ export class Hashtag { ...id(), array: true, }) - public mentionedUserIds: User['id'][]; + public mentionedUserIds: User["id"][]; @Index() @Column('integer', { @@ -29,7 +29,7 @@ export class Hashtag { ...id(), array: true, }) - public mentionedLocalUserIds: User['id'][]; + public mentionedLocalUserIds: User["id"][]; @Index() @Column('integer', { @@ -41,7 +41,7 @@ export class Hashtag { ...id(), array: true, }) - public mentionedRemoteUserIds: User['id'][]; + public mentionedRemoteUserIds: User["id"][]; @Index() @Column('integer', { @@ -53,7 +53,7 @@ export class Hashtag { ...id(), array: true, }) - public attachedUserIds: User['id'][]; + public attachedUserIds: User["id"][]; @Index() @Column('integer', { @@ -65,7 +65,7 @@ export class Hashtag { ...id(), array: true, }) - public attachedLocalUserIds: User['id'][]; + public attachedLocalUserIds: User["id"][]; @Index() @Column('integer', { @@ -77,7 +77,7 @@ export class Hashtag { ...id(), array: true, }) - public attachedRemoteUserIds: User['id'][]; + public attachedRemoteUserIds: User["id"][]; @Index() @Column('integer', { diff --git a/packages/backend/src/models/entities/instance.ts b/packages/backend/src/models/entities/instance.ts index 7ea923438..2b118455d 100644 --- a/packages/backend/src/models/entities/instance.ts +++ b/packages/backend/src/models/entities/instance.ts @@ -1,5 +1,5 @@ -import { Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { id } from '../id.js'; +import { Entity, PrimaryColumn, Index, Column } from "typeorm"; +import { id } from "../id.js"; @Entity() export class Instance { diff --git a/packages/backend/src/models/entities/messaging-message.ts b/packages/backend/src/models/entities/messaging-message.ts index 099fb7aa0..9cf197fa3 100644 --- a/packages/backend/src/models/entities/messaging-message.ts +++ b/packages/backend/src/models/entities/messaging-message.ts @@ -1,8 +1,15 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { DriveFile } from './drive-file.js'; -import { id } from '../id.js'; -import { UserGroup } from './user-group.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { DriveFile } from "./drive-file.js"; +import { id } from "../id.js"; +import { UserGroup } from "./user-group.js"; @Entity() export class MessagingMessage { @@ -20,7 +27,7 @@ export class MessagingMessage { ...id(), comment: 'The sender user ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -33,7 +40,7 @@ export class MessagingMessage { ...id(), nullable: true, comment: 'The recipient user ID.', }) - public recipientId: User['id'] | null; + public recipientId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -46,7 +53,7 @@ export class MessagingMessage { ...id(), nullable: true, comment: 'The recipient group ID.', }) - public groupId: UserGroup['id'] | null; + public groupId: UserGroup["id"] | null; @ManyToOne(type => UserGroup, { onDelete: 'CASCADE', @@ -73,13 +80,13 @@ export class MessagingMessage { ...id(), array: true, default: '{}', }) - public reads: User['id'][]; + public reads: User["id"][]; @Column({ ...id(), nullable: true, }) - public fileId: DriveFile['id'] | null; + public fileId: DriveFile["id"] | null; @ManyToOne(type => DriveFile, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index c24936c03..26a7c9c19 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -1,7 +1,7 @@ -import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm'; -import { id } from '../id.js'; -import { User } from './user.js'; -import type { Clip } from './clip.js'; +import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from "typeorm"; +import { id } from "../id.js"; +import { User } from "./user.js"; +import type { Clip } from "./clip.js"; @Entity() export class Meta { @@ -57,10 +57,10 @@ export class Meta { }) public disableGlobalTimeline: boolean; - @Column('boolean', { - default: false, + @Column('varchar', { + length: 256, default: '⭐', }) - public useStarForReactionFallback: boolean; + public defaultReaction: string; @Column('varchar', { length: 64, array: true, default: '{}', @@ -121,7 +121,7 @@ export class Meta { ...id(), nullable: true, }) - public pinnedClipId: Clip['id'] | null; + public pinnedClipId: Clip["id"] | null; @Column('varchar', { length: 512, @@ -176,7 +176,7 @@ export class Meta { ...id(), nullable: true, }) - public proxyAccountId: User['id'] | null; + public proxyAccountId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'SET NULL', @@ -227,13 +227,18 @@ export class Meta { enum: ['none', 'all', 'local', 'remote'], default: 'none', }) - public sensitiveMediaDetection: 'none' | 'all' | 'local' | 'remote'; + public sensitiveMediaDetection: "none" | "all" | "local" | "remote"; @Column('enum', { enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'], default: 'medium', }) - public sensitiveMediaDetectionSensitivity: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh'; + public sensitiveMediaDetectionSensitivity: + | "medium" + | "low" + | "high" + | "veryLow" + | "veryHigh"; @Column('boolean', { default: false, diff --git a/packages/backend/src/models/entities/moderation-log.ts b/packages/backend/src/models/entities/moderation-log.ts index c99e55078..cc745e0d2 100644 --- a/packages/backend/src/models/entities/moderation-log.ts +++ b/packages/backend/src/models/entities/moderation-log.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class ModerationLog { @@ -14,7 +21,7 @@ export class ModerationLog { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/muted-note.ts b/packages/backend/src/models/entities/muted-note.ts index 96a4fa8e3..11a6ae95d 100644 --- a/packages/backend/src/models/entities/muted-note.ts +++ b/packages/backend/src/models/entities/muted-note.ts @@ -1,8 +1,15 @@ -import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { mutedNoteReasons } from '../../types.js'; +import { + Entity, + Index, + JoinColumn, + Column, + ManyToOne, + PrimaryColumn, +} from "typeorm"; +import { Note } from "./note.js"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { mutedNoteReasons } from "../../types.js"; @Entity() @Index(['noteId', 'userId'], { unique: true }) @@ -15,7 +22,7 @@ export class MutedNote { ...id(), comment: 'The note ID.', }) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -28,7 +35,7 @@ export class MutedNote { ...id(), comment: 'The user ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/muting.ts b/packages/backend/src/models/entities/muting.ts index 8f9e69063..561bcfb95 100644 --- a/packages/backend/src/models/entities/muting.ts +++ b/packages/backend/src/models/entities/muting.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['muterId', 'muteeId'], { unique: true }) @@ -25,7 +32,7 @@ export class Muting { ...id(), comment: 'The mutee user ID.', }) - public muteeId: User['id']; + public muteeId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -38,7 +45,7 @@ export class Muting { ...id(), comment: 'The muter user ID.', }) - public muterId: User['id']; + public muterId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/note-favorite.ts b/packages/backend/src/models/entities/note-favorite.ts index fe065b77a..ab12d8b1b 100644 --- a/packages/backend/src/models/entities/note-favorite.ts +++ b/packages/backend/src/models/entities/note-favorite.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { Note } from "./note.js"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -16,7 +23,7 @@ export class NoteFavorite { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -25,7 +32,7 @@ export class NoteFavorite { public user: User | null; @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/note-reaction.ts b/packages/backend/src/models/entities/note-reaction.ts index d7bc60989..0e51c33b1 100644 --- a/packages/backend/src/models/entities/note-reaction.ts +++ b/packages/backend/src/models/entities/note-reaction.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Note } from './note.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Note } from "./note.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -17,7 +24,7 @@ export class NoteReaction { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -27,7 +34,7 @@ export class NoteReaction { @Index() @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/note-thread-muting.ts b/packages/backend/src/models/entities/note-thread-muting.ts index 8c5f7bbab..2985b195f 100644 --- a/packages/backend/src/models/entities/note-thread-muting.ts +++ b/packages/backend/src/models/entities/note-thread-muting.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Note } from './note.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Note } from "./note.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'threadId'], { unique: true }) @@ -17,7 +24,7 @@ export class NoteThreadMuting { @Column({ ...id(), }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/note-unread.ts b/packages/backend/src/models/entities/note-unread.ts index a7acf254d..d5bba7221 100644 --- a/packages/backend/src/models/entities/note-unread.ts +++ b/packages/backend/src/models/entities/note-unread.ts @@ -1,8 +1,15 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Note } from './note.js'; -import { id } from '../id.js'; -import { Channel } from './channel.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Note } from "./note.js"; +import { id } from "../id.js"; +import type { Channel } from "./channel.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -12,7 +19,7 @@ export class NoteUnread { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -22,7 +29,7 @@ export class NoteUnread { @Index() @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -50,7 +57,7 @@ export class NoteUnread { ...id(), comment: '[Denormalized]', }) - public noteUserId: User['id']; + public noteUserId: User["id"]; @Index() @Column({ @@ -58,6 +65,6 @@ export class NoteUnread { nullable: true, comment: '[Denormalized]', }) - public noteChannelId: Channel['id'] | null; + public noteChannelId: Channel["id"] | null; //#endregion } diff --git a/packages/backend/src/models/entities/note-watching.ts b/packages/backend/src/models/entities/note-watching.ts index ed82e7dfe..7ac3e8e29 100644 --- a/packages/backend/src/models/entities/note-watching.ts +++ b/packages/backend/src/models/entities/note-watching.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Note } from './note.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Note } from "./note.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -20,7 +27,7 @@ export class NoteWatching { ...id(), comment: 'The watcher ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -33,7 +40,7 @@ export class NoteWatching { ...id(), comment: 'The target Note ID.', }) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -47,6 +54,6 @@ export class NoteWatching { ...id(), comment: '[Denormalized]', }) - public noteUserId: Note['userId']; + public noteUserId: Note["userId"]; //#endregion } diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index 0ffeb85f6..fd6b170c0 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -1,9 +1,16 @@ -import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { DriveFile } from './drive-file.js'; -import { id } from '../id.js'; -import { noteVisibilities } from '../../types.js'; -import { Channel } from './channel.js'; +import { + Entity, + Index, + JoinColumn, + Column, + PrimaryColumn, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import type { DriveFile } from "./drive-file.js"; +import { id } from "../id.js"; +import { noteVisibilities } from "../../types.js"; +import { Channel } from "./channel.js"; @Entity() @Index('IDX_NOTE_TAGS', { synchronize: false }) @@ -25,7 +32,7 @@ export class Note { nullable: true, comment: 'The ID of reply target.', }) - public replyId: Note['id'] | null; + public replyId: Note["id"] | null; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -39,7 +46,7 @@ export class Note { nullable: true, comment: 'The ID of renote target.', }) - public renoteId: Note['id'] | null; + public renoteId: Note["id"] | null; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -73,7 +80,7 @@ export class Note { ...id(), comment: 'The ID of author.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -133,7 +140,7 @@ export class Note { ...id(), array: true, default: '{}', }) - public fileIds: DriveFile['id'][]; + public fileIds: DriveFile["id"][]; @Index() @Column('varchar', { @@ -146,14 +153,14 @@ export class Note { ...id(), array: true, default: '{}', }) - public visibleUserIds: User['id'][]; + public visibleUserIds: User["id"][]; @Index() @Column({ ...id(), array: true, default: '{}', }) - public mentions: User['id'][]; + public mentions: User["id"][]; @Column('text', { default: '[]', @@ -182,7 +189,7 @@ export class Note { nullable: true, comment: 'The ID of source channel.', }) - public channelId: Channel['id'] | null; + public channelId: Channel["id"] | null; @ManyToOne(type => Channel, { onDelete: 'CASCADE', @@ -203,7 +210,7 @@ export class Note { nullable: true, comment: '[Denormalized]', }) - public replyUserId: User['id'] | null; + public replyUserId: User["id"] | null; @Column('varchar', { length: 128, nullable: true, @@ -216,7 +223,7 @@ export class Note { nullable: true, comment: '[Denormalized]', }) - public renoteUserId: User['id'] | null; + public renoteUserId: User["id"] | null; @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/models/entities/notification.ts b/packages/backend/src/models/entities/notification.ts index db3dba363..2c55e988f 100644 --- a/packages/backend/src/models/entities/notification.ts +++ b/packages/backend/src/models/entities/notification.ts @@ -1,11 +1,18 @@ -import { Entity, Index, JoinColumn, ManyToOne, Column, PrimaryColumn } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { Note } from './note.js'; -import { FollowRequest } from './follow-request.js'; -import { UserGroupInvitation } from './user-group-invitation.js'; -import { AccessToken } from './access-token.js'; -import { notificationTypes } from '@/types.js'; +import { + Entity, + Index, + JoinColumn, + ManyToOne, + Column, + PrimaryColumn, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { Note } from "./note.js"; +import { FollowRequest } from "./follow-request.js"; +import { UserGroupInvitation } from "./user-group-invitation.js"; +import { AccessToken } from "./access-token.js"; +import { notificationTypes } from "@/types.js"; @Entity() export class Notification { @@ -19,14 +26,14 @@ export class Notification { public createdAt: Date; /** - * 通知の受信者 + * Notification Recipient ID */ @Index() @Column({ ...id(), comment: 'The ID of recipient user of the Notification.', }) - public notifieeId: User['id']; + public notifieeId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -35,7 +42,7 @@ export class Notification { public notifiee: User | null; /** - * 通知の送信者(initiator) + * Notification sender (initiator) */ @Index() @Column({ @@ -43,7 +50,7 @@ export class Notification { nullable: true, comment: 'The ID of sender user of the Notification.', }) - public notifierId: User['id'] | null; + public notifierId: User["id"] | null; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -52,19 +59,19 @@ export class Notification { public notifier: User | null; /** - * 通知の種類。 - * follow - フォローされた - * mention - 投稿で自分が言及された - * reply - (自分または自分がWatchしている)投稿が返信された - * renote - (自分または自分がWatchしている)投稿がRenoteされた - * quote - (自分または自分がWatchしている)投稿が引用Renoteされた + * Notification types: + * follow - Follow request + * mention - User was referenced in a post. + * reply - A post that a user made (or was watching) has been replied to. + * renote - A post that a user made (or was watching) has been renoted. + * quote - A post that a user made (or was watching) has been quoted and renoted. * reaction - (自分または自分がWatchしている)投稿にリアクションされた * pollVote - (自分または自分がWatchしている)投稿のアンケートに投票された * pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した * receiveFollowRequest - フォローリクエストされた - * followRequestAccepted - 自分の送ったフォローリクエストが承認された + * followRequestAccepted - A follow request has been accepted. * groupInvited - グループに招待された - * app - アプリ通知 + * app - App notifications. */ @Index() @Column('enum', { @@ -74,12 +81,12 @@ export class Notification { public type: typeof notificationTypes[number]; /** - * 通知が読まれたかどうか + * Whether the notification was read. */ @Index() @Column('boolean', { default: false, - comment: 'Whether the Notification is read.', + comment: 'Whether the notification was read.', }) public isRead: boolean; @@ -87,7 +94,7 @@ export class Notification { ...id(), nullable: true, }) - public noteId: Note['id'] | null; + public noteId: Note["id"] | null; @ManyToOne(type => Note, { onDelete: 'CASCADE', @@ -99,7 +106,7 @@ export class Notification { ...id(), nullable: true, }) - public followRequestId: FollowRequest['id'] | null; + public followRequestId: FollowRequest["id"] | null; @ManyToOne(type => FollowRequest, { onDelete: 'CASCADE', @@ -111,7 +118,7 @@ export class Notification { ...id(), nullable: true, }) - public userGroupInvitationId: UserGroupInvitation['id'] | null; + public userGroupInvitationId: UserGroupInvitation["id"] | null; @ManyToOne(type => UserGroupInvitation, { onDelete: 'CASCADE', @@ -130,7 +137,7 @@ export class Notification { public choice: number | null; /** - * アプリ通知のbody + * App notification body */ @Column('varchar', { length: 2048, nullable: true, @@ -138,8 +145,8 @@ export class Notification { public customBody: string | null; /** - * アプリ通知のheader - * (省略時はアプリ名で表示されることを期待) + * App notification header + * (If omitted, it is expected to be displayed with the app name) */ @Column('varchar', { length: 256, nullable: true, @@ -147,8 +154,8 @@ export class Notification { public customHeader: string | null; /** - * アプリ通知のicon(URL) - * (省略時はアプリアイコンで表示されることを期待) + * App notification icon (URL) + * (If omitted, it is expected to be displayed as an app icon) */ @Column('varchar', { length: 1024, nullable: true, @@ -156,14 +163,14 @@ export class Notification { public customIcon: string | null; /** - * アプリ通知のアプリ(のトークン) + * App notification app (token for) */ @Index() @Column({ ...id(), nullable: true, }) - public appAccessTokenId: AccessToken['id'] | null; + public appAccessTokenId: AccessToken["id"] | null; @ManyToOne(type => AccessToken, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/page-like.ts b/packages/backend/src/models/entities/page-like.ts index 17f4ebf52..75f4dc49b 100644 --- a/packages/backend/src/models/entities/page-like.ts +++ b/packages/backend/src/models/entities/page-like.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { Page } from './page.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { Page } from "./page.js"; @Entity() @Index(['userId', 'pageId'], { unique: true }) @@ -14,7 +21,7 @@ export class PageLike { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -23,7 +30,7 @@ export class PageLike { public user: User | null; @Column(id()) - public pageId: Page['id']; + public pageId: Page["id"]; @ManyToOne(type => Page, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/page.ts b/packages/backend/src/models/entities/page.ts index fac59479e..5fe9f5208 100644 --- a/packages/backend/src/models/entities/page.ts +++ b/packages/backend/src/models/entities/page.ts @@ -1,7 +1,14 @@ -import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; -import { DriveFile } from './drive-file.js'; +import { + Entity, + Index, + JoinColumn, + Column, + PrimaryColumn, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; +import { DriveFile } from "./drive-file.js"; @Entity() @Index(['userId', 'name'], { unique: true }) @@ -58,7 +65,7 @@ export class Page { ...id(), comment: 'The ID of author.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -70,7 +77,7 @@ export class Page { ...id(), nullable: true, }) - public eyeCatchingImageId: DriveFile['id'] | null; + public eyeCatchingImageId: DriveFile["id"] | null; @ManyToOne(type => DriveFile, { onDelete: 'CASCADE', @@ -100,14 +107,14 @@ export class Page { * specified ... visibleUserIds で指定したユーザーのみ */ @Column('enum', { enum: ['public', 'followers', 'specified'] }) - public visibility: 'public' | 'followers' | 'specified'; + public visibility: "public" | "followers" | "specified"; @Index() @Column({ ...id(), array: true, default: '{}', }) - public visibleUserIds: User['id'][]; + public visibleUserIds: User["id"][]; @Column('integer', { default: 0, diff --git a/packages/backend/src/models/entities/password-reset-request.ts b/packages/backend/src/models/entities/password-reset-request.ts index 05e62cc5a..4c681d4f7 100644 --- a/packages/backend/src/models/entities/password-reset-request.ts +++ b/packages/backend/src/models/entities/password-reset-request.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { id } from '../id.js'; -import { User } from './user.js'; +import { + PrimaryColumn, + Entity, + Index, + Column, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { id } from "../id.js"; +import { User } from "./user.js"; @Entity() export class PasswordResetRequest { @@ -20,7 +27,7 @@ export class PasswordResetRequest { @Column({ ...id(), }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/poll-vote.ts b/packages/backend/src/models/entities/poll-vote.ts index fca1cd009..0649951cf 100644 --- a/packages/backend/src/models/entities/poll-vote.ts +++ b/packages/backend/src/models/entities/poll-vote.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { Note } from './note.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { Note } from "./note.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId', 'choice'], { unique: true }) @@ -17,7 +24,7 @@ export class PollVote { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -27,7 +34,7 @@ export class PollVote { @Index() @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/poll.ts b/packages/backend/src/models/entities/poll.ts index 83d0873cc..28a70b3c7 100644 --- a/packages/backend/src/models/entities/poll.ts +++ b/packages/backend/src/models/entities/poll.ts @@ -1,13 +1,20 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { id } from '../id.js'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { noteVisibilities } from '../../types.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + OneToOne, +} from "typeorm"; +import { id } from "../id.js"; +import { Note } from "./note.js"; +import type { User } from "./user.js"; +import { noteVisibilities } from "../../types.js"; @Entity() export class Poll { @PrimaryColumn(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @OneToOne(type => Note, { onDelete: 'CASCADE', @@ -24,7 +31,7 @@ export class Poll { public multiple: boolean; @Column('varchar', { - length: 128, array: true, default: '{}', + length: 256, array: true, default: '{}', }) public choices: string[]; @@ -45,7 +52,7 @@ export class Poll { ...id(), comment: '[Denormalized]', }) - public userId: User['id']; + public userId: User["id"]; @Index() @Column('varchar', { diff --git a/packages/backend/src/models/entities/promo-note.ts b/packages/backend/src/models/entities/promo-note.ts index d110b81e9..4daacd246 100644 --- a/packages/backend/src/models/entities/promo-note.ts +++ b/packages/backend/src/models/entities/promo-note.ts @@ -1,12 +1,19 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + OneToOne, +} from "typeorm"; +import { Note } from "./note.js"; +import type { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class PromoNote { @PrimaryColumn(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @OneToOne(type => Note, { onDelete: 'CASCADE', @@ -23,6 +30,6 @@ export class PromoNote { ...id(), comment: '[Denormalized]', }) - public userId: User['id']; + public userId: User["id"]; //#endregion } diff --git a/packages/backend/src/models/entities/promo-read.ts b/packages/backend/src/models/entities/promo-read.ts index a63b79cd1..5938bfde9 100644 --- a/packages/backend/src/models/entities/promo-read.ts +++ b/packages/backend/src/models/entities/promo-read.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { Note } from "./note.js"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -16,7 +23,7 @@ export class PromoRead { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -25,7 +32,7 @@ export class PromoRead { public user: User | null; @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/registration-tickets.ts b/packages/backend/src/models/entities/registration-tickets.ts index 139e40f85..af785fbc0 100644 --- a/packages/backend/src/models/entities/registration-tickets.ts +++ b/packages/backend/src/models/entities/registration-tickets.ts @@ -1,5 +1,5 @@ -import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id.js'; +import { PrimaryColumn, Entity, Index, Column } from "typeorm"; +import { id } from "../id.js"; @Entity() export class RegistrationTicket { diff --git a/packages/backend/src/models/entities/registry-item.ts b/packages/backend/src/models/entities/registry-item.ts index 283796df9..655573883 100644 --- a/packages/backend/src/models/entities/registry-item.ts +++ b/packages/backend/src/models/entities/registry-item.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; // TODO: 同じdomain、同じscope、同じkeyのレコードは二つ以上存在しないように制約付けたい @Entity() @@ -23,7 +30,7 @@ export class RegistryItem { ...id(), comment: 'The owner ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/relay.ts b/packages/backend/src/models/entities/relay.ts index 94d192957..82c0779ff 100644 --- a/packages/backend/src/models/entities/relay.ts +++ b/packages/backend/src/models/entities/relay.ts @@ -1,5 +1,5 @@ -import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id.js'; +import { PrimaryColumn, Entity, Index, Column } from "typeorm"; +import { id } from "../id.js"; @Entity() export class Relay { @@ -15,5 +15,5 @@ export class Relay { @Column('enum', { enum: ['requesting', 'accepted', 'rejected'], }) - public status: 'requesting' | 'accepted' | 'rejected'; + public status: "requesting" | "accepted" | "rejected"; } diff --git a/packages/backend/src/models/entities/signin.ts b/packages/backend/src/models/entities/signin.ts index ba81f45e4..785991823 100644 --- a/packages/backend/src/models/entities/signin.ts +++ b/packages/backend/src/models/entities/signin.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class Signin { @@ -14,7 +21,7 @@ export class Signin { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/sw-subscription.ts b/packages/backend/src/models/entities/sw-subscription.ts index 59144d348..26891c1ce 100644 --- a/packages/backend/src/models/entities/sw-subscription.ts +++ b/packages/backend/src/models/entities/sw-subscription.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class SwSubscription { @@ -12,7 +19,7 @@ export class SwSubscription { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/used-username.ts b/packages/backend/src/models/entities/used-username.ts index eb90bef6c..a069205a5 100644 --- a/packages/backend/src/models/entities/used-username.ts +++ b/packages/backend/src/models/entities/used-username.ts @@ -1,4 +1,4 @@ -import { PrimaryColumn, Entity, Column } from 'typeorm'; +import { PrimaryColumn, Entity, Column } from "typeorm"; @Entity() export class UsedUsername { diff --git a/packages/backend/src/models/entities/user-group-invitation.ts b/packages/backend/src/models/entities/user-group-invitation.ts index 10f357049..8037b30e1 100644 --- a/packages/backend/src/models/entities/user-group-invitation.ts +++ b/packages/backend/src/models/entities/user-group-invitation.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { UserGroup } from './user-group.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { UserGroup } from "./user-group.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'userGroupId'], { unique: true }) @@ -19,7 +26,7 @@ export class UserGroupInvitation { ...id(), comment: 'The user ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -32,7 +39,7 @@ export class UserGroupInvitation { ...id(), comment: 'The group ID.', }) - public userGroupId: UserGroup['id']; + public userGroupId: UserGroup["id"]; @ManyToOne(type => UserGroup, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-group-joining.ts b/packages/backend/src/models/entities/user-group-joining.ts index 62a814218..6d503b274 100644 --- a/packages/backend/src/models/entities/user-group-joining.ts +++ b/packages/backend/src/models/entities/user-group-joining.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { UserGroup } from './user-group.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { UserGroup } from "./user-group.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'userGroupId'], { unique: true }) @@ -19,7 +26,7 @@ export class UserGroupJoining { ...id(), comment: 'The user ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -32,7 +39,7 @@ export class UserGroupJoining { ...id(), comment: 'The group ID.', }) - public userGroupId: UserGroup['id']; + public userGroupId: UserGroup["id"]; @ManyToOne(type => UserGroup, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-group.ts b/packages/backend/src/models/entities/user-group.ts index 8d5de1d92..38e5af334 100644 --- a/packages/backend/src/models/entities/user-group.ts +++ b/packages/backend/src/models/entities/user-group.ts @@ -1,6 +1,13 @@ -import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + Entity, + Index, + JoinColumn, + Column, + PrimaryColumn, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class UserGroup { @@ -23,7 +30,7 @@ export class UserGroup { ...id(), comment: 'The ID of owner.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-ip.ts b/packages/backend/src/models/entities/user-ip.ts index 543e9e728..6b88d5221 100644 --- a/packages/backend/src/models/entities/user-ip.ts +++ b/packages/backend/src/models/entities/user-ip.ts @@ -1,7 +1,15 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; -import { id } from '../id.js'; -import { Note } from './note.js'; -import { User } from './user.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, + PrimaryGeneratedColumn, +} from "typeorm"; +import { id } from "../id.js"; +import { Note } from "./note.js"; +import type { User } from "./user.js"; @Entity() @Index(['userId', 'ip'], { unique: true }) @@ -15,7 +23,7 @@ export class UserIp { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @Column('varchar', { length: 128, diff --git a/packages/backend/src/models/entities/user-keypair.ts b/packages/backend/src/models/entities/user-keypair.ts index 85fa06297..212e742b9 100644 --- a/packages/backend/src/models/entities/user-keypair.ts +++ b/packages/backend/src/models/entities/user-keypair.ts @@ -1,11 +1,11 @@ -import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class UserKeypair { @PrimaryColumn(id()) - public userId: User['id']; + public userId: User["id"]; @OneToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-list-joining.ts b/packages/backend/src/models/entities/user-list-joining.ts index 12f28c414..e52fa7b39 100644 --- a/packages/backend/src/models/entities/user-list-joining.ts +++ b/packages/backend/src/models/entities/user-list-joining.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { UserList } from './user-list.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { UserList } from "./user-list.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'userListId'], { unique: true }) @@ -19,7 +26,7 @@ export class UserListJoining { ...id(), comment: 'The user ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -32,7 +39,7 @@ export class UserListJoining { ...id(), comment: 'The list ID.', }) - public userListId: UserList['id']; + public userListId: UserList["id"]; @ManyToOne(type => UserList, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-list.ts b/packages/backend/src/models/entities/user-list.ts index ca69394e9..7c4345230 100644 --- a/packages/backend/src/models/entities/user-list.ts +++ b/packages/backend/src/models/entities/user-list.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class UserList { @@ -17,7 +24,7 @@ export class UserList { ...id(), comment: 'The owner ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-note-pining.ts b/packages/backend/src/models/entities/user-note-pining.ts index c91ab7fdd..dc6d61f7e 100644 --- a/packages/backend/src/models/entities/user-note-pining.ts +++ b/packages/backend/src/models/entities/user-note-pining.ts @@ -1,7 +1,14 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note.js'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { Note } from "./note.js"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() @Index(['userId', 'noteId'], { unique: true }) @@ -16,7 +23,7 @@ export class UserNotePining { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -25,7 +32,7 @@ export class UserNotePining { public user: User | null; @Column(id()) - public noteId: Note['id']; + public noteId: Note["id"]; @ManyToOne(type => Note, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-pending.ts b/packages/backend/src/models/entities/user-pending.ts index 763794884..cac85d1c0 100644 --- a/packages/backend/src/models/entities/user-pending.ts +++ b/packages/backend/src/models/entities/user-pending.ts @@ -1,5 +1,5 @@ -import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id.js'; +import { PrimaryColumn, Entity, Index, Column } from "typeorm"; +import { id } from "../id.js"; @Entity() export class UserPending { diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts index 3654b0a99..cc3d23867 100644 --- a/packages/backend/src/models/entities/user-profile.ts +++ b/packages/backend/src/models/entities/user-profile.ts @@ -1,15 +1,22 @@ -import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { ffVisibility, notificationTypes } from '@/types.js'; -import { id } from '../id.js'; -import { User } from './user.js'; -import { Page } from './page.js'; +import { + Entity, + Column, + Index, + OneToOne, + JoinColumn, + PrimaryColumn, +} from "typeorm"; +import { ffVisibility, notificationTypes } from "@/types.js"; +import { id } from "../id.js"; +import { User } from "./user.js"; +import { Page } from "./page.js"; // TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも // ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン @Entity() export class UserProfile { @PrimaryColumn(id()) - public userId: User['id']; + public userId: User["id"]; @OneToOne(type => User, { onDelete: 'CASCADE', @@ -176,7 +183,7 @@ export class UserProfile { ...id(), nullable: true, }) - public pinnedPageId: Page['id'] | null; + public pinnedPageId: Page["id"] | null; @OneToOne(type => Page, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/user-publickey.ts b/packages/backend/src/models/entities/user-publickey.ts index 31ed60de8..d1a9239d1 100644 --- a/packages/backend/src/models/entities/user-publickey.ts +++ b/packages/backend/src/models/entities/user-publickey.ts @@ -1,11 +1,18 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + OneToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class UserPublickey { @PrimaryColumn(id()) - public userId: User['id']; + public userId: User["id"]; @OneToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user-security-key.ts b/packages/backend/src/models/entities/user-security-key.ts index c4f2a852e..3b9d925d9 100644 --- a/packages/backend/src/models/entities/user-security-key.ts +++ b/packages/backend/src/models/entities/user-security-key.ts @@ -1,6 +1,13 @@ -import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + JoinColumn, + Column, + ManyToOne, + Index, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; @Entity() export class UserSecurityKey { @@ -11,7 +18,7 @@ export class UserSecurityKey { @Index() @Column(id()) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 3e406bdd7..c57ad916c 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -1,6 +1,13 @@ -import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { id } from '../id.js'; -import { DriveFile } from './drive-file.js'; +import { + Entity, + Column, + Index, + OneToOne, + JoinColumn, + PrimaryColumn, +} from "typeorm"; +import { id } from "../id.js"; +import { DriveFile } from "./drive-file.js"; @Entity() @Index(['usernameLower', 'host'], { unique: true }) @@ -92,7 +99,7 @@ export class User { nullable: true, comment: 'The ID of avatar DriveFile.', }) - public avatarId: DriveFile['id'] | null; + public avatarId: DriveFile["id"] | null; @OneToOne(type => DriveFile, { onDelete: 'SET NULL', @@ -105,7 +112,7 @@ export class User { nullable: true, comment: 'The ID of banner DriveFile.', }) - public bannerId: DriveFile['id'] | null; + public bannerId: DriveFile["id"] | null; @OneToOne(type => DriveFile, { onDelete: 'SET NULL', diff --git a/packages/backend/src/models/entities/webhook.ts b/packages/backend/src/models/entities/webhook.ts index 56b411f87..5db51c3a3 100644 --- a/packages/backend/src/models/entities/webhook.ts +++ b/packages/backend/src/models/entities/webhook.ts @@ -1,8 +1,24 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user.js'; -import { id } from '../id.js'; +import { + PrimaryColumn, + Entity, + Index, + JoinColumn, + Column, + ManyToOne, +} from "typeorm"; +import { User } from "./user.js"; +import { id } from "../id.js"; -export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction'] as const; +export const webhookEventTypes = [ + "mention", + "unfollow", + "follow", + "followed", + "note", + "reply", + "renote", + "reaction", +] as const; @Entity() export class Webhook { @@ -19,7 +35,7 @@ export class Webhook { ...id(), comment: 'The owner ID.', }) - public userId: User['id']; + public userId: User["id"]; @ManyToOne(type => User, { onDelete: 'CASCADE', @@ -37,7 +53,7 @@ export class Webhook { @Column('varchar', { length: 128, array: true, default: '{}', }) - public on: (typeof webhookEventTypes)[number][]; + public on: typeof webhookEventTypes[number][]; @Column('varchar', { length: 1024, diff --git a/packages/backend/src/models/id.ts b/packages/backend/src/models/id.ts index d614fc504..7e5a78798 100644 --- a/packages/backend/src/models/id.ts +++ b/packages/backend/src/models/id.ts @@ -1,4 +1,4 @@ export const id = () => ({ - type: 'varchar' as const, + type: "varchar" as const, length: 32, }); diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index 3f7326931..98f6705f4 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -1,130 +1,130 @@ -import { } from 'typeorm'; -import { db } from '@/db/postgre.js'; +import {} from "typeorm"; +import { db } from "@/db/postgre.js"; -import { Announcement } from './entities/announcement.js'; -import { AnnouncementRead } from './entities/announcement-read.js'; -import { Instance } from './entities/instance.js'; -import { Poll } from './entities/poll.js'; -import { PollVote } from './entities/poll-vote.js'; -import { Meta } from './entities/meta.js'; -import { SwSubscription } from './entities/sw-subscription.js'; -import { NoteWatching } from './entities/note-watching.js'; -import { NoteThreadMuting } from './entities/note-thread-muting.js'; -import { NoteUnread } from './entities/note-unread.js'; -import { RegistrationTicket } from './entities/registration-tickets.js'; -import { UserRepository } from './repositories/user.js'; -import { NoteRepository } from './repositories/note.js'; -import { DriveFileRepository } from './repositories/drive-file.js'; -import { DriveFolderRepository } from './repositories/drive-folder.js'; -import { AccessToken } from './entities/access-token.js'; -import { UserNotePining } from './entities/user-note-pining.js'; -import { SigninRepository } from './repositories/signin.js'; -import { MessagingMessageRepository } from './repositories/messaging-message.js'; -import { UserListRepository } from './repositories/user-list.js'; -import { UserListJoining } from './entities/user-list-joining.js'; -import { UserGroupRepository } from './repositories/user-group.js'; -import { UserGroupJoining } from './entities/user-group-joining.js'; -import { UserGroupInvitationRepository } from './repositories/user-group-invitation.js'; -import { FollowRequestRepository } from './repositories/follow-request.js'; -import { MutingRepository } from './repositories/muting.js'; -import { BlockingRepository } from './repositories/blocking.js'; -import { NoteReactionRepository } from './repositories/note-reaction.js'; -import { NotificationRepository } from './repositories/notification.js'; -import { NoteFavoriteRepository } from './repositories/note-favorite.js'; -import { UserPublickey } from './entities/user-publickey.js'; -import { UserKeypair } from './entities/user-keypair.js'; -import { AppRepository } from './repositories/app.js'; -import { FollowingRepository } from './repositories/following.js'; -import { AbuseUserReportRepository } from './repositories/abuse-user-report.js'; -import { AuthSessionRepository } from './repositories/auth-session.js'; -import { UserProfile } from './entities/user-profile.js'; -import { AttestationChallenge } from './entities/attestation-challenge.js'; -import { UserSecurityKey } from './entities/user-security-key.js'; -import { HashtagRepository } from './repositories/hashtag.js'; -import { PageRepository } from './repositories/page.js'; -import { PageLikeRepository } from './repositories/page-like.js'; -import { GalleryPostRepository } from './repositories/gallery-post.js'; -import { GalleryLikeRepository } from './repositories/gallery-like.js'; -import { ModerationLogRepository } from './repositories/moderation-logs.js'; -import { UsedUsername } from './entities/used-username.js'; -import { ClipRepository } from './repositories/clip.js'; -import { ClipNote } from './entities/clip-note.js'; -import { AntennaRepository } from './repositories/antenna.js'; -import { AntennaNote } from './entities/antenna-note.js'; -import { PromoNote } from './entities/promo-note.js'; -import { PromoRead } from './entities/promo-read.js'; -import { EmojiRepository } from './repositories/emoji.js'; -import { RelayRepository } from './repositories/relay.js'; -import { ChannelRepository } from './repositories/channel.js'; -import { MutedNote } from './entities/muted-note.js'; -import { ChannelFollowing } from './entities/channel-following.js'; -import { ChannelNotePining } from './entities/channel-note-pining.js'; -import { RegistryItem } from './entities/registry-item.js'; -import { Ad } from './entities/ad.js'; -import { PasswordResetRequest } from './entities/password-reset-request.js'; -import { UserPending } from './entities/user-pending.js'; -import { InstanceRepository } from './repositories/instance.js'; -import { Webhook } from './entities/webhook.js'; -import { UserIp } from './entities/user-ip.js'; +import { Announcement } from "./entities/announcement.js"; +import { AnnouncementRead } from "./entities/announcement-read.js"; +import { Instance } from "./entities/instance.js"; +import { Poll } from "./entities/poll.js"; +import { PollVote } from "./entities/poll-vote.js"; +import { Meta } from "./entities/meta.js"; +import { SwSubscription } from "./entities/sw-subscription.js"; +import { NoteWatching } from "./entities/note-watching.js"; +import { NoteThreadMuting } from "./entities/note-thread-muting.js"; +import { NoteUnread } from "./entities/note-unread.js"; +import { RegistrationTicket } from "./entities/registration-tickets.js"; +import { UserRepository } from "./repositories/user.js"; +import { NoteRepository } from "./repositories/note.js"; +import { DriveFileRepository } from "./repositories/drive-file.js"; +import { DriveFolderRepository } from "./repositories/drive-folder.js"; +import { AccessToken } from "./entities/access-token.js"; +import { UserNotePining } from "./entities/user-note-pining.js"; +import { SigninRepository } from "./repositories/signin.js"; +import { MessagingMessageRepository } from "./repositories/messaging-message.js"; +import { UserListRepository } from "./repositories/user-list.js"; +import { UserListJoining } from "./entities/user-list-joining.js"; +import { UserGroupRepository } from "./repositories/user-group.js"; +import { UserGroupJoining } from "./entities/user-group-joining.js"; +import { UserGroupInvitationRepository } from "./repositories/user-group-invitation.js"; +import { FollowRequestRepository } from "./repositories/follow-request.js"; +import { MutingRepository } from "./repositories/muting.js"; +import { BlockingRepository } from "./repositories/blocking.js"; +import { NoteReactionRepository } from "./repositories/note-reaction.js"; +import { NotificationRepository } from "./repositories/notification.js"; +import { NoteFavoriteRepository } from "./repositories/note-favorite.js"; +import { UserPublickey } from "./entities/user-publickey.js"; +import { UserKeypair } from "./entities/user-keypair.js"; +import { AppRepository } from "./repositories/app.js"; +import { FollowingRepository } from "./repositories/following.js"; +import { AbuseUserReportRepository } from "./repositories/abuse-user-report.js"; +import { AuthSessionRepository } from "./repositories/auth-session.js"; +import { UserProfile } from "./entities/user-profile.js"; +import { AttestationChallenge } from "./entities/attestation-challenge.js"; +import { UserSecurityKey } from "./entities/user-security-key.js"; +import { HashtagRepository } from "./repositories/hashtag.js"; +import { PageRepository } from "./repositories/page.js"; +import { PageLikeRepository } from "./repositories/page-like.js"; +import { GalleryPostRepository } from "./repositories/gallery-post.js"; +import { GalleryLikeRepository } from "./repositories/gallery-like.js"; +import { ModerationLogRepository } from "./repositories/moderation-logs.js"; +import { UsedUsername } from "./entities/used-username.js"; +import { ClipRepository } from "./repositories/clip.js"; +import { ClipNote } from "./entities/clip-note.js"; +import { AntennaRepository } from "./repositories/antenna.js"; +import { AntennaNote } from "./entities/antenna-note.js"; +import { PromoNote } from "./entities/promo-note.js"; +import { PromoRead } from "./entities/promo-read.js"; +import { EmojiRepository } from "./repositories/emoji.js"; +import { RelayRepository } from "./repositories/relay.js"; +import { ChannelRepository } from "./repositories/channel.js"; +import { MutedNote } from "./entities/muted-note.js"; +import { ChannelFollowing } from "./entities/channel-following.js"; +import { ChannelNotePining } from "./entities/channel-note-pining.js"; +import { RegistryItem } from "./entities/registry-item.js"; +import { Ad } from "./entities/ad.js"; +import { PasswordResetRequest } from "./entities/password-reset-request.js"; +import { UserPending } from "./entities/user-pending.js"; +import { InstanceRepository } from "./repositories/instance.js"; +import { Webhook } from "./entities/webhook.js"; +import { UserIp } from "./entities/user-ip.js"; export const Announcements = db.getRepository(Announcement); export const AnnouncementReads = db.getRepository(AnnouncementRead); -export const Apps = (AppRepository); -export const Notes = (NoteRepository); -export const NoteFavorites = (NoteFavoriteRepository); +export const Apps = AppRepository; +export const Notes = NoteRepository; +export const NoteFavorites = NoteFavoriteRepository; export const NoteWatchings = db.getRepository(NoteWatching); export const NoteThreadMutings = db.getRepository(NoteThreadMuting); -export const NoteReactions = (NoteReactionRepository); +export const NoteReactions = NoteReactionRepository; export const NoteUnreads = db.getRepository(NoteUnread); export const Polls = db.getRepository(Poll); export const PollVotes = db.getRepository(PollVote); -export const Users = (UserRepository); +export const Users = UserRepository; export const UserProfiles = db.getRepository(UserProfile); export const UserKeypairs = db.getRepository(UserKeypair); export const UserPendings = db.getRepository(UserPending); export const AttestationChallenges = db.getRepository(AttestationChallenge); export const UserSecurityKeys = db.getRepository(UserSecurityKey); export const UserPublickeys = db.getRepository(UserPublickey); -export const UserLists = (UserListRepository); +export const UserLists = UserListRepository; export const UserListJoinings = db.getRepository(UserListJoining); -export const UserGroups = (UserGroupRepository); +export const UserGroups = UserGroupRepository; export const UserGroupJoinings = db.getRepository(UserGroupJoining); -export const UserGroupInvitations = (UserGroupInvitationRepository); +export const UserGroupInvitations = UserGroupInvitationRepository; export const UserNotePinings = db.getRepository(UserNotePining); export const UserIps = db.getRepository(UserIp); export const UsedUsernames = db.getRepository(UsedUsername); -export const Followings = (FollowingRepository); -export const FollowRequests = (FollowRequestRepository); -export const Instances = (InstanceRepository); -export const Emojis = (EmojiRepository); -export const DriveFiles = (DriveFileRepository); -export const DriveFolders = (DriveFolderRepository); -export const Notifications = (NotificationRepository); +export const Followings = FollowingRepository; +export const FollowRequests = FollowRequestRepository; +export const Instances = InstanceRepository; +export const Emojis = EmojiRepository; +export const DriveFiles = DriveFileRepository; +export const DriveFolders = DriveFolderRepository; +export const Notifications = NotificationRepository; export const Metas = db.getRepository(Meta); -export const Mutings = (MutingRepository); -export const Blockings = (BlockingRepository); +export const Mutings = MutingRepository; +export const Blockings = BlockingRepository; export const SwSubscriptions = db.getRepository(SwSubscription); -export const Hashtags = (HashtagRepository); -export const AbuseUserReports = (AbuseUserReportRepository); +export const Hashtags = HashtagRepository; +export const AbuseUserReports = AbuseUserReportRepository; export const RegistrationTickets = db.getRepository(RegistrationTicket); -export const AuthSessions = (AuthSessionRepository); +export const AuthSessions = AuthSessionRepository; export const AccessTokens = db.getRepository(AccessToken); -export const Signins = (SigninRepository); -export const MessagingMessages = (MessagingMessageRepository); -export const Pages = (PageRepository); -export const PageLikes = (PageLikeRepository); -export const GalleryPosts = (GalleryPostRepository); -export const GalleryLikes = (GalleryLikeRepository); -export const ModerationLogs = (ModerationLogRepository); -export const Clips = (ClipRepository); +export const Signins = SigninRepository; +export const MessagingMessages = MessagingMessageRepository; +export const Pages = PageRepository; +export const PageLikes = PageLikeRepository; +export const GalleryPosts = GalleryPostRepository; +export const GalleryLikes = GalleryLikeRepository; +export const ModerationLogs = ModerationLogRepository; +export const Clips = ClipRepository; export const ClipNotes = db.getRepository(ClipNote); -export const Antennas = (AntennaRepository); +export const Antennas = AntennaRepository; export const AntennaNotes = db.getRepository(AntennaNote); export const PromoNotes = db.getRepository(PromoNote); export const PromoReads = db.getRepository(PromoRead); -export const Relays = (RelayRepository); +export const Relays = RelayRepository; export const MutedNotes = db.getRepository(MutedNote); -export const Channels = (ChannelRepository); +export const Channels = ChannelRepository; export const ChannelFollowings = db.getRepository(ChannelFollowing); export const ChannelNotePinings = db.getRepository(ChannelNotePining); export const RegistryItems = db.getRepository(RegistryItem); diff --git a/packages/backend/src/models/repositories/abuse-user-report.ts b/packages/backend/src/models/repositories/abuse-user-report.ts index 36d7ab90c..07afef48c 100644 --- a/packages/backend/src/models/repositories/abuse-user-report.ts +++ b/packages/backend/src/models/repositories/abuse-user-report.ts @@ -1,38 +1,39 @@ -import { db } from '@/db/postgre.js'; -import { Users } from '../index.js'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; -import { awaitAll } from '@/prelude/await-all.js'; +import { db } from "@/db/postgre.js"; +import { Users } from "../index.js"; +import { AbuseUserReport } from "@/models/entities/abuse-user-report.js"; +import { awaitAll } from "@/prelude/await-all.js"; -export const AbuseUserReportRepository = db.getRepository(AbuseUserReport).extend({ - async pack( - src: AbuseUserReport['id'] | AbuseUserReport, - ) { - const report = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); +export const AbuseUserReportRepository = db + .getRepository(AbuseUserReport) + .extend({ + async pack(src: AbuseUserReport["id"] | AbuseUserReport) { + const report = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - return await awaitAll({ - id: report.id, - createdAt: report.createdAt.toISOString(), - comment: report.comment, - resolved: report.resolved, - reporterId: report.reporterId, - targetUserId: report.targetUserId, - assigneeId: report.assigneeId, - reporter: Users.pack(report.reporter || report.reporterId, null, { - detail: true, - }), - targetUser: Users.pack(report.targetUser || report.targetUserId, null, { - detail: true, - }), - assignee: report.assigneeId ? Users.pack(report.assignee || report.assigneeId, null, { - detail: true, - }) : null, - forwarded: report.forwarded, - }); - }, + return await awaitAll({ + id: report.id, + createdAt: report.createdAt.toISOString(), + comment: report.comment, + resolved: report.resolved, + reporterId: report.reporterId, + targetUserId: report.targetUserId, + assigneeId: report.assigneeId, + reporter: Users.pack(report.reporter || report.reporterId, null, { + detail: true, + }), + targetUser: Users.pack(report.targetUser || report.targetUserId, null, { + detail: true, + }), + assignee: report.assigneeId + ? Users.pack(report.assignee || report.assigneeId, null, { + detail: true, + }) + : null, + forwarded: report.forwarded, + }); + }, - packMany( - reports: any[], - ) { - return Promise.all(reports.map(x => this.pack(x))); - }, -}); + packMany(reports: any[]) { + return Promise.all(reports.map((x) => this.pack(x))); + }, + }); diff --git a/packages/backend/src/models/repositories/antenna.ts b/packages/backend/src/models/repositories/antenna.ts index 70180e2de..57ce2fc9e 100644 --- a/packages/backend/src/models/repositories/antenna.ts +++ b/packages/backend/src/models/repositories/antenna.ts @@ -1,16 +1,19 @@ -import { db } from '@/db/postgre.js'; -import { Antenna } from '@/models/entities/antenna.js'; -import { Packed } from '@/misc/schema.js'; -import { AntennaNotes, UserGroupJoinings } from '../index.js'; +import { db } from "@/db/postgre.js"; +import { Antenna } from "@/models/entities/antenna.js"; +import type { Packed } from "@/misc/schema.js"; +import { AntennaNotes, UserGroupJoinings } from "../index.js"; export const AntennaRepository = db.getRepository(Antenna).extend({ - async pack( - src: Antenna['id'] | Antenna, - ): Promise> { - const antenna = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: Antenna["id"] | Antenna): Promise> { + const antenna = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - const hasUnreadNote = (await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) != null; - const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId }) : null; + const hasUnreadNote = + (await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) != + null; + const userGroupJoining = antenna.userGroupJoiningId + ? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId }) + : null; return { id: antenna.id, diff --git a/packages/backend/src/models/repositories/app.ts b/packages/backend/src/models/repositories/app.ts index e08dd6f0e..af3dfb81a 100644 --- a/packages/backend/src/models/repositories/app.ts +++ b/packages/backend/src/models/repositories/app.ts @@ -1,26 +1,30 @@ -import { db } from '@/db/postgre.js'; -import { App } from '@/models/entities/app.js'; -import { AccessTokens } from '../index.js'; -import { Packed } from '@/misc/schema.js'; -import { User } from '../entities/user.js'; +import { db } from "@/db/postgre.js"; +import { App } from "@/models/entities/app.js"; +import { AccessTokens } from "../index.js"; +import type { Packed } from "@/misc/schema.js"; +import type { User } from "../entities/user.js"; export const AppRepository = db.getRepository(App).extend({ async pack( - src: App['id'] | App, - me?: { id: User['id'] } | null | undefined, + src: App["id"] | App, + me?: { id: User["id"] } | null | undefined, options?: { - detail?: boolean, - includeSecret?: boolean, - includeProfileImageIds?: boolean - } - ): Promise> { - const opts = Object.assign({ - detail: false, - includeSecret: false, - includeProfileImageIds: false, - }, options); + detail?: boolean; + includeSecret?: boolean; + includeProfileImageIds?: boolean; + }, + ): Promise> { + const opts = Object.assign( + { + detail: false, + includeSecret: false, + includeProfileImageIds: false, + }, + options, + ); - const app = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const app = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: app.id, @@ -28,12 +32,14 @@ export const AppRepository = db.getRepository(App).extend({ callbackUrl: app.callbackUrl, permission: app.permission, ...(opts.includeSecret ? { secret: app.secret } : {}), - ...(me ? { - isAuthorized: await AccessTokens.countBy({ - appId: app.id, - userId: me.id, - }).then(count => count > 0), - } : {}), + ...(me + ? { + isAuthorized: await AccessTokens.countBy({ + appId: app.id, + userId: me.id, + }).then((count) => count > 0), + } + : {}), }; }, }); diff --git a/packages/backend/src/models/repositories/auth-session.ts b/packages/backend/src/models/repositories/auth-session.ts index 3f1f6f489..d3e1d45d6 100644 --- a/packages/backend/src/models/repositories/auth-session.ts +++ b/packages/backend/src/models/repositories/auth-session.ts @@ -1,15 +1,16 @@ -import { db } from '@/db/postgre.js'; -import { Apps } from '../index.js'; -import { AuthSession } from '@/models/entities/auth-session.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { Apps } from "../index.js"; +import { AuthSession } from "@/models/entities/auth-session.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { User } from "@/models/entities/user.js"; export const AuthSessionRepository = db.getRepository(AuthSession).extend({ async pack( - src: AuthSession['id'] | AuthSession, - me?: { id: User['id'] } | null | undefined + src: AuthSession["id"] | AuthSession, + me?: { id: User["id"] } | null | undefined, ) { - const session = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const session = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: session.id, diff --git a/packages/backend/src/models/repositories/blocking.ts b/packages/backend/src/models/repositories/blocking.ts index 1d569fb87..3dfa74e76 100644 --- a/packages/backend/src/models/repositories/blocking.ts +++ b/packages/backend/src/models/repositories/blocking.ts @@ -1,16 +1,17 @@ -import { db } from '@/db/postgre.js'; -import { Users } from '../index.js'; -import { Blocking } from '@/models/entities/blocking.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { Packed } from '@/misc/schema.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { Users } from "../index.js"; +import { Blocking } from "@/models/entities/blocking.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import type { User } from "@/models/entities/user.js"; export const BlockingRepository = db.getRepository(Blocking).extend({ async pack( - src: Blocking['id'] | Blocking, - me?: { id: User['id'] } | null | undefined - ): Promise> { - const blocking = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + src: Blocking["id"] | Blocking, + me?: { id: User["id"] } | null | undefined, + ): Promise> { + const blocking = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: blocking.id, @@ -22,10 +23,7 @@ export const BlockingRepository = db.getRepository(Blocking).extend({ }); }, - packMany( - blockings: any[], - me: { id: User['id'] } - ) { - return Promise.all(blockings.map(x => this.pack(x, me))); + packMany(blockings: any[], me: { id: User["id"] }) { + return Promise.all(blockings.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/channel.ts b/packages/backend/src/models/repositories/channel.ts index 213ac3671..7800a6594 100644 --- a/packages/backend/src/models/repositories/channel.ts +++ b/packages/backend/src/models/repositories/channel.ts @@ -1,30 +1,42 @@ -import { db } from '@/db/postgre.js'; -import { Channel } from '@/models/entities/channel.js'; -import { Packed } from '@/misc/schema.js'; -import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { Channel } from "@/models/entities/channel.js"; +import type { Packed } from "@/misc/schema.js"; +import { DriveFiles, ChannelFollowings, NoteUnreads } from "../index.js"; +import type { User } from "@/models/entities/user.js"; export const ChannelRepository = db.getRepository(Channel).extend({ async pack( - src: Channel['id'] | Channel, - me?: { id: User['id'] } | null | undefined, - ): Promise> { - const channel = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + src: Channel["id"] | Channel, + me?: { id: User["id"] } | null | undefined, + ): Promise> { + const channel = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); const meId = me ? me.id : null; - const banner = channel.bannerId ? await DriveFiles.findOneBy({ id: channel.bannerId }) : null; + const banner = channel.bannerId + ? await DriveFiles.findOneBy({ id: channel.bannerId }) + : null; - const hasUnreadNote = meId ? (await NoteUnreads.findOneBy({ noteChannelId: channel.id, userId: meId })) != null : undefined; + const hasUnreadNote = meId + ? (await NoteUnreads.findOneBy({ + noteChannelId: channel.id, + userId: meId, + })) != null + : undefined; - const following = meId ? await ChannelFollowings.findOneBy({ - followerId: meId, - followeeId: channel.id, - }) : null; + const following = meId + ? await ChannelFollowings.findOneBy({ + followerId: meId, + followeeId: channel.id, + }) + : null; return { id: channel.id, createdAt: channel.createdAt.toISOString(), - lastNotedAt: channel.lastNotedAt ? channel.lastNotedAt.toISOString() : null, + lastNotedAt: channel.lastNotedAt + ? channel.lastNotedAt.toISOString() + : null, name: channel.name, description: channel.description, userId: channel.userId, @@ -32,10 +44,12 @@ export const ChannelRepository = db.getRepository(Channel).extend({ usersCount: channel.usersCount, notesCount: channel.notesCount, - ...(me ? { - isFollowing: following != null, - hasUnreadNote, - } : {}), + ...(me + ? { + isFollowing: following != null, + hasUnreadNote, + } + : {}), }; }, }); diff --git a/packages/backend/src/models/repositories/clip.ts b/packages/backend/src/models/repositories/clip.ts index b4a342905..0c21691bf 100644 --- a/packages/backend/src/models/repositories/clip.ts +++ b/packages/backend/src/models/repositories/clip.ts @@ -1,14 +1,13 @@ -import { db } from '@/db/postgre.js'; -import { Clip } from '@/models/entities/clip.js'; -import { Packed } from '@/misc/schema.js'; -import { Users } from '../index.js'; -import { awaitAll } from '@/prelude/await-all.js'; +import { db } from "@/db/postgre.js"; +import { Clip } from "@/models/entities/clip.js"; +import type { Packed } from "@/misc/schema.js"; +import { Users } from "../index.js"; +import { awaitAll } from "@/prelude/await-all.js"; export const ClipRepository = db.getRepository(Clip).extend({ - async pack( - src: Clip['id'] | Clip, - ): Promise> { - const clip = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: Clip["id"] | Clip): Promise> { + const clip = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: clip.id, @@ -21,10 +20,7 @@ export const ClipRepository = db.getRepository(Clip).extend({ }); }, - packMany( - clips: Clip[], - ) { - return Promise.all(clips.map(x => this.pack(x))); + packMany(clips: Clip[]) { + return Promise.all(clips.map((x) => this.pack(x))); }, }); - diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts index a01fd86c6..3918f7947 100644 --- a/packages/backend/src/models/repositories/drive-file.ts +++ b/packages/backend/src/models/repositories/drive-file.ts @@ -1,39 +1,41 @@ -import { db } from '@/db/postgre.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { User } from '@/models/entities/user.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { awaitAll, Promiseable } from '@/prelude/await-all.js'; -import { Packed } from '@/misc/schema.js'; -import config from '@/config/index.js'; -import { query, appendQuery } from '@/prelude/url.js'; -import { Meta } from '@/models/entities/meta.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Users, DriveFolders } from '../index.js'; -import { deepClone } from '@/misc/clone.js'; - +import { db } from "@/db/postgre.js"; +import { DriveFile } from "@/models/entities/drive-file.js"; +import type { User } from "@/models/entities/user.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { awaitAll, Promiseable } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import config from "@/config/index.js"; +import { query, appendQuery } from "@/prelude/url.js"; +import { Meta } from "@/models/entities/meta.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Users, DriveFolders } from "../index.js"; +import { deepClone } from "@/misc/clone.js"; type PackOptions = { - detail?: boolean, - self?: boolean, - withUser?: boolean, + detail?: boolean; + self?: boolean; + withUser?: boolean; }; export const DriveFileRepository = db.getRepository(DriveFile).extend({ validateFileName(name: string): boolean { return ( - (name.trim().length > 0) && - (name.length <= 200) && - (name.indexOf('\\') === -1) && - (name.indexOf('/') === -1) && - (name.indexOf('..') === -1) + name.trim().length > 0 && + name.length <= 200 && + name.indexOf("\\") === -1 && + name.indexOf("/") === -1 && + name.indexOf("..") === -1 ); }, - getPublicProperties(file: DriveFile): DriveFile['properties'] { + getPublicProperties(file: DriveFile): DriveFile["properties"] { if (file.properties.orientation != null) { const properties = deepClone(file.properties); if (file.properties.orientation >= 5) { - [properties.width, properties.height] = [properties.height, properties.width]; + [properties.width, properties.height] = [ + properties.height, + properties.width, + ]; } properties.orientation = undefined; return properties; @@ -44,85 +46,107 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({ getPublicUrl(file: DriveFile, thumbnail = false): string | null { // リモートかつメディアプロキシ - if (file.uri != null && file.userHost != null && config.mediaProxy != null) { - return appendQuery(config.mediaProxy, query({ - url: file.uri, - thumbnail: thumbnail ? '1' : undefined, - })); + if ( + file.uri != null && + file.userHost != null && + config.mediaProxy != null + ) { + return appendQuery( + config.mediaProxy, + query({ + url: file.uri, + thumbnail: thumbnail ? "1" : undefined, + }), + ); } // リモートかつ期限切れはローカルプロキシを試みる if (file.uri != null && file.isLink && config.proxyRemoteFiles) { const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; - if (key && !key.match('/')) { // 古いものはここにオブジェクトストレージキーが入ってるので除外 + if (key && !key.match("/")) { + // 古いものはここにオブジェクトストレージキーが入ってるので除外 return `${config.url}/files/${key}`; } } - const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/svg+xml', 'image/avif'].includes(file.type); + const isImage = + file.type && + [ + "image/png", + "image/apng", + "image/gif", + "image/jpeg", + "image/webp", + "image/svg+xml", + "image/avif", + ].includes(file.type); - return thumbnail ? (file.thumbnailUrl || (isImage ? (file.webpublicUrl || file.url) : null)) : (file.webpublicUrl || file.url); + return thumbnail + ? file.thumbnailUrl || (isImage ? file.webpublicUrl || file.url : null) + : file.webpublicUrl || file.url; }, - async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise { - const id = typeof user === 'object' ? user.id : user; + async calcDriveUsageOf( + user: User["id"] | { id: User["id"] }, + ): Promise { + const id = typeof user === "object" ? user.id : user; - const { sum } = await this - .createQueryBuilder('file') - .where('file.userId = :id', { id: id }) - .andWhere('file.isLink = FALSE') - .select('SUM(file.size)', 'sum') + const { sum } = await this.createQueryBuilder("file") + .where("file.userId = :id", { id: id }) + .andWhere("file.isLink = FALSE") + .select("SUM(file.size)", "sum") .getRawOne(); return parseInt(sum, 10) || 0; }, async calcDriveUsageOfHost(host: string): Promise { - const { sum } = await this - .createQueryBuilder('file') - .where('file.userHost = :host', { host: toPuny(host) }) - .andWhere('file.isLink = FALSE') - .select('SUM(file.size)', 'sum') + const { sum } = await this.createQueryBuilder("file") + .where("file.userHost = :host", { host: toPuny(host) }) + .andWhere("file.isLink = FALSE") + .select("SUM(file.size)", "sum") .getRawOne(); return parseInt(sum, 10) || 0; }, async calcDriveUsageOfLocal(): Promise { - const { sum } = await this - .createQueryBuilder('file') - .where('file.userHost IS NULL') - .andWhere('file.isLink = FALSE') - .select('SUM(file.size)', 'sum') + const { sum } = await this.createQueryBuilder("file") + .where("file.userHost IS NULL") + .andWhere("file.isLink = FALSE") + .select("SUM(file.size)", "sum") .getRawOne(); return parseInt(sum, 10) || 0; }, async calcDriveUsageOfRemote(): Promise { - const { sum } = await this - .createQueryBuilder('file') - .where('file.userHost IS NOT NULL') - .andWhere('file.isLink = FALSE') - .select('SUM(file.size)', 'sum') + const { sum } = await this.createQueryBuilder("file") + .where("file.userHost IS NOT NULL") + .andWhere("file.isLink = FALSE") + .select("SUM(file.size)", "sum") .getRawOne(); return parseInt(sum, 10) || 0; }, async pack( - src: DriveFile['id'] | DriveFile, + src: DriveFile["id"] | DriveFile, options?: PackOptions, - ): Promise> { - const opts = Object.assign({ - detail: false, - self: false, - }, options); + ): Promise> { + const opts = Object.assign( + { + detail: false, + self: false, + }, + options, + ); - const file = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const file = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - return await awaitAll>({ + return await awaitAll>({ id: file.id, createdAt: file.createdAt.toISOString(), name: file.name, @@ -136,27 +160,34 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({ thumbnailUrl: this.getPublicUrl(file, true), comment: file.comment, folderId: file.folderId, - folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { - detail: true, - }) : null, + folder: + opts.detail && file.folderId + ? DriveFolders.pack(file.folderId, { + detail: true, + }) + : null, userId: opts.withUser ? file.userId : null, - user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null, + user: opts.withUser && file.userId ? Users.pack(file.userId) : null, }); }, async packNullable( - src: DriveFile['id'] | DriveFile, + src: DriveFile["id"] | DriveFile, options?: PackOptions, - ): Promise | null> { - const opts = Object.assign({ - detail: false, - self: false, - }, options); + ): Promise | null> { + const opts = Object.assign( + { + detail: false, + self: false, + }, + options, + ); - const file = typeof src === 'object' ? src : await this.findOneBy({ id: src }); + const file = + typeof src === "object" ? src : await this.findOneBy({ id: src }); if (file == null) return null; - return await awaitAll>({ + return await awaitAll>({ id: file.id, createdAt: file.createdAt.toISOString(), name: file.name, @@ -170,19 +201,24 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({ thumbnailUrl: this.getPublicUrl(file, true), comment: file.comment, folderId: file.folderId, - folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { - detail: true, - }) : null, + folder: + opts.detail && file.folderId + ? DriveFolders.pack(file.folderId, { + detail: true, + }) + : null, userId: opts.withUser ? file.userId : null, - user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null, + user: opts.withUser && file.userId ? Users.pack(file.userId) : null, }); }, async packMany( - files: (DriveFile['id'] | DriveFile)[], + files: (DriveFile["id"] | DriveFile)[], options?: PackOptions, - ): Promise[]> { - const items = await Promise.all(files.map(f => this.packNullable(f, options))); - return items.filter((x): x is Packed<'DriveFile'> => x != null); + ): Promise[]> { + const items = await Promise.all( + files.map((f) => this.packNullable(f, options)), + ); + return items.filter((x): x is Packed<"DriveFile"> => x != null); }, }); diff --git a/packages/backend/src/models/repositories/drive-folder.ts b/packages/backend/src/models/repositories/drive-folder.ts index ab5f3dab6..9823561d0 100644 --- a/packages/backend/src/models/repositories/drive-folder.ts +++ b/packages/backend/src/models/repositories/drive-folder.ts @@ -1,21 +1,25 @@ -import { db } from '@/db/postgre.js'; -import { DriveFolders, DriveFiles } from '../index.js'; -import { DriveFolder } from '@/models/entities/drive-folder.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { Packed } from '@/misc/schema.js'; +import { db } from "@/db/postgre.js"; +import { DriveFolders, DriveFiles } from "../index.js"; +import { DriveFolder } from "@/models/entities/drive-folder.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; export const DriveFolderRepository = db.getRepository(DriveFolder).extend({ async pack( - src: DriveFolder['id'] | DriveFolder, + src: DriveFolder["id"] | DriveFolder, options?: { - detail: boolean - } - ): Promise> { - const opts = Object.assign({ - detail: false, - }, options); + detail: boolean; + }, + ): Promise> { + const opts = Object.assign( + { + detail: false, + }, + options, + ); - const folder = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const folder = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: folder.id, @@ -23,20 +27,24 @@ export const DriveFolderRepository = db.getRepository(DriveFolder).extend({ name: folder.name, parentId: folder.parentId, - ...(opts.detail ? { - foldersCount: DriveFolders.countBy({ - parentId: folder.id, - }), - filesCount: DriveFiles.countBy({ - folderId: folder.id, - }), + ...(opts.detail + ? { + foldersCount: DriveFolders.countBy({ + parentId: folder.id, + }), + filesCount: DriveFiles.countBy({ + folderId: folder.id, + }), - ...(folder.parentId ? { - parent: this.pack(folder.parentId, { - detail: true, - }), - } : {}), - } : {}), + ...(folder.parentId + ? { + parent: this.pack(folder.parentId, { + detail: true, + }), + } + : {}), + } + : {}), }); }, }); diff --git a/packages/backend/src/models/repositories/emoji.ts b/packages/backend/src/models/repositories/emoji.ts index a0d390d79..e868fe94f 100644 --- a/packages/backend/src/models/repositories/emoji.ts +++ b/packages/backend/src/models/repositories/emoji.ts @@ -1,12 +1,11 @@ -import { db } from '@/db/postgre.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { Packed } from '@/misc/schema.js'; +import { db } from "@/db/postgre.js"; +import { Emoji } from "@/models/entities/emoji.js"; +import type { Packed } from "@/misc/schema.js"; export const EmojiRepository = db.getRepository(Emoji).extend({ - async pack( - src: Emoji['id'] | Emoji, - ): Promise> { - const emoji = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: Emoji["id"] | Emoji): Promise> { + const emoji = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: emoji.id, @@ -19,9 +18,7 @@ export const EmojiRepository = db.getRepository(Emoji).extend({ }; }, - packMany( - emojis: any[], - ) { - return Promise.all(emojis.map(x => this.pack(x))); + packMany(emojis: any[]) { + return Promise.all(emojis.map((x) => this.pack(x))); }, }); diff --git a/packages/backend/src/models/repositories/follow-request.ts b/packages/backend/src/models/repositories/follow-request.ts index c4a7203aa..cef6ea722 100644 --- a/packages/backend/src/models/repositories/follow-request.ts +++ b/packages/backend/src/models/repositories/follow-request.ts @@ -1,14 +1,15 @@ -import { db } from '@/db/postgre.js'; -import { FollowRequest } from '@/models/entities/follow-request.js'; -import { Users } from '../index.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { FollowRequest } from "@/models/entities/follow-request.js"; +import { Users } from "../index.js"; +import type { User } from "@/models/entities/user.js"; export const FollowRequestRepository = db.getRepository(FollowRequest).extend({ async pack( - src: FollowRequest['id'] | FollowRequest, - me?: { id: User['id'] } | null | undefined + src: FollowRequest["id"] | FollowRequest, + me?: { id: User["id"] } | null | undefined, ) { - const request = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const request = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: request.id, diff --git a/packages/backend/src/models/repositories/following.ts b/packages/backend/src/models/repositories/following.ts index 46109244f..b102365e0 100644 --- a/packages/backend/src/models/repositories/following.ts +++ b/packages/backend/src/models/repositories/following.ts @@ -1,9 +1,9 @@ -import { db } from '@/db/postgre.js'; -import { Users } from '../index.js'; -import { Following } from '@/models/entities/following.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { Packed } from '@/misc/schema.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { Users } from "../index.js"; +import { Following } from "@/models/entities/following.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import type { User } from "@/models/entities/user.js"; type LocalFollowerFollowing = Following & { followerHost: null; @@ -47,14 +47,15 @@ export const FollowingRepository = db.getRepository(Following).extend({ }, async pack( - src: Following['id'] | Following, - me?: { id: User['id'] } | null | undefined, + src: Following["id"] | Following, + me?: { id: User["id"] } | null | undefined, opts?: { populateFollowee?: boolean; populateFollower?: boolean; - } - ): Promise> { - const following = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + }, + ): Promise> { + const following = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); if (opts == null) opts = {}; @@ -63,23 +64,27 @@ export const FollowingRepository = db.getRepository(Following).extend({ createdAt: following.createdAt.toISOString(), followeeId: following.followeeId, followerId: following.followerId, - followee: opts.populateFollowee ? Users.pack(following.followee || following.followeeId, me, { - detail: true, - }) : undefined, - follower: opts.populateFollower ? Users.pack(following.follower || following.followerId, me, { - detail: true, - }) : undefined, + followee: opts.populateFollowee + ? Users.pack(following.followee || following.followeeId, me, { + detail: true, + }) + : undefined, + follower: opts.populateFollower + ? Users.pack(following.follower || following.followerId, me, { + detail: true, + }) + : undefined, }); }, packMany( followings: any[], - me?: { id: User['id'] } | null | undefined, + me?: { id: User["id"] } | null | undefined, opts?: { populateFollowee?: boolean; populateFollower?: boolean; - } + }, ) { - return Promise.all(followings.map(x => this.pack(x, me, opts))); + return Promise.all(followings.map((x) => this.pack(x, me, opts))); }, }); diff --git a/packages/backend/src/models/repositories/gallery-like.ts b/packages/backend/src/models/repositories/gallery-like.ts index 08ca4962b..c8920d1ee 100644 --- a/packages/backend/src/models/repositories/gallery-like.ts +++ b/packages/backend/src/models/repositories/gallery-like.ts @@ -1,13 +1,11 @@ -import { db } from '@/db/postgre.js'; -import { GalleryLike } from '@/models/entities/gallery-like.js'; -import { GalleryPosts } from '../index.js'; +import { db } from "@/db/postgre.js"; +import { GalleryLike } from "@/models/entities/gallery-like.js"; +import { GalleryPosts } from "../index.js"; export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({ - async pack( - src: GalleryLike['id'] | GalleryLike, - me?: any - ) { - const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: GalleryLike["id"] | GalleryLike, me?: any) { + const like = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: like.id, @@ -15,10 +13,7 @@ export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({ }; }, - packMany( - likes: any[], - me: any - ) { - return Promise.all(likes.map(x => this.pack(x, me))); + packMany(likes: any[], me: any) { + return Promise.all(likes.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/gallery-post.ts b/packages/backend/src/models/repositories/gallery-post.ts index bb8d40b75..b4206b0bf 100644 --- a/packages/backend/src/models/repositories/gallery-post.ts +++ b/packages/backend/src/models/repositories/gallery-post.ts @@ -1,17 +1,18 @@ -import { db } from '@/db/postgre.js'; -import { GalleryPost } from '@/models/entities/gallery-post.js'; -import { Packed } from '@/misc/schema.js'; -import { Users, DriveFiles, GalleryLikes } from '../index.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { GalleryPost } from "@/models/entities/gallery-post.js"; +import type { Packed } from "@/misc/schema.js"; +import { Users, DriveFiles, GalleryLikes } from "../index.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { User } from "@/models/entities/user.js"; export const GalleryPostRepository = db.getRepository(GalleryPost).extend({ async pack( - src: GalleryPost['id'] | GalleryPost, - me?: { id: User['id'] } | null | undefined, - ): Promise> { + src: GalleryPost["id"] | GalleryPost, + me?: { id: User["id"] } | null | undefined, + ): Promise> { const meId = me ? me.id : null; - const post = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const post = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: post.id, @@ -26,14 +27,15 @@ export const GalleryPostRepository = db.getRepository(GalleryPost).extend({ tags: post.tags.length > 0 ? post.tags : undefined, isSensitive: post.isSensitive, likedCount: post.likedCount, - isLiked: meId ? await GalleryLikes.findOneBy({ postId: post.id, userId: meId }).then(x => x != null) : undefined, + isLiked: meId + ? await GalleryLikes.findOneBy({ postId: post.id, userId: meId }).then( + (x) => x != null, + ) + : undefined, }); }, - packMany( - posts: GalleryPost[], - me?: { id: User['id'] } | null | undefined, - ) { - return Promise.all(posts.map(x => this.pack(x, me))); + packMany(posts: GalleryPost[], me?: { id: User["id"] } | null | undefined) { + return Promise.all(posts.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/hashtag.ts b/packages/backend/src/models/repositories/hashtag.ts index e6c0e36f0..7bd76c1c7 100644 --- a/packages/backend/src/models/repositories/hashtag.ts +++ b/packages/backend/src/models/repositories/hashtag.ts @@ -1,11 +1,9 @@ -import { db } from '@/db/postgre.js'; -import { Hashtag } from '@/models/entities/hashtag.js'; -import { Packed } from '@/misc/schema.js'; +import { db } from "@/db/postgre.js"; +import { Hashtag } from "@/models/entities/hashtag.js"; +import type { Packed } from "@/misc/schema.js"; export const HashtagRepository = db.getRepository(Hashtag).extend({ - async pack( - src: Hashtag, - ): Promise> { + async pack(src: Hashtag): Promise> { return { tag: src.name, mentionedUsersCount: src.mentionedUsersCount, @@ -17,9 +15,7 @@ export const HashtagRepository = db.getRepository(Hashtag).extend({ }; }, - packMany( - hashtags: Hashtag[], - ) { - return Promise.all(hashtags.map(x => this.pack(x))); + packMany(hashtags: Hashtag[]) { + return Promise.all(hashtags.map((x) => this.pack(x))); }, }); diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts index 5f0fd8d58..fb4498911 100644 --- a/packages/backend/src/models/repositories/instance.ts +++ b/packages/backend/src/models/repositories/instance.ts @@ -1,12 +1,11 @@ -import { db } from '@/db/postgre.js'; -import { Instance } from '@/models/entities/instance.js'; -import { Packed } from '@/misc/schema.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { db } from "@/db/postgre.js"; +import { Instance } from "@/models/entities/instance.js"; +import type { Packed } from "@/misc/schema.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; export const InstanceRepository = db.getRepository(Instance).extend({ - async pack( - instance: Instance, - ): Promise> { + async pack(instance: Instance): Promise> { const meta = await fetchMeta(); return { id: instance.id, @@ -16,11 +15,13 @@ export const InstanceRepository = db.getRepository(Instance).extend({ notesCount: instance.notesCount, followingCount: instance.followingCount, followersCount: instance.followersCount, - latestRequestSentAt: instance.latestRequestSentAt ? instance.latestRequestSentAt.toISOString() : null, + latestRequestSentAt: instance.latestRequestSentAt + ? instance.latestRequestSentAt.toISOString() + : null, lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(), isNotResponding: instance.isNotResponding, isSuspended: instance.isSuspended, - isBlocked: meta.blockedHosts.includes(instance.host), + isBlocked: await shouldBlockInstance(instance.host), softwareName: instance.softwareName, softwareVersion: instance.softwareVersion, openRegistrations: instance.openRegistrations, @@ -31,13 +32,13 @@ export const InstanceRepository = db.getRepository(Instance).extend({ iconUrl: instance.iconUrl, faviconUrl: instance.faviconUrl, themeColor: instance.themeColor, - infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, + infoUpdatedAt: instance.infoUpdatedAt + ? instance.infoUpdatedAt.toISOString() + : null, }; }, - packMany( - instances: Instance[], - ) { - return Promise.all(instances.map(x => this.pack(x))); + packMany(instances: Instance[]) { + return Promise.all(instances.map((x) => this.pack(x))); }, }); diff --git a/packages/backend/src/models/repositories/messaging-message.ts b/packages/backend/src/models/repositories/messaging-message.ts index 6c51c93ff..6c0987bf0 100644 --- a/packages/backend/src/models/repositories/messaging-message.ts +++ b/packages/backend/src/models/repositories/messaging-message.ts @@ -1,39 +1,48 @@ -import { db } from '@/db/postgre.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { Users, DriveFiles, UserGroups } from '../index.js'; -import { Packed } from '@/misc/schema.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { Users, DriveFiles, UserGroups } from "../index.js"; +import type { Packed } from "@/misc/schema.js"; +import type { User } from "@/models/entities/user.js"; -export const MessagingMessageRepository = db.getRepository(MessagingMessage).extend({ - async pack( - src: MessagingMessage['id'] | MessagingMessage, - me?: { id: User['id'] } | null | undefined, - options?: { - populateRecipient?: boolean, - populateGroup?: boolean, - } - ): Promise> { - const opts = options || { - populateRecipient: true, - populateGroup: true, - }; +export const MessagingMessageRepository = db + .getRepository(MessagingMessage) + .extend({ + async pack( + src: MessagingMessage["id"] | MessagingMessage, + me?: { id: User["id"] } | null | undefined, + options?: { + populateRecipient?: boolean; + populateGroup?: boolean; + }, + ): Promise> { + const opts = options || { + populateRecipient: true, + populateGroup: true, + }; - const message = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const message = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - return { - id: message.id, - createdAt: message.createdAt.toISOString(), - text: message.text, - userId: message.userId, - user: await Users.pack(message.user || message.userId, me), - recipientId: message.recipientId, - recipient: message.recipientId && opts.populateRecipient ? await Users.pack(message.recipient || message.recipientId, me) : undefined, - groupId: message.groupId, - group: message.groupId && opts.populateGroup ? await UserGroups.pack(message.group || message.groupId) : undefined, - fileId: message.fileId, - file: message.fileId ? await DriveFiles.pack(message.fileId) : null, - isRead: message.isRead, - reads: message.reads, - }; - }, -}); + return { + id: message.id, + createdAt: message.createdAt.toISOString(), + text: message.text, + userId: message.userId, + user: await Users.pack(message.user || message.userId, me), + recipientId: message.recipientId, + recipient: + message.recipientId && opts.populateRecipient + ? await Users.pack(message.recipient || message.recipientId, me) + : undefined, + groupId: message.groupId, + group: + message.groupId && opts.populateGroup + ? await UserGroups.pack(message.group || message.groupId) + : undefined, + fileId: message.fileId, + file: message.fileId ? await DriveFiles.pack(message.fileId) : null, + isRead: message.isRead, + reads: message.reads, + }; + }, + }); diff --git a/packages/backend/src/models/repositories/moderation-logs.ts b/packages/backend/src/models/repositories/moderation-logs.ts index 1488b1eab..3858b9509 100644 --- a/packages/backend/src/models/repositories/moderation-logs.ts +++ b/packages/backend/src/models/repositories/moderation-logs.ts @@ -1,13 +1,12 @@ -import { db } from '@/db/postgre.js'; -import { Users } from '../index.js'; -import { ModerationLog } from '@/models/entities/moderation-log.js'; -import { awaitAll } from '@/prelude/await-all.js'; +import { db } from "@/db/postgre.js"; +import { Users } from "../index.js"; +import { ModerationLog } from "@/models/entities/moderation-log.js"; +import { awaitAll } from "@/prelude/await-all.js"; export const ModerationLogRepository = db.getRepository(ModerationLog).extend({ - async pack( - src: ModerationLog['id'] | ModerationLog, - ) { - const log = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: ModerationLog["id"] | ModerationLog) { + const log = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: log.id, @@ -21,9 +20,7 @@ export const ModerationLogRepository = db.getRepository(ModerationLog).extend({ }); }, - packMany( - reports: any[], - ) { - return Promise.all(reports.map(x => this.pack(x))); + packMany(reports: any[]) { + return Promise.all(reports.map((x) => this.pack(x))); }, }); diff --git a/packages/backend/src/models/repositories/muting.ts b/packages/backend/src/models/repositories/muting.ts index 7891b10fb..4d0201d5a 100644 --- a/packages/backend/src/models/repositories/muting.ts +++ b/packages/backend/src/models/repositories/muting.ts @@ -1,16 +1,17 @@ -import { db } from '@/db/postgre.js'; -import { Users } from '../index.js'; -import { Muting } from '@/models/entities/muting.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { Packed } from '@/misc/schema.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { Users } from "../index.js"; +import { Muting } from "@/models/entities/muting.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import type { User } from "@/models/entities/user.js"; export const MutingRepository = db.getRepository(Muting).extend({ async pack( - src: Muting['id'] | Muting, - me?: { id: User['id'] } | null | undefined - ): Promise> { - const muting = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + src: Muting["id"] | Muting, + me?: { id: User["id"] } | null | undefined, + ): Promise> { + const muting = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: muting.id, @@ -23,10 +24,7 @@ export const MutingRepository = db.getRepository(Muting).extend({ }); }, - packMany( - mutings: any[], - me: { id: User['id'] } - ) { - return Promise.all(mutings.map(x => this.pack(x, me))); + packMany(mutings: any[], me: { id: User["id"] }) { + return Promise.all(mutings.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/note-favorite.ts b/packages/backend/src/models/repositories/note-favorite.ts index 1d5702053..ba43e3c3b 100644 --- a/packages/backend/src/models/repositories/note-favorite.ts +++ b/packages/backend/src/models/repositories/note-favorite.ts @@ -1,14 +1,15 @@ -import { db } from '@/db/postgre.js'; -import { NoteFavorite } from '@/models/entities/note-favorite.js'; -import { Notes } from '../index.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { NoteFavorite } from "@/models/entities/note-favorite.js"; +import { Notes } from "../index.js"; +import type { User } from "@/models/entities/user.js"; export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ async pack( - src: NoteFavorite['id'] | NoteFavorite, - me?: { id: User['id'] } | null | undefined + src: NoteFavorite["id"] | NoteFavorite, + me?: { id: User["id"] } | null | undefined, ) { - const favorite = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const favorite = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: favorite.id, @@ -19,11 +20,12 @@ export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ }; }, - packMany( - favorites: any[], - me: { id: User['id'] } - ) { - return Promise.allSettled(favorites.map(x => this.pack(x, me))) - .then(promises => promises.flatMap(result => result.status === 'fulfilled' ? [result.value] : [])); + packMany(favorites: any[], me: { id: User["id"] }) { + return Promise.allSettled(favorites.map((x) => this.pack(x, me))).then( + (promises) => + promises.flatMap((result) => + result.status === "fulfilled" ? [result.value] : [], + ), + ); }, }); diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index 46084a9a1..6d1dfbd6f 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -1,46 +1,56 @@ -import { db } from '@/db/postgre.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import { Notes, Users } from '../index.js'; -import { Packed } from '@/misc/schema.js'; -import { convertLegacyReaction } from '@/misc/reaction-lib.js'; -import { User } from '@/models/entities/user.js'; +import { db } from "@/db/postgre.js"; +import { NoteReaction } from "@/models/entities/note-reaction.js"; +import { Notes, Users } from "../index.js"; +import type { Packed } from "@/misc/schema.js"; +import { convertLegacyReaction } from "@/misc/reaction-lib.js"; +import type { User } from "@/models/entities/user.js"; export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ async pack( - src: NoteReaction['id'] | NoteReaction, - me?: { id: User['id'] } | null | undefined, + src: NoteReaction["id"] | NoteReaction, + me?: { id: User["id"] } | null | undefined, options?: { withNote: boolean; }, - ): Promise> { - const opts = Object.assign({ - withNote: false, - }, options); + ): Promise> { + const opts = Object.assign( + { + withNote: false, + }, + options, + ); - const reaction = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const reaction = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: reaction.id, createdAt: reaction.createdAt.toISOString(), user: await Users.pack(reaction.user ?? reaction.userId, me), type: convertLegacyReaction(reaction.reaction), - ...(opts.withNote ? { - // may throw error - note: await Notes.pack(reaction.note ?? reaction.noteId, me), - } : {}), + ...(opts.withNote + ? { + // may throw error + note: await Notes.pack(reaction.note ?? reaction.noteId, me), + } + : {}), }; }, async packMany( src: NoteReaction[], - me?: { id: User['id'] } | null | undefined, + me?: { id: User["id"] } | null | undefined, options?: { withNote: booleam; }, - ): Promise[]> { - const reactions = await Promise.allSettled(src.map(reaction => this.pack(reaction, me, options))); + ): Promise[]> { + const reactions = await Promise.allSettled( + src.map((reaction) => this.pack(reaction, me, options)), + ); // filter out rejected promises, only keep fulfilled values - return reactions.flatMap(result => result.status === 'fulfilled' ? [result.value] : []); - } + return reactions.flatMap((result) => + result.status === "fulfilled" ? [result.value] : [], + ); + }, }); diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index e697b4cea..2bc3b90ca 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -1,20 +1,36 @@ -import { In } from 'typeorm'; -import * as mfm from 'mfm-js'; -import { Note } from '@/models/entities/note.js'; -import { User } from '@/models/entities/user.js'; -import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '../index.js'; -import { Packed } from '@/misc/schema.js'; -import { nyaize } from '@/misc/nyaize.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; -import { db } from '@/db/postgre.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { In } from "typeorm"; +import * as mfm from "mfm-js"; +import { Note } from "@/models/entities/note.js"; +import type { User } from "@/models/entities/user.js"; +import { + Users, + PollVotes, + DriveFiles, + NoteReactions, + Followings, + Polls, + Channels, +} from "../index.js"; +import type { Packed } from "@/misc/schema.js"; +import { nyaize } from "@/misc/nyaize.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import { + convertLegacyReaction, + convertLegacyReactions, + decodeReaction, +} from "@/misc/reaction-lib.js"; +import type { NoteReaction } from "@/models/entities/note-reaction.js"; +import { + aggregateNoteEmojis, + populateEmojis, + prefetchEmojis, +} from "@/misc/populate-emojis.js"; +import { db } from "@/db/postgre.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; -async function populatePoll(note: Note, meId: User['id'] | null) { +async function populatePoll(note: Note, meId: User["id"] | null) { const poll = await Polls.findOneByOrFail({ noteId: note.id }); - const choices = poll.choices.map(c => ({ + const choices = poll.choices.map((c) => ({ text: c, votes: poll.votes[poll.choices.indexOf(c)], isVoted: false, @@ -27,7 +43,7 @@ async function populatePoll(note: Note, meId: User['id'] | null) { noteId: note.id, }); - const myChoices = votes.map(v => v.choice); + const myChoices = votes.map((v) => v.choice); for (const myChoice of myChoices) { choices[myChoice].isVoted = true; } @@ -50,9 +66,13 @@ async function populatePoll(note: Note, meId: User['id'] | null) { }; } -async function populateMyReaction(note: Note, meId: User['id'], _hint_?: { - myReactions: Map; -}) { +async function populateMyReaction( + note: Note, + meId: User["id"], + _hint_?: { + myReactions: Map; + }, +) { if (_hint_?.myReactions) { const reaction = _hint_.myReactions.get(note.id); if (reaction) { @@ -76,10 +96,10 @@ async function populateMyReaction(note: Note, meId: User['id'], _hint_?: { } export const NoteRepository = db.getRepository(Note).extend({ - async isVisibleForMe(note: Note, meId: User['id'] | null): Promise { + async isVisibleForMe(note: Note, meId: User["id"] | null): Promise { // This code must always be synchronized with the checks in generateVisibilityQuery. // visibility が specified かつ自分が指定されていなかったら非表示 - if (note.visibility === 'specified') { + if (note.visibility === "specified") { if (meId == null) { return false; } else if (meId === note.userId) { @@ -91,15 +111,15 @@ export const NoteRepository = db.getRepository(Note).extend({ } // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 - if (note.visibility === 'followers') { + if (note.visibility === "followers") { if (meId == null) { return false; } else if (meId === note.userId) { return true; - } else if (note.reply && (meId === note.reply.userId)) { + } else if (note.reply && meId === note.reply.userId) { // 自分の投稿に対するリプライ return true; - } else if (note.mentions && note.mentions.some(id => meId === id)) { + } else if (note.mentions?.some((id) => meId === id)) { // 自分へのメンション return true; } else { @@ -130,31 +150,40 @@ export const NoteRepository = db.getRepository(Note).extend({ }, async pack( - src: Note['id'] | Note, - me?: { id: User['id'] } | null | undefined, + src: Note["id"] | Note, + me?: { id: User["id"] } | null | undefined, options?: { detail?: boolean; _hint_?: { - myReactions: Map; + myReactions: Map; }; - } - ): Promise> { - const opts = Object.assign({ - detail: true, - }, options); + }, + ): Promise> { + const opts = Object.assign( + { + detail: true, + }, + options, + ); const meId = me ? me.id : null; - const note = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const note = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); const host = note.userHost; - if (!await this.isVisibleForMe(note, meId)) { - throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); + if (!(await this.isVisibleForMe(note, meId))) { + throw new IdentifiableError( + "9725d0ce-ba28-4dde-95a7-2cbb2c15de24", + "No such note.", + ); } let text = note.text; if (note.name && (note.url ?? note.uri)) { - text = `【${note.name}】\n${(note.text || '').trim()}\n\n${note.url ?? note.uri}`; + text = `【${note.name}】\n${(note.text || "").trim()}\n\n${ + note.url ?? note.uri + }`; } const channel = note.channelId @@ -163,9 +192,12 @@ export const NoteRepository = db.getRepository(Note).extend({ : await Channels.findOneBy({ id: note.channelId }) : null; - const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); + const reactionEmojiNames = Object.keys(note.reactions) + .filter((x) => x?.startsWith(":")) + .map((x) => decodeReaction(x).reaction) + .map((x) => x.replace(/:/g, "")); - const packed: Packed<'Note'> = await awaitAll({ + const packed: Packed<"Note"> = await awaitAll({ id: note.id, createdAt: note.createdAt.toISOString(), userId: note.userId, @@ -176,7 +208,8 @@ export const NoteRepository = db.getRepository(Note).extend({ cw: note.cw, visibility: note.visibility, localOnly: note.localOnly || undefined, - visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined, + visibleUserIds: + note.visibility === "specified" ? note.visibleUserIds : undefined, renoteCount: note.renoteCount, repliesCount: note.repliesCount, reactions: convertLegacyReactions(note.reactions), @@ -187,37 +220,47 @@ export const NoteRepository = db.getRepository(Note).extend({ replyId: note.replyId, renoteId: note.renoteId, channelId: note.channelId || undefined, - channel: channel ? { - id: channel.id, - name: channel.name, - } : undefined, + channel: channel + ? { + id: channel.id, + name: channel.name, + } + : undefined, mentions: note.mentions.length > 0 ? note.mentions : undefined, uri: note.uri || undefined, url: note.url || undefined, - ...(opts.detail ? { - reply: note.replyId ? this.pack(note.reply || note.replyId, me, { - detail: false, - _hint_: options?._hint_, - }) : undefined, + ...(opts.detail + ? { + reply: note.replyId + ? this.pack(note.reply || note.replyId, me, { + detail: false, + _hint_: options?._hint_, + }) + : undefined, - renote: note.renoteId ? this.pack(note.renote || note.renoteId, me, { - detail: true, - _hint_: options?._hint_, - }) : undefined, + renote: note.renoteId + ? this.pack(note.renote || note.renoteId, me, { + detail: true, + _hint_: options?._hint_, + }) + : undefined, - poll: note.hasPoll ? populatePoll(note, meId) : undefined, + poll: note.hasPoll ? populatePoll(note, meId) : undefined, - ...(meId ? { - myReaction: populateMyReaction(note, meId, options?._hint_), - } : {}), - } : {}), + ...(meId + ? { + myReaction: populateMyReaction(note, meId, options?._hint_), + } + : {}), + } + : {}), }); if (packed.user.isCat && packed.text) { const tokens = packed.text ? mfm.parse(packed.text) : []; - mfm.inspect(tokens, node => { - if (node.type === 'text') { + mfm.inspect(tokens, (node) => { + if (node.type === "text") { // TODO: quoteなtextはskip node.props.text = nyaize(node.props.text); } @@ -230,38 +273,49 @@ export const NoteRepository = db.getRepository(Note).extend({ async packMany( notes: Note[], - me?: { id: User['id'] } | null | undefined, + me?: { id: User["id"] } | null | undefined, options?: { detail?: boolean; - } + }, ) { if (notes.length === 0) return []; const meId = me ? me.id : null; - const myReactionsMap = new Map(); + const myReactionsMap = new Map(); if (meId) { - const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); - const targets = [...notes.map(n => n.id), ...renoteIds]; + const renoteIds = notes + .filter((n) => n.renoteId != null) + .map((n) => n.renoteId!); + const targets = [...notes.map((n) => n.id), ...renoteIds]; const myReactions = await NoteReactions.findBy({ userId: meId, noteId: In(targets), }); for (const target of targets) { - myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null); + myReactionsMap.set( + target, + myReactions.find((reaction) => reaction.noteId === target) || null, + ); } } await prefetchEmojis(aggregateNoteEmojis(notes)); - const promises = await Promise.allSettled(notes.map(n => this.pack(n, me, { - ...options, - _hint_: { - myReactions: myReactionsMap, - }, - }))); + const promises = await Promise.allSettled( + notes.map((n) => + this.pack(n, me, { + ...options, + _hint_: { + myReactions: myReactionsMap, + }, + }), + ), + ); // filter out rejected promises, only keep fulfilled values - return promises.flatMap(result => result.status === 'fulfilled' ? [result.value] : []); + return promises.flatMap((result) => + result.status === "fulfilled" ? [result.value] : [], + ); }, }); diff --git a/packages/backend/src/models/repositories/notification.ts b/packages/backend/src/models/repositories/notification.ts index efa3e860b..1538e67d8 100644 --- a/packages/backend/src/models/repositories/notification.ts +++ b/packages/backend/src/models/repositories/notification.ts @@ -1,26 +1,37 @@ -import { In, Repository } from 'typeorm'; -import { Notification } from '@/models/entities/notification.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import type { Packed } from '@/misc/schema.js'; -import type { Note } from '@/models/entities/note.js'; -import type { NoteReaction } from '@/models/entities/note-reaction.js'; -import type { User } from '@/models/entities/user.js'; -import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; -import { notificationTypes } from '@/types.js'; -import { db } from '@/db/postgre.js'; -import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index.js'; +import { In, Repository } from "typeorm"; +import { Notification } from "@/models/entities/notification.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { Packed } from "@/misc/schema.js"; +import type { Note } from "@/models/entities/note.js"; +import type { NoteReaction } from "@/models/entities/note-reaction.js"; +import type { User } from "@/models/entities/user.js"; +import { aggregateNoteEmojis, prefetchEmojis } from "@/misc/populate-emojis.js"; +import { notificationTypes } from "@/types.js"; +import { db } from "@/db/postgre.js"; +import { + Users, + Notes, + UserGroupInvitations, + AccessTokens, + NoteReactions, +} from "../index.js"; export const NotificationRepository = db.getRepository(Notification).extend({ async pack( - src: Notification['id'] | Notification, + src: Notification["id"] | Notification, options: { _hintForEachNotes_?: { - myReactions: Map; + myReactions: Map; }; }, - ): Promise> { - const notification = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); - const token = notification.appAccessTokenId ? await AccessTokens.findOneByOrFail({ id: notification.appAccessTokenId }) : null; + ): Promise> { + const notification = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); + const token = notification.appAccessTokenId + ? await AccessTokens.findOneByOrFail({ + id: notification.appAccessTokenId, + }) + : null; return await awaitAll({ id: notification.id, @@ -28,72 +39,123 @@ export const NotificationRepository = db.getRepository(Notification).extend({ type: notification.type, isRead: notification.isRead, userId: notification.notifierId, - user: notification.notifierId ? Users.pack(notification.notifier || notification.notifierId) : null, - ...(notification.type === 'mention' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - } : {}), - ...(notification.type === 'reply' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - } : {}), - ...(notification.type === 'renote' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - } : {}), - ...(notification.type === 'quote' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - } : {}), - ...(notification.type === 'reaction' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - reaction: notification.reaction, - } : {}), - ...(notification.type === 'pollVote' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - choice: notification.choice, - } : {}), - ...(notification.type === 'pollEnded' ? { - note: Notes.pack(notification.note || notification.noteId!, { id: notification.notifieeId }, { - detail: true, - _hint_: options._hintForEachNotes_, - }), - } : {}), - ...(notification.type === 'groupInvited' ? { - invitation: UserGroupInvitations.pack(notification.userGroupInvitationId!), - } : {}), - ...(notification.type === 'app' ? { - body: notification.customBody, - header: notification.customHeader || token?.name, - icon: notification.customIcon || token?.iconUrl, - } : {}), + user: notification.notifierId + ? Users.pack(notification.notifier || notification.notifierId) + : null, + ...(notification.type === "mention" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + } + : {}), + ...(notification.type === "reply" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + } + : {}), + ...(notification.type === "renote" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + } + : {}), + ...(notification.type === "quote" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + } + : {}), + ...(notification.type === "reaction" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + reaction: notification.reaction, + } + : {}), + ...(notification.type === "pollVote" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + choice: notification.choice, + } + : {}), + ...(notification.type === "pollEnded" + ? { + note: Notes.pack( + notification.note || notification.noteId!, + { id: notification.notifieeId }, + { + detail: true, + _hint_: options._hintForEachNotes_, + }, + ), + } + : {}), + ...(notification.type === "groupInvited" + ? { + invitation: UserGroupInvitations.pack( + notification.userGroupInvitationId!, + ), + } + : {}), + ...(notification.type === "app" + ? { + body: notification.customBody, + header: notification.customHeader || token?.name, + icon: notification.customIcon || token?.iconUrl, + } + : {}), }); }, - async packMany( - notifications: Notification[], - meId: User['id'], - ) { + async packMany(notifications: Notification[], meId: User["id"]) { if (notifications.length === 0) return []; - const notes = notifications.filter(x => x.note != null).map(x => x.note!); - const noteIds = notes.map(n => n.id); - const myReactionsMap = new Map(); - const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); + const notes = notifications + .filter((x) => x.note != null) + .map((x) => x.note!); + const noteIds = notes.map((n) => n.id); + const myReactionsMap = new Map(); + const renoteIds = notes + .filter((n) => n.renoteId != null) + .map((n) => n.renoteId!); const targets = [...noteIds, ...renoteIds]; const myReactions = await NoteReactions.findBy({ userId: meId, @@ -101,20 +163,23 @@ export const NotificationRepository = db.getRepository(Notification).extend({ }); for (const target of targets) { - myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null); + myReactionsMap.set( + target, + myReactions.find((reaction) => reaction.noteId === target) || null, + ); } await prefetchEmojis(aggregateNoteEmojis(notes)); - const results = await Promise.all(notifications - .map(x => + const results = await Promise.all( + notifications.map((x) => this.pack(x, { _hintForEachNotes_: { myReactions: myReactionsMap, }, - }).catch(e => null), + }).catch((e) => null), ), ); - return results.filter(x => x != null); + return results.filter((x) => x != null); }, }); diff --git a/packages/backend/src/models/repositories/page-like.ts b/packages/backend/src/models/repositories/page-like.ts index 3f259f981..f78ef81b0 100644 --- a/packages/backend/src/models/repositories/page-like.ts +++ b/packages/backend/src/models/repositories/page-like.ts @@ -1,14 +1,15 @@ -import { db } from '@/db/postgre.js'; -import { PageLike } from '@/models/entities/page-like.js'; -import type { User } from '@/models/entities/user.js'; -import { Pages } from '../index.js'; +import { db } from "@/db/postgre.js"; +import { PageLike } from "@/models/entities/page-like.js"; +import type { User } from "@/models/entities/user.js"; +import { Pages } from "../index.js"; export const PageLikeRepository = db.getRepository(PageLike).extend({ async pack( - src: PageLike['id'] | PageLike, - me?: { id: User['id'] } | null | undefined, + src: PageLike["id"] | PageLike, + me?: { id: User["id"] } | null | undefined, ) { - const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const like = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); return { id: like.id, @@ -16,10 +17,7 @@ export const PageLikeRepository = db.getRepository(PageLike).extend({ }; }, - packMany( - likes: PageLike[], - me: { id: User['id'] }, - ) { - return Promise.all(likes.map(x => this.pack(x, me))); + packMany(likes: PageLike[], me: { id: User["id"] }) { + return Promise.all(likes.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/page.ts b/packages/backend/src/models/repositories/page.ts index 1a8bc50e2..d9241c362 100644 --- a/packages/backend/src/models/repositories/page.ts +++ b/packages/backend/src/models/repositories/page.ts @@ -1,27 +1,30 @@ -import { db } from '@/db/postgre.js'; -import { Page } from '@/models/entities/page.js'; -import type { Packed } from '@/misc/schema.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import type { DriveFile } from '@/models/entities/drive-file.js'; -import type { User } from '@/models/entities/user.js'; -import { Users, DriveFiles, PageLikes } from '../index.js'; +import { db } from "@/db/postgre.js"; +import { Page } from "@/models/entities/page.js"; +import type { Packed } from "@/misc/schema.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { User } from "@/models/entities/user.js"; +import { Users, DriveFiles, PageLikes } from "../index.js"; export const PageRepository = db.getRepository(Page).extend({ async pack( - src: Page['id'] | Page, - me?: { id: User['id'] } | null | undefined, - ): Promise> { + src: Page["id"] | Page, + me?: { id: User["id"] } | null | undefined, + ): Promise> { const meId = me ? me.id : null; - const page = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const page = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); const attachedFiles: Promise[] = []; const collectFile = (xs: any[]) => { for (const x of xs) { - if (x.type === 'image') { - attachedFiles.push(DriveFiles.findOneBy({ - id: x.fileId, - userId: page.userId, - })); + if (x.type === "image") { + attachedFiles.push( + DriveFiles.findOneBy({ + id: x.fileId, + userId: page.userId, + }), + ); } if (x.children) { collectFile(x.children); @@ -34,12 +37,12 @@ export const PageRepository = db.getRepository(Page).extend({ let migrated = false; const migrate = (xs: any[]) => { for (const x of xs) { - if (x.type === 'input') { - if (x.inputType === 'text') { - x.type = 'textInput'; + if (x.type === "input") { + if (x.inputType === "text") { + x.type = "textInput"; } - if (x.inputType === 'number') { - x.type = 'numberInput'; + if (x.inputType === "number") { + x.type = "numberInput"; if (x.default) x.default = parseInt(x.default, 10); } migrated = true; @@ -73,17 +76,24 @@ export const PageRepository = db.getRepository(Page).extend({ font: page.font, script: page.script, eyeCatchingImageId: page.eyeCatchingImageId, - eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null, - attachedFiles: DriveFiles.packMany((await Promise.all(attachedFiles)).filter((x): x is DriveFile => x != null)), + eyeCatchingImage: page.eyeCatchingImageId + ? await DriveFiles.pack(page.eyeCatchingImageId) + : null, + attachedFiles: DriveFiles.packMany( + ( + await Promise.all(attachedFiles) + ).filter((x): x is DriveFile => x != null), + ), likedCount: page.likedCount, - isLiked: meId ? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then(x => x != null) : undefined, + isLiked: meId + ? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then( + (x) => x != null, + ) + : undefined, }); }, - packMany( - pages: Page[], - me?: { id: User['id'] } | null | undefined, - ) { - return Promise.all(pages.map(x => this.pack(x, me))); + packMany(pages: Page[], me?: { id: User["id"] } | null | undefined) { + return Promise.all(pages.map((x) => this.pack(x, me))); }, }); diff --git a/packages/backend/src/models/repositories/relay.ts b/packages/backend/src/models/repositories/relay.ts index fa1c8f4d8..633861496 100644 --- a/packages/backend/src/models/repositories/relay.ts +++ b/packages/backend/src/models/repositories/relay.ts @@ -1,5 +1,4 @@ -import { db } from '@/db/postgre.js'; -import { Relay } from '@/models/entities/relay.js'; +import { db } from "@/db/postgre.js"; +import { Relay } from "@/models/entities/relay.js"; -export const RelayRepository = db.getRepository(Relay).extend({ -}); +export const RelayRepository = db.getRepository(Relay).extend({}); diff --git a/packages/backend/src/models/repositories/signin.ts b/packages/backend/src/models/repositories/signin.ts index 94410ec58..06cf2c210 100644 --- a/packages/backend/src/models/repositories/signin.ts +++ b/packages/backend/src/models/repositories/signin.ts @@ -1,10 +1,8 @@ -import { db } from '@/db/postgre.js'; -import { Signin } from '@/models/entities/signin.js'; +import { db } from "@/db/postgre.js"; +import { Signin } from "@/models/entities/signin.js"; export const SigninRepository = db.getRepository(Signin).extend({ - async pack( - src: Signin, - ) { + async pack(src: Signin) { return src; }, }); diff --git a/packages/backend/src/models/repositories/user-group-invitation.ts b/packages/backend/src/models/repositories/user-group-invitation.ts index 79ad019c9..920fb9ba2 100644 --- a/packages/backend/src/models/repositories/user-group-invitation.ts +++ b/packages/backend/src/models/repositories/user-group-invitation.ts @@ -1,22 +1,23 @@ -import { db } from '@/db/postgre.js'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; -import { UserGroups } from '../index.js'; +import { db } from "@/db/postgre.js"; +import { UserGroupInvitation } from "@/models/entities/user-group-invitation.js"; +import { UserGroups } from "../index.js"; -export const UserGroupInvitationRepository = db.getRepository(UserGroupInvitation).extend({ - async pack( - src: UserGroupInvitation['id'] | UserGroupInvitation, - ) { - const invitation = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); +export const UserGroupInvitationRepository = db + .getRepository(UserGroupInvitation) + .extend({ + async pack(src: UserGroupInvitation["id"] | UserGroupInvitation) { + const invitation = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - return { - id: invitation.id, - group: await UserGroups.pack(invitation.userGroup || invitation.userGroupId), - }; - }, + return { + id: invitation.id, + group: await UserGroups.pack( + invitation.userGroup || invitation.userGroupId, + ), + }; + }, - packMany( - invitations: any[], - ) { - return Promise.all(invitations.map(x => this.pack(x))); - }, -}); + packMany(invitations: any[]) { + return Promise.all(invitations.map((x) => this.pack(x))); + }, + }); diff --git a/packages/backend/src/models/repositories/user-group.ts b/packages/backend/src/models/repositories/user-group.ts index 6eb923424..daec94490 100644 --- a/packages/backend/src/models/repositories/user-group.ts +++ b/packages/backend/src/models/repositories/user-group.ts @@ -1,13 +1,12 @@ -import { db } from '@/db/postgre.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { UserGroupJoinings } from '../index.js'; -import { Packed } from '@/misc/schema.js'; +import { db } from "@/db/postgre.js"; +import { UserGroup } from "@/models/entities/user-group.js"; +import { UserGroupJoinings } from "../index.js"; +import type { Packed } from "@/misc/schema.js"; export const UserGroupRepository = db.getRepository(UserGroup).extend({ - async pack( - src: UserGroup['id'] | UserGroup, - ): Promise> { - const userGroup = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: UserGroup["id"] | UserGroup): Promise> { + const userGroup = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); const users = await UserGroupJoinings.findBy({ userGroupId: userGroup.id, @@ -18,7 +17,7 @@ export const UserGroupRepository = db.getRepository(UserGroup).extend({ createdAt: userGroup.createdAt.toISOString(), name: userGroup.name, ownerId: userGroup.userId, - userIds: users.map(x => x.userId), + userIds: users.map((x) => x.userId), }; }, }); diff --git a/packages/backend/src/models/repositories/user-list.ts b/packages/backend/src/models/repositories/user-list.ts index 2b6f411ef..e3abeac3f 100644 --- a/packages/backend/src/models/repositories/user-list.ts +++ b/packages/backend/src/models/repositories/user-list.ts @@ -1,13 +1,12 @@ -import { db } from '@/db/postgre.js'; -import { UserList } from '@/models/entities/user-list.js'; -import { UserListJoinings } from '../index.js'; -import { Packed } from '@/misc/schema.js'; +import { db } from "@/db/postgre.js"; +import { UserList } from "@/models/entities/user-list.js"; +import { UserListJoinings } from "../index.js"; +import type { Packed } from "@/misc/schema.js"; export const UserListRepository = db.getRepository(UserList).extend({ - async pack( - src: UserList['id'] | UserList, - ): Promise> { - const userList = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + async pack(src: UserList["id"] | UserList): Promise> { + const userList = + typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); const users = await UserListJoinings.findBy({ userListId: userList.id, @@ -17,7 +16,7 @@ export const UserListRepository = db.getRepository(UserList).extend({ id: userList.id, createdAt: userList.createdAt.toISOString(), name: userList.name, - userIds: users.map(x => x.userId), + userIds: users.map((x) => x.userId), }; }, }); diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 138929c4b..aa224b667 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -1,21 +1,21 @@ -import { URL } from 'url'; -import { In, Not } from 'typeorm'; -import Ajv from 'ajv'; -import type { ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { User } from '@/models/entities/user.js'; -import config from '@/config/index.js'; -import type { Packed } from '@/misc/schema.js'; -import type { Promiseable } from '@/prelude/await-all.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import { populateEmojis } from '@/misc/populate-emojis.js'; -import { getAntennas } from '@/misc/antenna-cache.js'; -import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; -import { Cache } from '@/misc/cache.js'; -import { db } from '@/db/postgre.js'; -import { isActor, getApId } from '@/remote/activitypub/type.js'; -import DbResolver from '@/remote/activitypub/db-resolver.js'; -import Resolver from '@/remote/activitypub/resolver.js'; -import { createPerson } from '@/remote/activitypub/models/person.js'; +import { URL } from "url"; +import { In, Not } from "typeorm"; +import Ajv from "ajv"; +import type { ILocalUser, IRemoteUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import config from "@/config/index.js"; +import type { Packed } from "@/misc/schema.js"; +import type { Promiseable } from "@/prelude/await-all.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import { populateEmojis } from "@/misc/populate-emojis.js"; +import { getAntennas } from "@/misc/antenna-cache.js"; +import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from "@/const.js"; +import { Cache } from "@/misc/cache.js"; +import { db } from "@/db/postgre.js"; +import { isActor, getApId } from "@/remote/activitypub/type.js"; +import DbResolver from "@/remote/activitypub/db-resolver.js"; +import Resolver from "@/remote/activitypub/resolver.js"; +import { createPerson } from "@/remote/activitypub/models/person.js"; import { AnnouncementReads, Announcements, @@ -36,49 +36,69 @@ import { UserNotePinings, UserProfiles, UserSecurityKeys, -} from '../index.js'; -import type { Instance } from '../entities/instance.js'; +} from "../index.js"; +import type { Instance } from "../entities/instance.js"; const userInstanceCache = new Cache(1000 * 60 * 60 * 3); -type IsUserDetailed = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>; -type IsMeAndIsUserDetailed = - Detailed extends true ? - ExpectsMe extends true ? Packed<'MeDetailed'> : - ExpectsMe extends false ? Packed<'UserDetailedNotMe'> : - Packed<'UserDetailed'> : - Packed<'UserLite'>; +type IsUserDetailed = Detailed extends true + ? Packed<"UserDetailed"> + : Packed<"UserLite">; +type IsMeAndIsUserDetailed< + ExpectsMe extends boolean | null, + Detailed extends boolean, +> = Detailed extends true + ? ExpectsMe extends true + ? Packed<"MeDetailed"> + : ExpectsMe extends false + ? Packed<"UserDetailedNotMe"> + : Packed<"UserDetailed"> + : Packed<"UserLite">; const ajv = new Ajv(); -const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; -const passwordSchema = { type: 'string', minLength: 1 } as const; -const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; -const descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; -const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; -const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const; +const localUsernameSchema = { + type: "string", + pattern: /^\w{1,20}$/.toString().slice(1, -1), +} as const; +const passwordSchema = { type: "string", minLength: 1 } as const; +const nameSchema = { type: "string", minLength: 1, maxLength: 50 } as const; +const descriptionSchema = { + type: "string", + minLength: 1, + maxLength: 500, +} as const; +const locationSchema = { type: "string", minLength: 1, maxLength: 50 } as const; +const birthdaySchema = { + type: "string", + pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1), +} as const; function isLocalUser(user: User): user is ILocalUser; -function isLocalUser(user: T): user is T & { host: null; }; +function isLocalUser( + user: T, +): user is T & { host: null }; /** * Returns true if the user is local. * * @param user The user to check. * @returns True if the user is local. */ -function isLocalUser(user: User | { host: User['host'] }): boolean { +function isLocalUser(user: User | { host: User["host"] }): boolean { return user.host == null; } function isRemoteUser(user: User): user is IRemoteUser; -function isRemoteUser(user: T): user is T & { host: string; }; +function isRemoteUser( + user: T, +): user is T & { host: string }; /** * Returns true if the user is remote. * * @param user The user to check. * @returns True if the user is remote. */ -function isRemoteUser(user: User | { host: User['host'] }): boolean { +function isRemoteUser(user: User | { host: User["host"] }): boolean { return !isLocalUser(user); } @@ -99,7 +119,7 @@ export const UserRepository = db.getRepository(User).extend({ validateBirthday: ajv.compile(birthdaySchema), //#endregion - async getRelation(me: User['id'], target: User['id']) { + async getRelation(me: User["id"], target: User["id"]) { return awaitAll({ id: target, isFollowing: Followings.count({ @@ -108,89 +128,100 @@ export const UserRepository = db.getRepository(User).extend({ followeeId: target, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), isFollowed: Followings.count({ where: { followerId: target, followeeId: me, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), hasPendingFollowRequestFromYou: FollowRequests.count({ where: { followerId: me, followeeId: target, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), hasPendingFollowRequestToYou: FollowRequests.count({ where: { followerId: target, followeeId: me, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), isBlocking: Blockings.count({ where: { blockerId: me, blockeeId: target, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), isBlocked: Blockings.count({ where: { blockerId: target, blockeeId: me, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), isMuted: Mutings.count({ where: { muterId: me, muteeId: target, }, take: 1, - }).then(n => n > 0), + }).then((n) => n > 0), }); }, - async getHasUnreadMessagingMessage(userId: User['id']): Promise { + async getHasUnreadMessagingMessage(userId: User["id"]): Promise { const mute = await Mutings.findBy({ muterId: userId, }); const joinings = await UserGroupJoinings.findBy({ userId: userId }); - const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') - .where('message.groupId = :groupId', { groupId: j.userGroupId }) - .andWhere('message.userId != :userId', { userId: userId }) - .andWhere('NOT (:userId = ANY(message.reads))', { userId: userId }) - .andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない - .getOne().then(x => x != null))); + const groupQs = Promise.all( + joinings.map((j) => + MessagingMessages.createQueryBuilder("message") + .where("message.groupId = :groupId", { groupId: j.userGroupId }) + .andWhere("message.userId != :userId", { userId: userId }) + .andWhere("NOT (:userId = ANY(message.reads))", { userId: userId }) + .andWhere("message.createdAt > :joinedAt", { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない + .getOne() + .then((x) => x != null), + ), + ); const [withUser, withGroups] = await Promise.all([ MessagingMessages.count({ where: { recipientId: userId, isRead: false, - ...(mute.length > 0 ? { userId: Not(In(mute.map(x => x.muteeId))) } : {}), + ...(mute.length > 0 + ? { userId: Not(In(mute.map((x) => x.muteeId))) } + : {}), }, take: 1, - }).then(count => count > 0), + }).then((count) => count > 0), groupQs, ]); - return withUser || withGroups.some(x => x); + return withUser || withGroups.some((x) => x); }, - async getHasUnreadAnnouncement(userId: User['id']): Promise { + async getHasUnreadAnnouncement(userId: User["id"]): Promise { const reads = await AnnouncementReads.findBy({ userId: userId, }); - const count = await Announcements.countBy(reads.length > 0 ? { - id: Not(In(reads.map(read => read.announcementId))), - } : {}); + const count = await Announcements.countBy( + reads.length > 0 + ? { + id: Not(In(reads.map((read) => read.announcementId))), + } + : {}, + ); return count > 0; }, @@ -199,12 +230,12 @@ export const UserRepository = db.getRepository(User).extend({ const dbResolver = new DbResolver(); let local = await dbResolver.getUserFromApId(uri); if (local) { - return local; - } + return local; + } // fetching Object once from remote const resolver = new Resolver(); - const object = await resolver.resolve(uri) as any; + const object = (await resolver.resolve(uri)) as any; // /@user If a URI other than the id is specified, // the URI is determined here @@ -216,38 +247,46 @@ export const UserRepository = db.getRepository(User).extend({ return isActor(object) ? await createPerson(getApId(object)) : null; }, - async getHasUnreadAntenna(userId: User['id']): Promise { - const myAntennas = (await getAntennas()).filter(a => a.userId === userId); + async getHasUnreadAntenna(userId: User["id"]): Promise { + const myAntennas = (await getAntennas()).filter((a) => a.userId === userId); - const unread = myAntennas.length > 0 ? await AntennaNotes.findOneBy({ - antennaId: In(myAntennas.map(x => x.id)), - read: false, - }) : null; + const unread = + myAntennas.length > 0 + ? await AntennaNotes.findOneBy({ + antennaId: In(myAntennas.map((x) => x.id)), + read: false, + }) + : null; return unread != null; }, - async getHasUnreadChannel(userId: User['id']): Promise { + async getHasUnreadChannel(userId: User["id"]): Promise { const channels = await ChannelFollowings.findBy({ followerId: userId }); - const unread = channels.length > 0 ? await NoteUnreads.findOneBy({ - userId: userId, - noteChannelId: In(channels.map(x => x.followeeId)), - }) : null; + const unread = + channels.length > 0 + ? await NoteUnreads.findOneBy({ + userId: userId, + noteChannelId: In(channels.map((x) => x.followeeId)), + }) + : null; return unread != null; }, - async getHasUnreadNotification(userId: User['id']): Promise { + async getHasUnreadNotification(userId: User["id"]): Promise { const mute = await Mutings.findBy({ muterId: userId, }); - const mutedUserIds = mute.map(m => m.muteeId); + const mutedUserIds = mute.map((m) => m.muteeId); const count = await Notifications.count({ where: { notifieeId: userId, - ...(mutedUserIds.length > 0 ? { notifierId: Not(In(mutedUserIds)) } : {}), + ...(mutedUserIds.length > 0 + ? { notifierId: Not(In(mutedUserIds)) } + : {}), isRead: false, }, take: 1, @@ -256,7 +295,9 @@ export const UserRepository = db.getRepository(User).extend({ return count > 0; }, - async getHasPendingReceivedFollowRequest(userId: User['id']): Promise { + async getHasPendingReceivedFollowRequest( + userId: User["id"], + ): Promise { const count = await FollowRequests.countBy({ followeeId: userId, }); @@ -264,23 +305,28 @@ export const UserRepository = db.getRepository(User).extend({ return count > 0; }, - getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' { - if (user.hideOnlineStatus) return 'unknown'; - if (user.lastActiveDate == null) return 'unknown'; + getOnlineStatus(user: User): "unknown" | "online" | "active" | "offline" { + if (user.hideOnlineStatus) return "unknown"; + if (user.lastActiveDate == null) return "unknown"; const elapsed = Date.now() - user.lastActiveDate.getTime(); - return ( - elapsed < USER_ONLINE_THRESHOLD ? 'online' : - elapsed < USER_ACTIVE_THRESHOLD ? 'active' : - 'offline' - ); + return elapsed < USER_ONLINE_THRESHOLD + ? "online" + : elapsed < USER_ACTIVE_THRESHOLD + ? "active" + : "offline"; }, async getAvatarUrl(user: User): Promise { if (user.avatar) { - return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); + return ( + DriveFiles.getPublicUrl(user.avatar, true) || + this.getIdenticonUrl(user.id) + ); } else if (user.avatarId) { const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId }); - return DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id); + return ( + DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id) + ); } else { return this.getIdenticonUrl(user.id); } @@ -288,35 +334,46 @@ export const UserRepository = db.getRepository(User).extend({ getAvatarUrlSync(user: User): string { if (user.avatar) { - return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); + return ( + DriveFiles.getPublicUrl(user.avatar, true) || + this.getIdenticonUrl(user.id) + ); } else { return this.getIdenticonUrl(user.id); } }, - getIdenticonUrl(userId: User['id']): string { + getIdenticonUrl(userId: User["id"]): string { return `${config.url}/identicon/${userId}`; }, - async pack( - src: User['id'] | User, - me?: { id: User['id'] } | null | undefined, + async pack< + ExpectsMe extends boolean | null = null, + D extends boolean = false, + >( + src: User["id"] | User, + me?: { id: User["id"] } | null | undefined, options?: { - detail?: D, - includeSecrets?: boolean, + detail?: D; + includeSecrets?: boolean; }, ): Promise> { - const opts = Object.assign({ - detail: false, - includeSecrets: false, - }, options); + const opts = Object.assign( + { + detail: false, + includeSecrets: false, + }, + options, + ); let user: User; - if (typeof src === 'object') { + if (typeof src === "object") { user = src; - if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOneBy({ id: src.avatarId }) ?? null; - if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOneBy({ id: src.bannerId }) ?? null; + if (src.avatar === undefined && src.avatarId) + src.avatar = (await DriveFiles.findOneBy({ id: src.avatarId })) ?? null; + if (src.banner === undefined && src.bannerId) + src.banner = (await DriveFiles.findOneBy({ id: src.bannerId })) ?? null; } else { user = await this.findOneOrFail({ where: { id: src }, @@ -330,23 +387,42 @@ export const UserRepository = db.getRepository(User).extend({ const meId = me ? me.id : null; const isMe = meId === user.id; - const relation = meId && !isMe && opts.detail ? await this.getRelation(meId, user.id) : null; - const pins = opts.detail ? await UserNotePinings.createQueryBuilder('pin') - .where('pin.userId = :userId', { userId: user.id }) - .innerJoinAndSelect('pin.note', 'note') - .orderBy('pin.id', 'DESC') - .getMany() : []; - const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null; + const relation = + meId && !isMe && opts.detail + ? await this.getRelation(meId, user.id) + : null; + const pins = opts.detail + ? await UserNotePinings.createQueryBuilder("pin") + .where("pin.userId = :userId", { userId: user.id }) + .innerJoinAndSelect("pin.note", "note") + .orderBy("pin.id", "DESC") + .getMany() + : []; + const profile = opts.detail + ? await UserProfiles.findOneByOrFail({ userId: user.id }) + : null; - const followingCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followingCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : - null; + const followingCount = + profile == null + ? null + : profile.ffVisibility === "public" || isMe + ? user.followingCount + : profile.ffVisibility === "followers" && + relation && + relation.isFollowing + ? user.followingCount + : null; - const followersCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followersCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : - null; + const followersCount = + profile == null + ? null + : profile.ffVisibility === "public" || isMe + ? user.followersCount + : profile.ffVisibility === "followers" && + relation && + relation.isFollowing + ? user.followersCount + : null; const falsy = opts.detail ? false : undefined; @@ -362,135 +438,170 @@ export const UserRepository = db.getRepository(User).extend({ isModerator: user.isModerator || falsy, isBot: user.isBot || falsy, isCat: user.isCat || falsy, - instance: user.host ? userInstanceCache.fetch(user.host, - () => Instances.findOneBy({ host: user.host! }), - v => v != null, - ).then(instance => instance ? { - name: instance.name, - softwareName: instance.softwareName, - softwareVersion: instance.softwareVersion, - iconUrl: instance.iconUrl, - faviconUrl: instance.faviconUrl, - themeColor: instance.themeColor, - } : undefined) : undefined, + instance: user.host + ? userInstanceCache + .fetch( + user.host, + () => Instances.findOneBy({ host: user.host! }), + (v) => v != null, + ) + .then((instance) => + instance + ? { + name: instance.name, + softwareName: instance.softwareName, + softwareVersion: instance.softwareVersion, + iconUrl: instance.iconUrl, + faviconUrl: instance.faviconUrl, + themeColor: instance.themeColor, + } + : undefined, + ) + : undefined, emojis: populateEmojis(user.emojis, user.host), onlineStatus: this.getOnlineStatus(user), driveCapacityOverrideMb: user.driveCapacityOverrideMb, - ...(opts.detail ? { - url: profile!.url, - uri: user.uri, - movedToUri: user.movedToUri ? await this.userFromURI(user.movedToUri) : null, - alsoKnownAs: user.alsoKnownAs, - createdAt: user.createdAt.toISOString(), - updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, - lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, - bannerUrl: user.banner ? DriveFiles.getPublicUrl(user.banner, false) : null, - bannerBlurhash: user.banner?.blurhash || null, - bannerColor: null, // 後方互換性のため - isLocked: user.isLocked, - isSilenced: user.isSilenced || falsy, - isSuspended: user.isSuspended || falsy, - description: profile!.description, - location: profile!.location, - birthday: profile!.birthday, - lang: profile!.lang, - fields: profile!.fields, - followersCount: followersCount || 0, - followingCount: followingCount || 0, - notesCount: user.notesCount, - pinnedNoteIds: pins.map(pin => pin.noteId), - pinnedNotes: Notes.packMany(pins.map(pin => pin.note!), me, { - detail: true, - }), - pinnedPageId: profile!.pinnedPageId, - pinnedPage: profile!.pinnedPageId ? Pages.pack(profile!.pinnedPageId, me) : null, - publicReactions: profile!.publicReactions, - ffVisibility: profile!.ffVisibility, - twoFactorEnabled: profile!.twoFactorEnabled, - usePasswordLessLogin: profile!.usePasswordLessLogin, - securityKeys: profile!.twoFactorEnabled - ? UserSecurityKeys.countBy({ - userId: user.id, - }).then(result => result >= 1) - : false, - } : {}), + ...(opts.detail + ? { + url: profile!.url, + uri: user.uri, + movedToUri: user.movedToUri + ? await this.userFromURI(user.movedToUri) + : null, + alsoKnownAs: user.alsoKnownAs, + createdAt: user.createdAt.toISOString(), + updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, + lastFetchedAt: user.lastFetchedAt + ? user.lastFetchedAt.toISOString() + : null, + bannerUrl: user.banner + ? DriveFiles.getPublicUrl(user.banner, false) + : null, + bannerBlurhash: user.banner?.blurhash || null, + bannerColor: null, // 後方互換性のため + isLocked: user.isLocked, + isSilenced: user.isSilenced || falsy, + isSuspended: user.isSuspended || falsy, + description: profile!.description, + location: profile!.location, + birthday: profile!.birthday, + lang: profile!.lang, + fields: profile!.fields, + followersCount: followersCount || 0, + followingCount: followingCount || 0, + notesCount: user.notesCount, + pinnedNoteIds: pins.map((pin) => pin.noteId), + pinnedNotes: Notes.packMany( + pins.map((pin) => pin.note!), + me, + { + detail: true, + }, + ), + pinnedPageId: profile!.pinnedPageId, + pinnedPage: profile!.pinnedPageId + ? Pages.pack(profile!.pinnedPageId, me) + : null, + publicReactions: profile!.publicReactions, + ffVisibility: profile!.ffVisibility, + twoFactorEnabled: profile!.twoFactorEnabled, + usePasswordLessLogin: profile!.usePasswordLessLogin, + securityKeys: profile!.twoFactorEnabled + ? UserSecurityKeys.countBy({ + userId: user.id, + }).then((result) => result >= 1) + : false, + } + : {}), - ...(opts.detail && isMe ? { - avatarId: user.avatarId, - bannerId: user.bannerId, - injectFeaturedNote: profile!.injectFeaturedNote, - receiveAnnouncementEmail: profile!.receiveAnnouncementEmail, - alwaysMarkNsfw: profile!.alwaysMarkNsfw, - autoSensitive: profile!.autoSensitive, - carefulBot: profile!.carefulBot, - autoAcceptFollowed: profile!.autoAcceptFollowed, - noCrawle: profile!.noCrawle, - isExplorable: user.isExplorable, - isDeleted: user.isDeleted, - hideOnlineStatus: user.hideOnlineStatus, - hasUnreadSpecifiedNotes: NoteUnreads.count({ - where: { userId: user.id, isSpecified: true }, - take: 1, - }).then(count => count > 0), - hasUnreadMentions: NoteUnreads.count({ - where: { userId: user.id, isMentioned: true }, - take: 1, - }).then(count => count > 0), - hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id), - hasUnreadAntenna: this.getHasUnreadAntenna(user.id), - hasUnreadChannel: this.getHasUnreadChannel(user.id), - hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage(user.id), - hasUnreadNotification: this.getHasUnreadNotification(user.id), - hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id), - integrations: profile!.integrations, - mutedWords: profile!.mutedWords, - mutedInstances: profile!.mutedInstances, - mutingNotificationTypes: profile!.mutingNotificationTypes, - emailNotificationTypes: profile!.emailNotificationTypes, - showTimelineReplies: user.showTimelineReplies || falsy, - } : {}), + ...(opts.detail && isMe + ? { + avatarId: user.avatarId, + bannerId: user.bannerId, + injectFeaturedNote: profile!.injectFeaturedNote, + receiveAnnouncementEmail: profile!.receiveAnnouncementEmail, + alwaysMarkNsfw: profile!.alwaysMarkNsfw, + autoSensitive: profile!.autoSensitive, + carefulBot: profile!.carefulBot, + autoAcceptFollowed: profile!.autoAcceptFollowed, + noCrawle: profile!.noCrawle, + isExplorable: user.isExplorable, + isDeleted: user.isDeleted, + hideOnlineStatus: user.hideOnlineStatus, + hasUnreadSpecifiedNotes: NoteUnreads.count({ + where: { userId: user.id, isSpecified: true }, + take: 1, + }).then((count) => count > 0), + hasUnreadMentions: NoteUnreads.count({ + where: { userId: user.id, isMentioned: true }, + take: 1, + }).then((count) => count > 0), + hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id), + hasUnreadAntenna: this.getHasUnreadAntenna(user.id), + hasUnreadChannel: this.getHasUnreadChannel(user.id), + hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage( + user.id, + ), + hasUnreadNotification: this.getHasUnreadNotification(user.id), + hasPendingReceivedFollowRequest: + this.getHasPendingReceivedFollowRequest(user.id), + integrations: profile!.integrations, + mutedWords: profile!.mutedWords, + mutedInstances: profile!.mutedInstances, + mutingNotificationTypes: profile!.mutingNotificationTypes, + emailNotificationTypes: profile!.emailNotificationTypes, + showTimelineReplies: user.showTimelineReplies || falsy, + } + : {}), - ...(opts.includeSecrets ? { - email: profile!.email, - emailVerified: profile!.emailVerified, - securityKeysList: profile!.twoFactorEnabled - ? UserSecurityKeys.find({ - where: { - userId: user.id, - }, - select: { - id: true, - name: true, - lastUsed: true, - }, - }) - : [], - } : {}), + ...(opts.includeSecrets + ? { + email: profile!.email, + emailVerified: profile!.emailVerified, + securityKeysList: profile!.twoFactorEnabled + ? UserSecurityKeys.find({ + where: { + userId: user.id, + }, + select: { + id: true, + name: true, + lastUsed: true, + }, + }) + : [], + } + : {}), - ...(relation ? { - isFollowing: relation.isFollowing, - isFollowed: relation.isFollowed, - hasPendingFollowRequestFromYou: relation.hasPendingFollowRequestFromYou, - hasPendingFollowRequestToYou: relation.hasPendingFollowRequestToYou, - isBlocking: relation.isBlocking, - isBlocked: relation.isBlocked, - isMuted: relation.isMuted, - } : {}), - } as Promiseable> as Promiseable>; + ...(relation + ? { + isFollowing: relation.isFollowing, + isFollowed: relation.isFollowed, + hasPendingFollowRequestFromYou: + relation.hasPendingFollowRequestFromYou, + hasPendingFollowRequestToYou: relation.hasPendingFollowRequestToYou, + isBlocking: relation.isBlocking, + isBlocked: relation.isBlocked, + isMuted: relation.isMuted, + } + : {}), + } as Promiseable> as Promiseable< + IsMeAndIsUserDetailed + >; return await awaitAll(packed); }, packMany( - users: (User['id'] | User)[], - me?: { id: User['id'] } | null | undefined, + users: (User["id"] | User)[], + me?: { id: User["id"] } | null | undefined, options?: { - detail?: D, - includeSecrets?: boolean, + detail?: D; + includeSecrets?: boolean; }, ): Promise[]> { - return Promise.all(users.map(u => this.pack(u, me, options))); + return Promise.all(users.map((u) => this.pack(u, me, options))); }, isLocalUser, diff --git a/packages/backend/src/models/schema/antenna.ts b/packages/backend/src/models/schema/antenna.ts index 9cf522802..c7eed092e 100644 --- a/packages/backend/src/models/schema/antenna.ts +++ b/packages/backend/src/models/schema/antenna.ts @@ -1,88 +1,107 @@ export const packedAntennaSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, keywords: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, excludeKeywords: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, src: { - type: 'string', - optional: false, nullable: false, - enum: ['home', 'all', 'users', 'list', 'group'], + type: "string", + optional: false, + nullable: false, + enum: ["home", "all", "users", "list", "group"], }, userListId: { - type: 'string', - optional: false, nullable: true, - format: 'id', + type: "string", + optional: false, + nullable: true, + format: "id", }, userGroupId: { - type: 'string', - optional: false, nullable: true, - format: 'id', + type: "string", + optional: false, + nullable: true, + format: "id", }, users: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, caseSensitive: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, default: false, }, notify: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, withReplies: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, default: false, }, withFile: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hasUnreadNote: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, default: false, }, }, diff --git a/packages/backend/src/models/schema/app.ts b/packages/backend/src/models/schema/app.ts index c80dc81c3..8ec71159a 100644 --- a/packages/backend/src/models/schema/app.ts +++ b/packages/backend/src/models/schema/app.ts @@ -1,33 +1,40 @@ export const packedAppSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, callbackUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, permission: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, secret: { - type: 'string', - optional: true, nullable: false, + type: "string", + optional: true, + nullable: false, }, isAuthorized: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/blocking.ts b/packages/backend/src/models/schema/blocking.ts index 553232242..1d491e939 100644 --- a/packages/backend/src/models/schema/blocking.ts +++ b/packages/backend/src/models/schema/blocking.ts @@ -1,26 +1,30 @@ export const packedBlockingSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, blockeeId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, blockee: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; diff --git a/packages/backend/src/models/schema/channel.ts b/packages/backend/src/models/schema/channel.ts index 7f4f2a48b..67833cb0d 100644 --- a/packages/backend/src/models/schema/channel.ts +++ b/packages/backend/src/models/schema/channel.ts @@ -1,51 +1,61 @@ export const packedChannelSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, lastNotedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, description: { - type: 'string', - nullable: true, optional: false, + type: "string", + nullable: true, + optional: false, }, bannerUrl: { - type: 'string', - format: 'url', - nullable: true, optional: false, + type: "string", + format: "url", + nullable: true, + optional: false, }, notesCount: { - type: 'number', - nullable: false, optional: false, + type: "number", + nullable: false, + optional: false, }, usersCount: { - type: 'number', - nullable: false, optional: false, + type: "number", + nullable: false, + optional: false, }, isFollowing: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, userId: { - type: 'string', - nullable: true, optional: false, - format: 'id', + type: "string", + nullable: true, + optional: false, + format: "id", }, }, } as const; diff --git a/packages/backend/src/models/schema/clip.ts b/packages/backend/src/models/schema/clip.ts index f0ee2ce0c..651303ad9 100644 --- a/packages/backend/src/models/schema/clip.ts +++ b/packages/backend/src/models/schema/clip.ts @@ -1,38 +1,45 @@ export const packedClipSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + type: "object", + ref: "UserLite", + optional: false, + nullable: false, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, description: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, isPublic: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/drive-file.ts b/packages/backend/src/models/schema/drive-file.ts index 435907661..30db9e7d4 100644 --- a/packages/backend/src/models/schema/drive-file.ts +++ b/packages/backend/src/models/schema/drive-file.ts @@ -1,107 +1,127 @@ export const packedDriveFileSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, - example: 'lenna.jpg', + type: "string", + optional: false, + nullable: false, + example: "lenna.jpg", }, type: { - type: 'string', - optional: false, nullable: false, - example: 'image/jpeg', + type: "string", + optional: false, + nullable: false, + example: "image/jpeg", }, md5: { - type: 'string', - optional: false, nullable: false, - format: 'md5', - example: '15eca7fba0480996e2245f5185bf39f2', + type: "string", + optional: false, + nullable: false, + format: "md5", + example: "15eca7fba0480996e2245f5185bf39f2", }, size: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, example: 51469, }, isSensitive: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, blurhash: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, properties: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { width: { - type: 'number', - optional: true, nullable: false, + type: "number", + optional: true, + nullable: false, example: 1280, }, height: { - type: 'number', - optional: true, nullable: false, + type: "number", + optional: true, + nullable: false, example: 720, }, orientation: { - type: 'number', - optional: true, nullable: false, + type: "number", + optional: true, + nullable: false, example: 8, }, avgColor: { - type: 'string', - optional: true, nullable: false, - example: 'rgb(40,65,87)', + type: "string", + optional: true, + nullable: false, + example: "rgb(40,65,87)", }, }, }, url: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, thumbnailUrl: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, comment: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, folderId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, folder: { - type: 'object', - optional: true, nullable: true, - ref: 'DriveFolder', + type: "object", + optional: true, + nullable: true, + ref: "DriveFolder", }, userId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, user: { - type: 'object', - optional: true, nullable: true, - ref: 'UserLite', + type: "object", + optional: true, + nullable: true, + ref: "UserLite", }, }, } as const; diff --git a/packages/backend/src/models/schema/drive-folder.ts b/packages/backend/src/models/schema/drive-folder.ts index 88cb8ab4a..2298b5420 100644 --- a/packages/backend/src/models/schema/drive-folder.ts +++ b/packages/backend/src/models/schema/drive-folder.ts @@ -1,39 +1,46 @@ export const packedDriveFolderSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, foldersCount: { - type: 'number', - optional: true, nullable: false, + type: "number", + optional: true, + nullable: false, }, filesCount: { - type: 'number', - optional: true, nullable: false, + type: "number", + optional: true, + nullable: false, }, parentId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, parent: { - type: 'object', - optional: true, nullable: true, - ref: 'DriveFolder', + type: "object", + optional: true, + nullable: true, + ref: "DriveFolder", }, }, } as const; diff --git a/packages/backend/src/models/schema/emoji.ts b/packages/backend/src/models/schema/emoji.ts index e97fdd5ef..1e1dab868 100644 --- a/packages/backend/src/models/schema/emoji.ts +++ b/packages/backend/src/models/schema/emoji.ts @@ -1,37 +1,44 @@ export const packedEmojiSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, aliases: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, category: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, host: { - type: 'string', - optional: false, nullable: true, - description: 'The local host is represented with `null`.', + type: "string", + optional: false, + nullable: true, + description: "The local host is represented with `null`.", }, url: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts index e35f5ecb8..ed3369bf1 100644 --- a/packages/backend/src/models/schema/federation-instance.ts +++ b/packages/backend/src/models/schema/federation-instance.ts @@ -1,110 +1,133 @@ -import config from '@/config/index.js'; +import config from "@/config/index.js"; export const packedFederationInstanceSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, caughtAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, host: { - type: 'string', - optional: false, nullable: false, - example: 'calckey.example.com', + type: "string", + optional: false, + nullable: false, + example: "calckey.example.com", }, usersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, notesCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, followingCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, followersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, latestRequestSentAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, lastCommunicatedAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, isNotResponding: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isSuspended: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isBlocked: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, softwareName: { - type: 'string', - optional: false, nullable: true, - example: 'calckey', + type: "string", + optional: false, + nullable: true, + example: "calckey", }, softwareVersion: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, example: config.version, }, openRegistrations: { - type: 'boolean', - optional: false, nullable: true, + type: "boolean", + optional: false, + nullable: true, example: true, }, name: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, description: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, maintainerName: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, maintainerEmail: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, iconUrl: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, faviconUrl: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, themeColor: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, infoUpdatedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, }, } as const; diff --git a/packages/backend/src/models/schema/following.ts b/packages/backend/src/models/schema/following.ts index 2bcffbfc4..f53cafaba 100644 --- a/packages/backend/src/models/schema/following.ts +++ b/packages/backend/src/models/schema/following.ts @@ -1,36 +1,42 @@ export const packedFollowingSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, followeeId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, followee: { - type: 'object', - optional: true, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: true, + nullable: false, + ref: "UserDetailed", }, followerId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, follower: { - type: 'object', - optional: true, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: true, + nullable: false, + ref: "UserDetailed", }, }, } as const; diff --git a/packages/backend/src/models/schema/gallery-post.ts b/packages/backend/src/models/schema/gallery-post.ts index fc503d4a6..9ac348e1f 100644 --- a/packages/backend/src/models/schema/gallery-post.ts +++ b/packages/backend/src/models/schema/gallery-post.ts @@ -1,69 +1,83 @@ export const packedGalleryPostSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, updatedAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, title: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, description: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + type: "object", + ref: "UserLite", + optional: false, + nullable: false, }, fileIds: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, files: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, tags: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, isSensitive: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/hashtag.ts b/packages/backend/src/models/schema/hashtag.ts index 7245535c4..dacc51507 100644 --- a/packages/backend/src/models/schema/hashtag.ts +++ b/packages/backend/src/models/schema/hashtag.ts @@ -1,34 +1,41 @@ export const packedHashtagSchema = { - type: 'object', + type: "object", properties: { tag: { - type: 'string', - optional: false, nullable: false, - example: 'calckey', + type: "string", + optional: false, + nullable: false, + example: "calckey", }, mentionedUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, mentionedLocalUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, mentionedRemoteUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, attachedUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, attachedLocalUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, attachedRemoteUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/messaging-message.ts b/packages/backend/src/models/schema/messaging-message.ts index b1ffa4595..d598e6dbc 100644 --- a/packages/backend/src/models/schema/messaging-message.ts +++ b/packages/backend/src/models/schema/messaging-message.ts @@ -1,72 +1,86 @@ export const packedMessagingMessageSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - ref: 'UserLite', - optional: true, nullable: false, + type: "object", + ref: "UserLite", + optional: true, + nullable: false, }, text: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, fileId: { - type: 'string', - optional: true, nullable: true, - format: 'id', + type: "string", + optional: true, + nullable: true, + format: "id", }, file: { - type: 'object', - optional: true, nullable: true, - ref: 'DriveFile', + type: "object", + optional: true, + nullable: true, + ref: "DriveFile", }, recipientId: { - type: 'string', - optional: false, nullable: true, - format: 'id', + type: "string", + optional: false, + nullable: true, + format: "id", }, recipient: { - type: 'object', - optional: true, nullable: true, - ref: 'UserLite', + type: "object", + optional: true, + nullable: true, + ref: "UserLite", }, groupId: { - type: 'string', - optional: false, nullable: true, - format: 'id', + type: "string", + optional: false, + nullable: true, + format: "id", }, group: { - type: 'object', - optional: true, nullable: true, - ref: 'UserGroup', + type: "object", + optional: true, + nullable: true, + ref: "UserGroup", }, isRead: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, reads: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, }, diff --git a/packages/backend/src/models/schema/muting.ts b/packages/backend/src/models/schema/muting.ts index 3ab99e17e..d5815f86d 100644 --- a/packages/backend/src/models/schema/muting.ts +++ b/packages/backend/src/models/schema/muting.ts @@ -1,31 +1,36 @@ export const packedMutingSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, expiresAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, muteeId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, mutee: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; diff --git a/packages/backend/src/models/schema/note-favorite.ts b/packages/backend/src/models/schema/note-favorite.ts index d133f7367..17a42baf0 100644 --- a/packages/backend/src/models/schema/note-favorite.ts +++ b/packages/backend/src/models/schema/note-favorite.ts @@ -1,26 +1,30 @@ export const packedNoteFavoriteSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, note: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, noteId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, } as const; diff --git a/packages/backend/src/models/schema/note-reaction.ts b/packages/backend/src/models/schema/note-reaction.ts index 0d8fc5449..1080bdcf5 100644 --- a/packages/backend/src/models/schema/note-reaction.ts +++ b/packages/backend/src/models/schema/note-reaction.ts @@ -1,25 +1,29 @@ export const packedNoteReactionSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, user: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, type: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts index 292bbb82f..4a7bd80fc 100644 --- a/packages/backend/src/models/schema/note.ts +++ b/packages/backend/src/models/schema/note.ts @@ -1,179 +1,217 @@ export const packedNoteSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, text: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, cw: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + type: "object", + ref: "UserLite", + optional: false, + nullable: false, }, replyId: { - type: 'string', - optional: true, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: true, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, renoteId: { - type: 'string', - optional: true, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: true, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, reply: { - type: 'object', - optional: true, nullable: true, - ref: 'Note', + type: "object", + optional: true, + nullable: true, + ref: "Note", }, renote: { - type: 'object', - optional: true, nullable: true, - ref: 'Note', + type: "object", + optional: true, + nullable: true, + ref: "Note", }, visibility: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, mentions: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, visibleUserIds: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, fileIds: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, files: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, tags: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, poll: { - type: 'object', - optional: true, nullable: true, + type: "object", + optional: true, + nullable: true, }, channelId: { - type: 'string', - optional: true, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: true, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, channel: { - type: 'object', - optional: true, nullable: true, + type: "object", + optional: true, + nullable: true, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, name: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, }, }, }, localOnly: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, emojis: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, url: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, }, }, }, reactions: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, }, renoteCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, repliesCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, uri: { - type: 'string', - optional: true, nullable: false, + type: "string", + optional: true, + nullable: false, }, url: { - type: 'string', - optional: true, nullable: false, + type: "string", + optional: true, + nullable: false, }, myReaction: { - type: 'object', - optional: true, nullable: true, + type: "object", + optional: true, + nullable: true, }, }, } as const; diff --git a/packages/backend/src/models/schema/notification.ts b/packages/backend/src/models/schema/notification.ts index d3f2405cd..97fd16339 100644 --- a/packages/backend/src/models/schema/notification.ts +++ b/packages/backend/src/models/schema/notification.ts @@ -1,66 +1,79 @@ -import { notificationTypes } from '@/types.js'; +import { notificationTypes } from "@/types.js"; export const packedNotificationSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, isRead: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, type: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, enum: [...notificationTypes], }, user: { - type: 'object', - ref: 'UserLite', - optional: true, nullable: true, + type: "object", + ref: "UserLite", + optional: true, + nullable: true, }, userId: { - type: 'string', - optional: true, nullable: true, - format: 'id', + type: "string", + optional: true, + nullable: true, + format: "id", }, note: { - type: 'object', - ref: 'Note', - optional: true, nullable: true, + type: "object", + ref: "Note", + optional: true, + nullable: true, }, reaction: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, choice: { - type: 'number', - optional: true, nullable: true, + type: "number", + optional: true, + nullable: true, }, invitation: { - type: 'object', - optional: true, nullable: true, + type: "object", + optional: true, + nullable: true, }, body: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, header: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, icon: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, }, } as const; diff --git a/packages/backend/src/models/schema/page.ts b/packages/backend/src/models/schema/page.ts index 19074947b..a1b9144b5 100644 --- a/packages/backend/src/models/schema/page.ts +++ b/packages/backend/src/models/schema/page.ts @@ -1,55 +1,66 @@ export const packedPageSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, updatedAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, title: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, summary: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, content: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, }, variables: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, + type: "object", + ref: "UserLite", + optional: false, + nullable: false, }, isPublic: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/queue.ts b/packages/backend/src/models/schema/queue.ts index 7ceeda26a..954ac688b 100644 --- a/packages/backend/src/models/schema/queue.ts +++ b/packages/backend/src/models/schema/queue.ts @@ -1,25 +1,30 @@ export const packedQueueCountSchema = { - type: 'object', + type: "object", properties: { waiting: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, active: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, completed: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, failed: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, delayed: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, } as const; diff --git a/packages/backend/src/models/schema/user-group.ts b/packages/backend/src/models/schema/user-group.ts index a73bf82bb..a4a85f969 100644 --- a/packages/backend/src/models/schema/user-group.ts +++ b/packages/backend/src/models/schema/user-group.ts @@ -1,33 +1,39 @@ export const packedUserGroupSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, ownerId: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, userIds: { - type: 'array', - nullable: false, optional: true, + type: "array", + nullable: false, + optional: true, items: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, }, }, diff --git a/packages/backend/src/models/schema/user-list.ts b/packages/backend/src/models/schema/user-list.ts index 3ba5dc4a8..1e203b63a 100644 --- a/packages/backend/src/models/schema/user-list.ts +++ b/packages/backend/src/models/schema/user-list.ts @@ -1,28 +1,33 @@ export const packedUserListSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, userIds: { - type: 'array', - nullable: false, optional: true, + type: "array", + nullable: false, + optional: true, items: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, }, }, diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts index b70210a0f..9fb5aa8f3 100644 --- a/packages/backend/src/models/schema/user.ts +++ b/packages/backend/src/models/schema/user.ts @@ -1,422 +1,513 @@ export const packedUserLiteSchema = { - type: 'object', + type: "object", properties: { id: { - type: 'string', - nullable: false, optional: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + nullable: false, + optional: false, + format: "id", + example: "xxxxxxxxxx", }, name: { - type: 'string', - nullable: true, optional: false, - example: '藍', + type: "string", + nullable: true, + optional: false, + example: "藍", }, username: { - type: 'string', - nullable: false, optional: false, - example: 'calc', + type: "string", + nullable: false, + optional: false, + example: "calc", }, host: { - type: 'string', - nullable: true, optional: false, - example: 'misskey.example.com', - description: 'The local host is represented with `null`.', + type: "string", + nullable: true, + optional: false, + example: "misskey.example.com", + description: "The local host is represented with `null`.", }, avatarUrl: { - type: 'string', - format: 'url', - nullable: true, optional: false, + type: "string", + format: "url", + nullable: true, + optional: false, }, avatarBlurhash: { - type: 'any', - nullable: true, optional: false, + type: "any", + nullable: true, + optional: false, }, avatarColor: { - type: 'any', - nullable: true, optional: false, + type: "any", + nullable: true, + optional: false, default: null, }, isAdmin: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, default: false, }, isModerator: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, default: false, }, isBot: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, isCat: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, emojis: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'object', - nullable: false, optional: false, + type: "object", + nullable: false, + optional: false, properties: { name: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, url: { - type: 'string', - nullable: false, optional: false, - format: 'url', + type: "string", + nullable: false, + optional: false, + format: "url", }, }, }, }, onlineStatus: { - type: 'string', - format: 'url', - nullable: true, optional: false, - enum: ['unknown', 'online', 'active', 'offline'], + type: "string", + format: "url", + nullable: true, + optional: false, + enum: ["unknown", "online", "active", "offline"], }, }, } as const; export const packedUserDetailedNotMeOnlySchema = { - type: 'object', + type: "object", properties: { url: { - type: 'string', - format: 'url', - nullable: true, optional: false, + type: "string", + format: "url", + nullable: true, + optional: false, }, uri: { - type: 'string', - format: 'uri', - nullable: true, optional: false, + type: "string", + format: "uri", + nullable: true, + optional: false, }, movedToUri: { - type: 'string', - format: 'uri', - nullable: true, optional: false, + type: "string", + format: "uri", + nullable: true, + optional: false, }, alsoKnownAs: { - type: 'array', - format: 'uri', - nullable: true, optional: false, + type: "array", + format: "uri", + nullable: true, + optional: false, }, createdAt: { - type: 'string', - nullable: false, optional: false, - format: 'date-time', + type: "string", + nullable: false, + optional: false, + format: "date-time", }, updatedAt: { - type: 'string', - nullable: true, optional: false, - format: 'date-time', + type: "string", + nullable: true, + optional: false, + format: "date-time", }, lastFetchedAt: { - type: 'string', - nullable: true, optional: false, - format: 'date-time', + type: "string", + nullable: true, + optional: false, + format: "date-time", }, bannerUrl: { - type: 'string', - format: 'url', - nullable: true, optional: false, + type: "string", + format: "url", + nullable: true, + optional: false, }, bannerBlurhash: { - type: 'any', - nullable: true, optional: false, + type: "any", + nullable: true, + optional: false, }, bannerColor: { - type: 'any', - nullable: true, optional: false, + type: "any", + nullable: true, + optional: false, default: null, }, isLocked: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, isSilenced: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, isSuspended: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, example: false, }, description: { - type: 'string', - nullable: true, optional: false, - example: 'Hi masters, I am Ai!', + type: "string", + nullable: true, + optional: false, + example: "Hi masters, I am Ai!", }, location: { - type: 'string', - nullable: true, optional: false, + type: "string", + nullable: true, + optional: false, }, birthday: { - type: 'string', - nullable: true, optional: false, - example: '2018-03-12', + type: "string", + nullable: true, + optional: false, + example: "2018-03-12", }, lang: { - type: 'string', - nullable: true, optional: false, - example: 'ja-JP', + type: "string", + nullable: true, + optional: false, + example: "ja-JP", }, fields: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'object', - nullable: false, optional: false, + type: "object", + nullable: false, + optional: false, properties: { name: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, value: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, }, maxLength: 4, }, }, followersCount: { - type: 'number', - nullable: false, optional: false, + type: "number", + nullable: false, + optional: false, }, followingCount: { - type: 'number', - nullable: false, optional: false, + type: "number", + nullable: false, + optional: false, }, notesCount: { - type: 'number', - nullable: false, optional: false, + type: "number", + nullable: false, + optional: false, }, pinnedNoteIds: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, }, pinnedNotes: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'object', - nullable: false, optional: false, - ref: 'Note', + type: "object", + nullable: false, + optional: false, + ref: "Note", }, }, pinnedPageId: { - type: 'string', - nullable: true, optional: false, + type: "string", + nullable: true, + optional: false, }, pinnedPage: { - type: 'object', - nullable: true, optional: false, - ref: 'Page', + type: "object", + nullable: true, + optional: false, + ref: "Page", }, publicReactions: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, twoFactorEnabled: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, default: false, }, usePasswordLessLogin: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, default: false, }, securityKeys: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, default: false, }, //#region relations isFollowing: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, isFollowed: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, hasPendingFollowRequestFromYou: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, hasPendingFollowRequestToYou: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, isBlocking: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, isBlocked: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, isMuted: { - type: 'boolean', - nullable: false, optional: true, + type: "boolean", + nullable: false, + optional: true, }, //#endregion }, } as const; export const packedMeDetailedOnlySchema = { - type: 'object', + type: "object", properties: { avatarId: { - type: 'string', - nullable: true, optional: false, - format: 'id', + type: "string", + nullable: true, + optional: false, + format: "id", }, bannerId: { - type: 'string', - nullable: true, optional: false, - format: 'id', + type: "string", + nullable: true, + optional: false, + format: "id", }, injectFeaturedNote: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, receiveAnnouncementEmail: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, alwaysMarkNsfw: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, autoSensitive: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, carefulBot: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, autoAcceptFollowed: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, noCrawle: { - type: 'boolean', - nullable: true, optional: false, + type: "boolean", + nullable: true, + optional: false, }, isExplorable: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, isDeleted: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hideOnlineStatus: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadSpecifiedNotes: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadMentions: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadAnnouncement: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadAntenna: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadChannel: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadMessagingMessage: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasUnreadNotification: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, hasPendingReceivedFollowRequest: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, }, integrations: { - type: 'object', - nullable: true, optional: false, + type: "object", + nullable: true, + optional: false, }, mutedWords: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, }, }, mutedInstances: { - type: 'array', - nullable: true, optional: false, + type: "array", + nullable: true, + optional: false, items: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, }, mutingNotificationTypes: { - type: 'array', - nullable: true, optional: false, + type: "array", + nullable: true, + optional: false, items: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, }, emailNotificationTypes: { - type: 'array', - nullable: true, optional: false, + type: "array", + nullable: true, + optional: false, items: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, }, //#region secrets email: { - type: 'string', - nullable: true, optional: true, + type: "string", + nullable: true, + optional: true, }, emailVerified: { - type: 'boolean', - nullable: true, optional: true, + type: "boolean", + nullable: true, + optional: true, }, securityKeysList: { - type: 'array', - nullable: false, optional: true, + type: "array", + nullable: false, + optional: true, items: { - type: 'object', - nullable: false, optional: false, + type: "object", + nullable: false, + optional: false, }, }, //#endregion @@ -424,33 +515,33 @@ export const packedMeDetailedOnlySchema = { } as const; export const packedUserDetailedNotMeSchema = { - type: 'object', + type: "object", allOf: [ { - type: 'object', - ref: 'UserLite', + type: "object", + ref: "UserLite", }, { - type: 'object', - ref: 'UserDetailedNotMeOnly', + type: "object", + ref: "UserDetailedNotMeOnly", }, ], } as const; export const packedMeDetailedSchema = { - type: 'object', + type: "object", allOf: [ { - type: 'object', - ref: 'UserLite', + type: "object", + ref: "UserLite", }, { - type: 'object', - ref: 'UserDetailedNotMeOnly', + type: "object", + ref: "UserDetailedNotMeOnly", }, { - type: 'object', - ref: 'MeDetailedOnly', + type: "object", + ref: "MeDetailedOnly", }, ], } as const; @@ -458,12 +549,12 @@ export const packedMeDetailedSchema = { export const packedUserDetailedSchema = { oneOf: [ { - type: 'object', - ref: 'UserDetailedNotMe', + type: "object", + ref: "UserDetailedNotMe", }, { - type: 'object', - ref: 'MeDetailed', + type: "object", + ref: "MeDetailed", }, ], } as const; @@ -471,12 +562,12 @@ export const packedUserDetailedSchema = { export const packedUserSchema = { oneOf: [ { - type: 'object', - ref: 'UserLite', + type: "object", + ref: "UserLite", }, { - type: 'object', - ref: 'UserDetailed', + type: "object", + ref: "UserDetailed", }, ], } as const; diff --git a/packages/backend/src/prelude/array.ts b/packages/backend/src/prelude/array.ts index 0b2830cb7..71a24c89b 100644 --- a/packages/backend/src/prelude/array.ts +++ b/packages/backend/src/prelude/array.ts @@ -1,4 +1,4 @@ -import { EndoRelation, Predicate } from './relation.js'; +import type { EndoRelation, Predicate } from "./relation.js"; /** * Count the number of elements that satisfy the predicate @@ -12,7 +12,7 @@ export function countIf(f: Predicate, xs: T[]): number { * Count the number of elements that is equal to the element */ export function count(a: T, xs: T[]): number { - return countIf(x => x === a, xs); + return countIf((x) => x === a, xs); } /** @@ -27,14 +27,14 @@ export function concat(xss: T[][]): T[] { * @param sep The element to be interspersed */ export function intersperse(sep: T, xs: T[]): T[] { - return concat(xs.map(x => [sep, x])).slice(1); + return concat(xs.map((x) => [sep, x])).slice(1); } /** * Returns the array of elements that is not equal to the element */ export function erase(a: T, xs: T[]): T[] { - return xs.filter(x => x !== a); + return xs.filter((x) => x !== a); } /** @@ -42,7 +42,7 @@ export function erase(a: T, xs: T[]): T[] { * The order of result values are determined by the first array. */ export function difference(xs: T[], ys: T[]): T[] { - return xs.filter(x => !ys.includes(x)); + return xs.filter((x) => !ys.includes(x)); } /** diff --git a/packages/backend/src/prelude/await-all.ts b/packages/backend/src/prelude/await-all.ts index b955c3a5d..ce11eb87b 100644 --- a/packages/backend/src/prelude/await-all.ts +++ b/packages/backend/src/prelude/await-all.ts @@ -7,11 +7,13 @@ export async function awaitAll(obj: Promiseable): Promise { const keys = Object.keys(obj) as unknown as (keyof T)[]; const values = Object.values(obj) as any[]; - const resolvedValues = await Promise.all(values.map(value => - (!value || !value.constructor || value.constructor.name !== 'Object') - ? value - : awaitAll(value) - )); + const resolvedValues = await Promise.all( + values.map((value) => + !value?.constructor || value.constructor.name !== "Object" + ? value + : awaitAll(value), + ), + ); for (let i = 0; i < keys.length; i++) { target[keys[i]] = resolvedValues[i]; diff --git a/packages/backend/src/prelude/string.ts b/packages/backend/src/prelude/string.ts index b907e0a2e..9588825cb 100644 --- a/packages/backend/src/prelude/string.ts +++ b/packages/backend/src/prelude/string.ts @@ -1,5 +1,5 @@ export function concat(xs: string[]): string { - return xs.join(''); + return xs.join(""); } export function capitalize(s: string): string { diff --git a/packages/backend/src/prelude/symbol.ts b/packages/backend/src/prelude/symbol.ts index 51e12f745..5b88467d4 100644 --- a/packages/backend/src/prelude/symbol.ts +++ b/packages/backend/src/prelude/symbol.ts @@ -1 +1 @@ -export const fallback = Symbol('fallback'); +export const fallback = Symbol("fallback"); diff --git a/packages/backend/src/prelude/time.ts b/packages/backend/src/prelude/time.ts index 0da1f7913..5901b9c48 100644 --- a/packages/backend/src/prelude/time.ts +++ b/packages/backend/src/prelude/time.ts @@ -1,19 +1,26 @@ const dateTimeIntervals = { - 'day': 86400000, - 'hour': 3600000, - 'ms': 1, + day: 86400000, + hour: 3600000, + ms: 1, }; export function dateUTC(time: number[]): Date { - const d = time.length === 2 ? Date.UTC(time[0], time[1]) - : time.length === 3 ? Date.UTC(time[0], time[1], time[2]) - : time.length === 4 ? Date.UTC(time[0], time[1], time[2], time[3]) - : time.length === 5 ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) - : time.length === 6 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) - : time.length === 7 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) - : null; + const d = + time.length === 2 + ? Date.UTC(time[0], time[1]) + : time.length === 3 + ? Date.UTC(time[0], time[1], time[2]) + : time.length === 4 + ? Date.UTC(time[0], time[1], time[2], time[3]) + : time.length === 5 + ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) + : time.length === 6 + ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) + : time.length === 7 + ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) + : null; - if (!d) throw new Error('wrong number of arguments'); + if (!d) throw new Error("wrong number of arguments"); return new Date(d); } @@ -23,17 +30,25 @@ export function isTimeSame(a: Date, b: Date): boolean { } export function isTimeBefore(a: Date, b: Date): boolean { - return (a.getTime() - b.getTime()) < 0; + return a.getTime() - b.getTime() < 0; } export function isTimeAfter(a: Date, b: Date): boolean { - return (a.getTime() - b.getTime()) > 0; + return a.getTime() - b.getTime() > 0; } -export function addTime(x: Date, value: number, span: keyof typeof dateTimeIntervals = 'ms'): Date { - return new Date(x.getTime() + (value * dateTimeIntervals[span])); +export function addTime( + x: Date, + value: number, + span: keyof typeof dateTimeIntervals = "ms", +): Date { + return new Date(x.getTime() + value * dateTimeIntervals[span]); } -export function subtractTime(x: Date, value: number, span: keyof typeof dateTimeIntervals = 'ms'): Date { - return new Date(x.getTime() - (value * dateTimeIntervals[span])); +export function subtractTime( + x: Date, + value: number, + span: keyof typeof dateTimeIntervals = "ms", +): Date { + return new Date(x.getTime() - value * dateTimeIntervals[span]); } diff --git a/packages/backend/src/prelude/url.ts b/packages/backend/src/prelude/url.ts index a4f2f7f5a..9e3f3f7c1 100644 --- a/packages/backend/src/prelude/url.ts +++ b/packages/backend/src/prelude/url.ts @@ -1,13 +1,15 @@ export function query(obj: Record): string { const params = Object.entries(obj) - .filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined) - .reduce((a, [k, v]) => (a[k] = v, a), {} as Record); + .filter(([, v]) => (Array.isArray(v) ? v.length : v !== undefined)) + .reduce((a, [k, v]) => ((a[k] = v), a), {} as Record); return Object.entries(params) .map((e) => `${e[0]}=${encodeURIComponent(e[1])}`) - .join('&'); + .join("&"); } export function appendQuery(url: string, query: string): string { - return `${url}${/\?/.test(url) ? url.endsWith('?') ? '' : '&' : '?'}${query}`; + return `${url}${ + /\?/.test(url) ? (url.endsWith("?") ? "" : "&") : "?" + }${query}`; } diff --git a/packages/backend/src/prelude/xml.ts b/packages/backend/src/prelude/xml.ts index b4469a1d8..9dcc4c96f 100644 --- a/packages/backend/src/prelude/xml.ts +++ b/packages/backend/src/prelude/xml.ts @@ -1,21 +1,18 @@ const map: Record = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''', + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", }; -const beginingOfCDATA = ''; +const beginingOfCDATA = ""; export function escapeValue(x: string): string { let insideOfCDATA = false; - let builder = ''; - for ( - let i = 0; - i < x.length; - ) { + let builder = ""; + for (let i = 0; i < x.length; ) { if (insideOfCDATA) { if (x.slice(i, i + beginingOfCDATA.length) === beginingOfCDATA) { insideOfCDATA = true; diff --git a/packages/backend/src/queue/get-job-info.ts b/packages/backend/src/queue/get-job-info.ts index d33e349c3..ae3532cda 100644 --- a/packages/backend/src/queue/get-job-info.ts +++ b/packages/backend/src/queue/get-job-info.ts @@ -1,11 +1,14 @@ -import Bull from 'bull'; +import type Bull from "bull"; export function getJobInfo(job: Bull.Job, increment = false) { const age = Date.now() - job.timestamp; - const formated = age > 60000 ? `${Math.floor(age / 1000 / 60)}m` - : age > 10000 ? `${Math.floor(age / 1000)}s` - : `${age}ms`; + const formated = + age > 60000 + ? `${Math.floor(age / 1000 / 60)}m` + : age > 10000 + ? `${Math.floor(age / 1000)}s` + : `${age}ms`; // onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする const currentAttempts = job.attemptsMade + (increment ? 1 : 0); diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts index ebb3a77ca..c40b3c6ae 100644 --- a/packages/backend/src/queue/index.ts +++ b/packages/backend/src/queue/index.ts @@ -1,23 +1,31 @@ -import httpSignature from '@peertube/http-signature'; -import { v4 as uuid } from 'uuid'; +import type httpSignature from "@peertube/http-signature"; +import { v4 as uuid } from "uuid"; -import config from '@/config/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { IActivity } from '@/remote/activitypub/type.js'; -import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js'; -import { envOption } from '../env.js'; +import config from "@/config/index.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { IActivity } from "@/remote/activitypub/type.js"; +import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js"; +import { envOption } from "../env.js"; -import processDeliver from './processors/deliver.js'; -import processInbox from './processors/inbox.js'; -import processDb from './processors/db/index.js'; -import processObjectStorage from './processors/object-storage/index.js'; -import processSystemQueue from './processors/system/index.js'; -import processWebhookDeliver from './processors/webhook-deliver.js'; -import { endedPollNotification } from './processors/ended-poll-notification.js'; -import { queueLogger } from './logger.js'; -import { getJobInfo } from './get-job-info.js'; -import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue, endedPollNotificationQueue, webhookDeliverQueue } from './queues.js'; -import { ThinUser } from './types.js'; +import processDeliver from "./processors/deliver.js"; +import processInbox from "./processors/inbox.js"; +import processDb from "./processors/db/index.js"; +import processObjectStorage from "./processors/object-storage/index.js"; +import processSystemQueue from "./processors/system/index.js"; +import processWebhookDeliver from "./processors/webhook-deliver.js"; +import { endedPollNotification } from "./processors/ended-poll-notification.js"; +import { queueLogger } from "./logger.js"; +import { getJobInfo } from "./get-job-info.js"; +import { + systemQueue, + dbQueue, + deliverQueue, + inboxQueue, + objectStorageQueue, + endedPollNotificationQueue, + webhookDeliverQueue, +} from "./queues.js"; +import type { ThinUser } from "./types.js"; function renderError(e: Error): any { return { @@ -27,60 +35,125 @@ function renderError(e: Error): any { }; } -const systemLogger = queueLogger.createSubLogger('system'); -const deliverLogger = queueLogger.createSubLogger('deliver'); -const webhookLogger = queueLogger.createSubLogger('webhook'); -const inboxLogger = queueLogger.createSubLogger('inbox'); -const dbLogger = queueLogger.createSubLogger('db'); -const objectStorageLogger = queueLogger.createSubLogger('objectStorage'); +const systemLogger = queueLogger.createSubLogger("system"); +const deliverLogger = queueLogger.createSubLogger("deliver"); +const webhookLogger = queueLogger.createSubLogger("webhook"); +const inboxLogger = queueLogger.createSubLogger("inbox"); +const dbLogger = queueLogger.createSubLogger("db"); +const objectStorageLogger = queueLogger.createSubLogger("objectStorage"); systemQueue - .on('waiting', (jobId) => systemLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => systemLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => systemLogger.warn(`stalled id=${job.id}`)); + .on("waiting", (jobId) => systemLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => systemLogger.debug(`active id=${job.id}`)) + .on("completed", (job, result) => + systemLogger.debug(`completed(${result}) id=${job.id}`), + ) + .on("failed", (job, err) => + systemLogger.warn(`failed(${err}) id=${job.id}`, { + job, + e: renderError(err), + }), + ) + .on("error", (job: any, err: Error) => + systemLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => systemLogger.warn(`stalled id=${job.id}`)); deliverQueue - .on('waiting', (jobId) => deliverLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`)) - .on('error', (job: any, err: Error) => deliverLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => deliverLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`)); + .on("waiting", (jobId) => deliverLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => + deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`), + ) + .on("completed", (job, result) => + deliverLogger.debug( + `completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`, + ), + ) + .on("failed", (job, err) => + deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`), + ) + .on("error", (job: any, err: Error) => + deliverLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => + deliverLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`), + ); inboxQueue - .on('waiting', (jobId) => inboxLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) - .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) - .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job.data.activity ? job.data.activity.id : 'none'}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => inboxLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => inboxLogger.warn(`stalled ${getJobInfo(job)} activity=${job.data.activity ? job.data.activity.id : 'none'}`)); + .on("waiting", (jobId) => inboxLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) + .on("completed", (job, result) => + inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`), + ) + .on("failed", (job, err) => + inboxLogger.warn( + `failed(${err}) ${getJobInfo(job)} activity=${ + job.data.activity ? job.data.activity.id : "none" + }`, + { job, e: renderError(err) }, + ), + ) + .on("error", (job: any, err: Error) => + inboxLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => + inboxLogger.warn( + `stalled ${getJobInfo(job)} activity=${ + job.data.activity ? job.data.activity.id : "none" + }`, + ), + ); dbQueue - .on('waiting', (jobId) => dbLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => dbLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => dbLogger.warn(`stalled id=${job.id}`)); + .on("waiting", (jobId) => dbLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => dbLogger.debug(`active id=${job.id}`)) + .on("completed", (job, result) => + dbLogger.debug(`completed(${result}) id=${job.id}`), + ) + .on("failed", (job, err) => + dbLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) }), + ) + .on("error", (job: any, err: Error) => + dbLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => dbLogger.warn(`stalled id=${job.id}`)); objectStorageQueue - .on('waiting', (jobId) => objectStorageLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => objectStorageLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => objectStorageLogger.warn(`stalled id=${job.id}`)); + .on("waiting", (jobId) => objectStorageLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => objectStorageLogger.debug(`active id=${job.id}`)) + .on("completed", (job, result) => + objectStorageLogger.debug(`completed(${result}) id=${job.id}`), + ) + .on("failed", (job, err) => + objectStorageLogger.warn(`failed(${err}) id=${job.id}`, { + job, + e: renderError(err), + }), + ) + .on("error", (job: any, err: Error) => + objectStorageLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => objectStorageLogger.warn(`stalled id=${job.id}`)); webhookDeliverQueue - .on('waiting', (jobId) => webhookLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`)) - .on('error', (job: any, err: Error) => webhookLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => webhookLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`)); + .on("waiting", (jobId) => webhookLogger.debug(`waiting id=${jobId}`)) + .on("active", (job) => + webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`), + ) + .on("completed", (job, result) => + webhookLogger.debug( + `completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`, + ), + ) + .on("failed", (job, err) => + webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`), + ) + .on("error", (job: any, err: Error) => + webhookLogger.error(`error ${err}`, { job, e: renderError(err) }), + ) + .on("stalled", (job) => + webhookLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`), + ); export function deliver(user: ThinUser, content: unknown, to: string | null) { if (content == null) return null; @@ -96,16 +169,19 @@ export function deliver(user: ThinUser, content: unknown, to: string | null) { return deliverQueue.add(data, { attempts: config.deliverJobMaxAttempts || 12, - timeout: 1 * 60 * 1000, // 1min + timeout: 1 * 60 * 1000, // 1min backoff: { - type: 'apBackoff', + type: "apBackoff", }, removeOnComplete: true, removeOnFail: true, }); } -export function inbox(activity: IActivity, signature: httpSignature.IParsedSignature) { +export function inbox( + activity: IActivity, + signature: httpSignature.IParsedSignature, +) { const data = { activity: activity, signature, @@ -113,9 +189,9 @@ export function inbox(activity: IActivity, signature: httpSignature.IParsedSigna return inboxQueue.add(data, { attempts: config.inboxJobMaxAttempts || 8, - timeout: 5 * 60 * 1000, // 5min + timeout: 5 * 60 * 1000, // 5min backoff: { - type: 'apBackoff', + type: "apBackoff", }, removeOnComplete: true, removeOnFail: true, @@ -123,147 +199,230 @@ export function inbox(activity: IActivity, signature: httpSignature.IParsedSigna } export function createDeleteDriveFilesJob(user: ThinUser) { - return dbQueue.add('deleteDriveFiles', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "deleteDriveFiles", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createExportCustomEmojisJob(user: ThinUser) { - return dbQueue.add('exportCustomEmojis', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "exportCustomEmojis", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createExportNotesJob(user: ThinUser) { - return dbQueue.add('exportNotes', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "exportNotes", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createExportFollowingJob(user: ThinUser, excludeMuting = false, excludeInactive = false) { - return dbQueue.add('exportFollowing', { - user: user, - excludeMuting, - excludeInactive, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createExportFollowingJob( + user: ThinUser, + excludeMuting = false, + excludeInactive = false, +) { + return dbQueue.add( + "exportFollowing", + { + user: user, + excludeMuting, + excludeInactive, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createExportMuteJob(user: ThinUser) { - return dbQueue.add('exportMute', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "exportMute", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createExportBlockingJob(user: ThinUser) { - return dbQueue.add('exportBlocking', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "exportBlocking", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createExportUserListsJob(user: ThinUser) { - return dbQueue.add('exportUserLists', { - user: user, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return dbQueue.add( + "exportUserLists", + { + user: user, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createImportFollowingJob(user: ThinUser, fileId: DriveFile['id']) { - return dbQueue.add('importFollowing', { - user: user, - fileId: fileId, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createImportFollowingJob( + user: ThinUser, + fileId: DriveFile["id"], +) { + return dbQueue.add( + "importFollowing", + { + user: user, + fileId: fileId, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createImportMutingJob(user: ThinUser, fileId: DriveFile['id']) { - return dbQueue.add('importMuting', { - user: user, - fileId: fileId, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createImportMutingJob(user: ThinUser, fileId: DriveFile["id"]) { + return dbQueue.add( + "importMuting", + { + user: user, + fileId: fileId, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createImportBlockingJob(user: ThinUser, fileId: DriveFile['id']) { - return dbQueue.add('importBlocking', { - user: user, - fileId: fileId, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createImportBlockingJob( + user: ThinUser, + fileId: DriveFile["id"], +) { + return dbQueue.add( + "importBlocking", + { + user: user, + fileId: fileId, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']) { - return dbQueue.add('importUserLists', { - user: user, - fileId: fileId, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createImportUserListsJob( + user: ThinUser, + fileId: DriveFile["id"], +) { + return dbQueue.add( + "importUserLists", + { + user: user, + fileId: fileId, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createImportCustomEmojisJob(user: ThinUser, fileId: DriveFile['id']) { - return dbQueue.add('importCustomEmojis', { - user: user, - fileId: fileId, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createImportCustomEmojisJob( + user: ThinUser, + fileId: DriveFile["id"], +) { + return dbQueue.add( + "importCustomEmojis", + { + user: user, + fileId: fileId, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; } = {}) { - return dbQueue.add('deleteAccount', { - user: user, - soft: opts.soft, - }, { - removeOnComplete: true, - removeOnFail: true, - }); +export function createDeleteAccountJob( + user: ThinUser, + opts: { soft?: boolean } = {}, +) { + return dbQueue.add( + "deleteAccount", + { + user: user, + soft: opts.soft, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createDeleteObjectStorageFileJob(key: string) { - return objectStorageQueue.add('deleteFile', { - key: key, - }, { - removeOnComplete: true, - removeOnFail: true, - }); + return objectStorageQueue.add( + "deleteFile", + { + key: key, + }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } export function createCleanRemoteFilesJob() { - return objectStorageQueue.add('cleanRemoteFiles', {}, { - removeOnComplete: true, - removeOnFail: true, - }); + return objectStorageQueue.add( + "cleanRemoteFiles", + {}, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); } -export function webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[number], content: unknown) { +export function webhookDeliver( + webhook: Webhook, + type: typeof webhookEventTypes[number], + content: unknown, +) { const data = { type, content, @@ -277,16 +436,16 @@ export function webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[ return webhookDeliverQueue.add(data, { attempts: 4, - timeout: 1 * 60 * 1000, // 1min + timeout: 1 * 60 * 1000, // 1min backoff: { - type: 'apBackoff', + type: "apBackoff", }, removeOnComplete: true, removeOnFail: true, }); } -export default function() { +export default function () { if (envOption.onlyServer) return; deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver); @@ -296,47 +455,62 @@ export default function() { processDb(dbQueue); processObjectStorage(objectStorageQueue); - systemQueue.add('tickCharts', { - }, { - repeat: { cron: '55 * * * *' }, - removeOnComplete: true, - }); + systemQueue.add( + "tickCharts", + {}, + { + repeat: { cron: "55 * * * *" }, + removeOnComplete: true, + }, + ); - systemQueue.add('resyncCharts', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); + systemQueue.add( + "resyncCharts", + {}, + { + repeat: { cron: "0 0 * * *" }, + removeOnComplete: true, + }, + ); - systemQueue.add('cleanCharts', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); + systemQueue.add( + "cleanCharts", + {}, + { + repeat: { cron: "0 0 * * *" }, + removeOnComplete: true, + }, + ); - systemQueue.add('clean', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); + systemQueue.add( + "clean", + {}, + { + repeat: { cron: "0 0 * * *" }, + removeOnComplete: true, + }, + ); - systemQueue.add('checkExpiredMutings', { - }, { - repeat: { cron: '*/5 * * * *' }, - removeOnComplete: true, - }); + systemQueue.add( + "checkExpiredMutings", + {}, + { + repeat: { cron: "*/5 * * * *" }, + removeOnComplete: true, + }, + ); processSystemQueue(systemQueue); } export function destroy() { - deliverQueue.once('cleaned', (jobs, status) => { + deliverQueue.once("cleaned", (jobs, status) => { deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`); }); - deliverQueue.clean(0, 'delayed'); + deliverQueue.clean(0, "delayed"); - inboxQueue.once('cleaned', (jobs, status) => { + inboxQueue.once("cleaned", (jobs, status) => { inboxLogger.succ(`Cleaned ${jobs.length} ${status} jobs`); }); - inboxQueue.clean(0, 'delayed'); + inboxQueue.clean(0, "delayed"); } diff --git a/packages/backend/src/queue/initialize.ts b/packages/backend/src/queue/initialize.ts index eef4080af..d7945d5da 100644 --- a/packages/backend/src/queue/initialize.ts +++ b/packages/backend/src/queue/initialize.ts @@ -1,5 +1,5 @@ -import Bull from 'bull'; -import config from '@/config/index.js'; +import Bull from "bull"; +import config from "@/config/index.js"; export function initialize(name: string, limitPerSec = -1) { return new Bull(name, { @@ -10,11 +10,14 @@ export function initialize(name: string, limitPerSec = -1) { password: config.redis.pass, db: config.redis.db || 0, }, - prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue', - limiter: limitPerSec > 0 ? { - max: limitPerSec, - duration: 1000, - } : undefined, + prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : "queue", + limiter: + limitPerSec > 0 + ? { + max: limitPerSec, + duration: 1000, + } + : undefined, settings: { backoffStrategies: { apBackoff, @@ -25,8 +28,8 @@ export function initialize(name: string, limitPerSec = -1) { // ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019 function apBackoff(attemptsMade: number, err: Error) { - const baseDelay = 60 * 1000; // 1min - const maxBackoff = 8 * 60 * 60 * 1000; // 8hours + const baseDelay = 60 * 1000; // 1min + const maxBackoff = 8 * 60 * 60 * 1000; // 8hours let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay; backoff = Math.min(backoff, maxBackoff); backoff += Math.round(backoff * Math.random() * 0.2); diff --git a/packages/backend/src/queue/logger.ts b/packages/backend/src/queue/logger.ts index 2843a3c26..929c207e3 100644 --- a/packages/backend/src/queue/logger.ts +++ b/packages/backend/src/queue/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger.js'; +import Logger from "@/services/logger.js"; -export const queueLogger = new Logger('queue', 'orange'); +export const queueLogger = new Logger("queue", "orange"); diff --git a/packages/backend/src/queue/processors/db/delete-account.ts b/packages/backend/src/queue/processors/db/delete-account.ts index c1657b4be..764b83db2 100644 --- a/packages/backend/src/queue/processors/db/delete-account.ts +++ b/packages/backend/src/queue/processors/db/delete-account.ts @@ -1,16 +1,18 @@ -import Bull from 'bull'; -import { queueLogger } from '../../logger.js'; -import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index.js'; -import { DbUserDeleteJobData } from '@/queue/types.js'; -import { Note } from '@/models/entities/note.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { MoreThan } from 'typeorm'; -import { deleteFileSync } from '@/services/drive/delete-file.js'; -import { sendEmail } from '@/services/send-email.js'; +import type Bull from "bull"; +import { queueLogger } from "../../logger.js"; +import { DriveFiles, Notes, UserProfiles, Users } from "@/models/index.js"; +import type { DbUserDeleteJobData } from "@/queue/types.js"; +import type { Note } from "@/models/entities/note.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { MoreThan } from "typeorm"; +import { deleteFileSync } from "@/services/drive/delete-file.js"; +import { sendEmail } from "@/services/send-email.js"; -const logger = queueLogger.createSubLogger('delete-account'); +const logger = queueLogger.createSubLogger("delete-account"); -export async function deleteAccount(job: Bull.Job): Promise { +export async function deleteAccount( + job: Bull.Job, +): Promise { logger.info(`Deleting account of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -18,11 +20,12 @@ export async function deleteAccount(job: Bull.Job): Promise return; } - { // Delete notes - let cursor: Note['id'] | null = null; + { + // Delete notes + let cursor: Note["id"] | null = null; while (true) { - const notes = await Notes.find({ + const notes = (await Notes.find({ where: { userId: user.id, ...(cursor ? { id: MoreThan(cursor) } : {}), @@ -31,7 +34,7 @@ export async function deleteAccount(job: Bull.Job): Promise order: { id: 1, }, - }) as Note[]; + })) as Note[]; if (notes.length === 0) { break; @@ -39,17 +42,18 @@ export async function deleteAccount(job: Bull.Job): Promise cursor = notes[notes.length - 1].id; - await Notes.delete(notes.map(note => note.id)); + await Notes.delete(notes.map((note) => note.id)); } - logger.succ(`All of notes deleted`); + logger.succ("All of notes deleted"); } - { // Delete files - let cursor: DriveFile['id'] | null = null; + { + // Delete files + let cursor: DriveFile["id"] | null = null; while (true) { - const files = await DriveFiles.find({ + const files = (await DriveFiles.find({ where: { userId: user.id, ...(cursor ? { id: MoreThan(cursor) } : {}), @@ -58,7 +62,7 @@ export async function deleteAccount(job: Bull.Job): Promise order: { id: 1, }, - }) as DriveFile[]; + })) as DriveFile[]; if (files.length === 0) { break; @@ -71,15 +75,19 @@ export async function deleteAccount(job: Bull.Job): Promise } } - logger.succ(`All of files deleted`); + logger.succ("All of files deleted"); } - { // Send email notification + { + // Send email notification const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.email && profile.emailVerified) { - sendEmail(profile.email, 'Account deleted', - `Your account has been deleted.`, - `Your account has been deleted.`); + sendEmail( + profile.email, + "Account deleted", + "Your account has been deleted.", + "Your account has been deleted.", + ); } } @@ -90,5 +98,5 @@ export async function deleteAccount(job: Bull.Job): Promise await Users.delete(job.data.user.id); } - return 'Account deleted'; + return "Account deleted"; } diff --git a/packages/backend/src/queue/processors/db/delete-drive-files.ts b/packages/backend/src/queue/processors/db/delete-drive-files.ts index b3832d9f0..28e477132 100644 --- a/packages/backend/src/queue/processors/db/delete-drive-files.ts +++ b/packages/backend/src/queue/processors/db/delete-drive-files.ts @@ -1,14 +1,17 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import { deleteFileSync } from '@/services/drive/delete-file.js'; -import { Users, DriveFiles } from '@/models/index.js'; -import { MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types.js'; +import { queueLogger } from "../../logger.js"; +import { deleteFileSync } from "@/services/drive/delete-file.js"; +import { Users, DriveFiles } from "@/models/index.js"; +import { MoreThan } from "typeorm"; +import type { DbUserJobData } from "@/queue/types.js"; -const logger = queueLogger.createSubLogger('delete-drive-files'); +const logger = queueLogger.createSubLogger("delete-drive-files"); -export async function deleteDriveFiles(job: Bull.Job, done: any): Promise { +export async function deleteDriveFiles( + job: Bull.Job, + done: any, +): Promise { logger.info(`Deleting drive files of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -51,6 +54,8 @@ export async function deleteDriveFiles(job: Bull.Job, done: any): job.progress(deletedCount / total); } - logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`); + logger.succ( + `All drive files (${deletedCount}) of ${user.id} has been deleted.`, + ); done(); } diff --git a/packages/backend/src/queue/processors/db/export-blocking.ts b/packages/backend/src/queue/processors/db/export-blocking.ts index f5e0424a7..90da76b87 100644 --- a/packages/backend/src/queue/processors/db/export-blocking.ts +++ b/packages/backend/src/queue/processors/db/export-blocking.ts @@ -1,18 +1,21 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { getFullApAccount } from '@/misc/convert-host.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { Users, Blockings } from '@/models/index.js'; -import { MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types.js'; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { getFullApAccount } from "@/misc/convert-host.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { Users, Blockings } from "@/models/index.js"; +import { MoreThan } from "typeorm"; +import type { DbUserJobData } from "@/queue/types.js"; -const logger = queueLogger.createSubLogger('export-blocking'); +const logger = queueLogger.createSubLogger("export-blocking"); -export async function exportBlocking(job: Bull.Job, done: any): Promise { +export async function exportBlocking( + job: Bull.Job, + done: any, +): Promise { logger.info(`Exporting blocking of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -27,7 +30,7 @@ export async function exportBlocking(job: Bull.Job, done: any): P logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + const stream = fs.createWriteStream(path, { flags: "a" }); let exportedCount = 0; let cursor: any = null; @@ -54,12 +57,13 @@ export async function exportBlocking(job: Bull.Job, done: any): P for (const block of blockings) { const u = await Users.findOneBy({ id: block.blockeeId }); if (u == null) { - exportedCount++; continue; + exportedCount++; + continue; } const content = getFullApAccount(u.username, u.host); await new Promise((res, rej) => { - stream.write(content + '\n', err => { + stream.write(content + "\n", (err) => { if (err) { logger.error(err); rej(err); @@ -81,8 +85,16 @@ export async function exportBlocking(job: Bull.Job, done: any): P stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'blocking-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; - const driveFile = await addFile({ user, path, name: fileName, force: true }); + const fileName = `blocking-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.csv`; + const driveFile = await addFile({ + user, + path, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); } finally { diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts index 3da887cda..7a19d0b60 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -1,23 +1,26 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { ulid } from 'ulid'; -import mime from 'mime-types'; -import archiver from 'archiver'; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { Users, Emojis } from '@/models/index.js'; -import { } from '@/queue/types.js'; -import { createTemp, createTempDir } from '@/misc/create-temp.js'; -import { downloadUrl } from '@/misc/download-url.js'; -import config from '@/config/index.js'; -import { IsNull } from 'typeorm'; +import { ulid } from "ulid"; +import mime from "mime-types"; +import archiver from "archiver"; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { Users, Emojis } from "@/models/index.js"; +import {} from "@/queue/types.js"; +import { createTemp, createTempDir } from "@/misc/create-temp.js"; +import { downloadUrl } from "@/misc/download-url.js"; +import config from "@/config/index.js"; +import { IsNull } from "typeorm"; -const logger = queueLogger.createSubLogger('export-custom-emojis'); +const logger = queueLogger.createSubLogger("export-custom-emojis"); -export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promise { - logger.info(`Exporting custom emojis ...`); +export async function exportCustomEmojis( + job: Bull.Job, + done: () => void, +): Promise { + logger.info("Exporting custom emojis ..."); const user = await Users.findOneBy({ id: job.data.user.id }); if (user == null) { @@ -29,15 +32,15 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi logger.info(`Temp dir is ${path}`); - const metaPath = path + '/meta.json'; + const metaPath = `${path}/meta.json`; - fs.writeFileSync(metaPath, '', 'utf-8'); + fs.writeFileSync(metaPath, "", "utf-8"); - const metaStream = fs.createWriteStream(metaPath, { flags: 'a' }); + const metaStream = fs.createWriteStream(metaPath, { flags: "a" }); const writeMeta = (text: string): Promise => { return new Promise((res, rej) => { - metaStream.write(text, err => { + metaStream.write(text, (err) => { if (err) { logger.error(err); rej(err); @@ -48,28 +51,33 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi }); }; - await writeMeta(`{"metaVersion":2,"host":"${config.host}","exportedAt":"${new Date().toString()}","emojis":[`); + await writeMeta( + `{"metaVersion":2,"host":"${ + config.host + }","exportedAt":"${new Date().toString()}","emojis":[`, + ); const customEmojis = await Emojis.find({ where: { host: IsNull(), }, order: { - id: 'ASC', + id: "ASC", }, }); for (const emoji of customEmojis) { const ext = mime.extension(emoji.type); - const fileName = emoji.name + (ext ? '.' + ext : ''); - const emojiPath = path + '/' + fileName; - fs.writeFileSync(emojiPath, '', 'binary'); + const fileName = emoji.name + (ext ? `.${ext}` : ""); + const emojiPath = `${path}/${fileName}`; + fs.writeFileSync(emojiPath, "", "binary"); let downloaded = false; try { await downloadUrl(emoji.originalUrl, emojiPath); downloaded = true; - } catch (e) { // TODO: 何度か再試行 + } catch (e) { + // TODO: 何度か再試行 logger.error(e instanceof Error ? e : new Error(e as string)); } @@ -84,24 +92,32 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi }); const isFirst = customEmojis.indexOf(emoji) === 0; - await writeMeta(isFirst ? content : ',\n' + content); + await writeMeta(isFirst ? content : ",\n" + content); } - await writeMeta(']}'); + await writeMeta("]}"); metaStream.end(); // Create archive const [archivePath, archiveCleanup] = await createTemp(); const archiveStream = fs.createWriteStream(archivePath); - const archive = archiver('zip', { + const archive = archiver("zip", { zlib: { level: 0 }, }); - archiveStream.on('close', async () => { + archiveStream.on("close", async () => { logger.succ(`Exported to: ${archivePath}`); - const fileName = 'custom-emojis-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.zip'; - const driveFile = await addFile({ user, path: archivePath, name: fileName, force: true }); + const fileName = `custom-emojis-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.zip`; + const driveFile = await addFile({ + user, + path: archivePath, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); cleanup(); diff --git a/packages/backend/src/queue/processors/db/export-following.ts b/packages/backend/src/queue/processors/db/export-following.ts index 4ac165567..80e8e6b92 100644 --- a/packages/backend/src/queue/processors/db/export-following.ts +++ b/packages/backend/src/queue/processors/db/export-following.ts @@ -1,19 +1,22 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { getFullApAccount } from '@/misc/convert-host.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { Users, Followings, Mutings } from '@/models/index.js'; -import { In, MoreThan, Not } from 'typeorm'; -import { DbUserJobData } from '@/queue/types.js'; -import { Following } from '@/models/entities/following.js'; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { getFullApAccount } from "@/misc/convert-host.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { Users, Followings, Mutings } from "@/models/index.js"; +import { In, MoreThan, Not } from "typeorm"; +import type { DbUserJobData } from "@/queue/types.js"; +import type { Following } from "@/models/entities/following.js"; -const logger = queueLogger.createSubLogger('export-following'); +const logger = queueLogger.createSubLogger("export-following"); -export async function exportFollowing(job: Bull.Job, done: () => void): Promise { +export async function exportFollowing( + job: Bull.Job, + done: () => void, +): Promise { logger.info(`Exporting following of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -28,26 +31,30 @@ export async function exportFollowing(job: Bull.Job, done: () => logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + const stream = fs.createWriteStream(path, { flags: "a" }); - let cursor: Following['id'] | null = null; + let cursor: Following["id"] | null = null; - const mutings = job.data.excludeMuting ? await Mutings.findBy({ - muterId: user.id, - }) : []; + const mutings = job.data.excludeMuting + ? await Mutings.findBy({ + muterId: user.id, + }) + : []; while (true) { - const followings = await Followings.find({ + const followings = (await Followings.find({ where: { followerId: user.id, - ...(mutings.length > 0 ? { followeeId: Not(In(mutings.map(x => x.muteeId))) } : {}), + ...(mutings.length > 0 + ? { followeeId: Not(In(mutings.map((x) => x.muteeId))) } + : {}), ...(cursor ? { id: MoreThan(cursor) } : {}), }, take: 100, order: { id: 1, }, - }) as Following[]; + })) as Following[]; if (followings.length === 0) { break; @@ -61,13 +68,17 @@ export async function exportFollowing(job: Bull.Job, done: () => continue; } - if (job.data.excludeInactive && u.updatedAt && (Date.now() - u.updatedAt.getTime() > 1000 * 60 * 60 * 24 * 90)) { + if ( + job.data.excludeInactive && + u.updatedAt && + Date.now() - u.updatedAt.getTime() > 1000 * 60 * 60 * 24 * 90 + ) { continue; } const content = getFullApAccount(u.username, u.host); await new Promise((res, rej) => { - stream.write(content + '\n', err => { + stream.write(content + "\n", (err) => { if (err) { logger.error(err); rej(err); @@ -82,8 +93,16 @@ export async function exportFollowing(job: Bull.Job, done: () => stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'following-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; - const driveFile = await addFile({ user, path, name: fileName, force: true }); + const fileName = `following-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.csv`; + const driveFile = await addFile({ + user, + path, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); } finally { diff --git a/packages/backend/src/queue/processors/db/export-mute.ts b/packages/backend/src/queue/processors/db/export-mute.ts index 6a36cfa07..87b140b76 100644 --- a/packages/backend/src/queue/processors/db/export-mute.ts +++ b/packages/backend/src/queue/processors/db/export-mute.ts @@ -1,18 +1,21 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { getFullApAccount } from '@/misc/convert-host.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { Users, Mutings } from '@/models/index.js'; -import { IsNull, MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types.js'; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { getFullApAccount } from "@/misc/convert-host.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { Users, Mutings } from "@/models/index.js"; +import { IsNull, MoreThan } from "typeorm"; +import type { DbUserJobData } from "@/queue/types.js"; -const logger = queueLogger.createSubLogger('export-mute'); +const logger = queueLogger.createSubLogger("export-mute"); -export async function exportMute(job: Bull.Job, done: any): Promise { +export async function exportMute( + job: Bull.Job, + done: any, +): Promise { logger.info(`Exporting mute of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -27,7 +30,7 @@ export async function exportMute(job: Bull.Job, done: any): Promi logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + const stream = fs.createWriteStream(path, { flags: "a" }); let exportedCount = 0; let cursor: any = null; @@ -55,12 +58,13 @@ export async function exportMute(job: Bull.Job, done: any): Promi for (const mute of mutes) { const u = await Users.findOneBy({ id: mute.muteeId }); if (u == null) { - exportedCount++; continue; + exportedCount++; + continue; } const content = getFullApAccount(u.username, u.host); await new Promise((res, rej) => { - stream.write(content + '\n', err => { + stream.write(content + "\n", (err) => { if (err) { logger.error(err); rej(err); @@ -82,8 +86,16 @@ export async function exportMute(job: Bull.Job, done: any): Promi stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'mute-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; - const driveFile = await addFile({ user, path, name: fileName, force: true }); + const fileName = `mute-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.csv`; + const driveFile = await addFile({ + user, + path, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); } finally { diff --git a/packages/backend/src/queue/processors/db/export-notes.ts b/packages/backend/src/queue/processors/db/export-notes.ts index 051fcdf38..de8fac05b 100644 --- a/packages/backend/src/queue/processors/db/export-notes.ts +++ b/packages/backend/src/queue/processors/db/export-notes.ts @@ -1,19 +1,22 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { Users, Notes, Polls } from '@/models/index.js'; -import { MoreThan } from 'typeorm'; -import { Note } from '@/models/entities/note.js'; -import { Poll } from '@/models/entities/poll.js'; -import { DbUserJobData } from '@/queue/types.js'; -import { createTemp } from '@/misc/create-temp.js'; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { Users, Notes, Polls } from "@/models/index.js"; +import { MoreThan } from "typeorm"; +import type { Note } from "@/models/entities/note.js"; +import type { Poll } from "@/models/entities/poll.js"; +import type { DbUserJobData } from "@/queue/types.js"; +import { createTemp } from "@/misc/create-temp.js"; -const logger = queueLogger.createSubLogger('export-notes'); +const logger = queueLogger.createSubLogger("export-notes"); -export async function exportNotes(job: Bull.Job, done: any): Promise { +export async function exportNotes( + job: Bull.Job, + done: any, +): Promise { logger.info(`Exporting notes of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -28,11 +31,11 @@ export async function exportNotes(job: Bull.Job, done: any): Prom logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + const stream = fs.createWriteStream(path, { flags: "a" }); const write = (text: string): Promise => { return new Promise((res, rej) => { - stream.write(text, err => { + stream.write(text, (err) => { if (err) { logger.error(err); rej(err); @@ -43,13 +46,13 @@ export async function exportNotes(job: Bull.Job, done: any): Prom }); }; - await write('['); + await write("["); let exportedNotesCount = 0; - let cursor: Note['id'] | null = null; + let cursor: Note["id"] | null = null; while (true) { - const notes = await Notes.find({ + const notes = (await Notes.find({ where: { userId: user.id, ...(cursor ? { id: MoreThan(cursor) } : {}), @@ -58,7 +61,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom order: { id: 1, }, - }) as Note[]; + })) as Note[]; if (notes.length === 0) { job.progress(100); @@ -74,7 +77,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom } const content = JSON.stringify(serialize(note, poll)); const isFirst = exportedNotesCount === 0; - await write(isFirst ? content : ',\n' + content); + await write(isFirst ? content : ",\n" + content); exportedNotesCount++; } @@ -85,13 +88,21 @@ export async function exportNotes(job: Bull.Job, done: any): Prom job.progress(exportedNotesCount / total); } - await write(']'); + await write("]"); stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'notes-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.json'; - const driveFile = await addFile({ user, path, name: fileName, force: true }); + const fileName = `notes-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.json`; + const driveFile = await addFile({ + user, + path, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); } finally { @@ -101,7 +112,10 @@ export async function exportNotes(job: Bull.Job, done: any): Prom done(); } -function serialize(note: Note, poll: Poll | null = null): Record { +function serialize( + note: Note, + poll: Poll | null = null, +): Record { return { id: note.id, text: note.text, diff --git a/packages/backend/src/queue/processors/db/export-user-lists.ts b/packages/backend/src/queue/processors/db/export-user-lists.ts index 71dd72df2..e0c9cd8f3 100644 --- a/packages/backend/src/queue/processors/db/export-user-lists.ts +++ b/packages/backend/src/queue/processors/db/export-user-lists.ts @@ -1,18 +1,21 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; +import type Bull from "bull"; +import * as fs from "node:fs"; -import { queueLogger } from '../../logger.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { format as dateFormat } from 'date-fns'; -import { getFullApAccount } from '@/misc/convert-host.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { Users, UserLists, UserListJoinings } from '@/models/index.js'; -import { In } from 'typeorm'; -import { DbUserJobData } from '@/queue/types.js'; +import { queueLogger } from "../../logger.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { format as dateFormat } from "date-fns"; +import { getFullApAccount } from "@/misc/convert-host.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { Users, UserLists, UserListJoinings } from "@/models/index.js"; +import { In } from "typeorm"; +import type { DbUserJobData } from "@/queue/types.js"; -const logger = queueLogger.createSubLogger('export-user-lists'); +const logger = queueLogger.createSubLogger("export-user-lists"); -export async function exportUserLists(job: Bull.Job, done: any): Promise { +export async function exportUserLists( + job: Bull.Job, + done: any, +): Promise { logger.info(`Exporting user lists of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -31,19 +34,19 @@ export async function exportUserLists(job: Bull.Job, done: any): logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + const stream = fs.createWriteStream(path, { flags: "a" }); for (const list of lists) { const joinings = await UserListJoinings.findBy({ userListId: list.id }); const users = await Users.findBy({ - id: In(joinings.map(j => j.userId)), + id: In(joinings.map((j) => j.userId)), }); for (const u of users) { const acct = getFullApAccount(u.username, u.host); const content = `${list.name},${acct}`; await new Promise((res, rej) => { - stream.write(content + '\n', err => { + stream.write(content + "\n", (err) => { if (err) { logger.error(err); rej(err); @@ -58,8 +61,16 @@ export async function exportUserLists(job: Bull.Job, done: any): stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'user-lists-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; - const driveFile = await addFile({ user, path, name: fileName, force: true }); + const fileName = `user-lists-${dateFormat( + new Date(), + "yyyy-MM-dd-HH-mm-ss", + )}.csv`; + const driveFile = await addFile({ + user, + path, + name: fileName, + force: true, + }); logger.succ(`Exported to: ${driveFile.id}`); } finally { diff --git a/packages/backend/src/queue/processors/db/import-blocking.ts b/packages/backend/src/queue/processors/db/import-blocking.ts index 42a14fb3e..2fdf80a6e 100644 --- a/packages/backend/src/queue/processors/db/import-blocking.ts +++ b/packages/backend/src/queue/processors/db/import-blocking.ts @@ -1,18 +1,21 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import * as Acct from '@/misc/acct.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { downloadTextFile } from '@/misc/download-text-file.js'; -import { isSelfHost, toPuny } from '@/misc/convert-host.js'; -import { Users, DriveFiles, Blockings } from '@/models/index.js'; -import { DbUserImportJobData } from '@/queue/types.js'; -import block from '@/services/blocking/create.js'; -import { IsNull } from 'typeorm'; +import { queueLogger } from "../../logger.js"; +import * as Acct from "@/misc/acct.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { downloadTextFile } from "@/misc/download-text-file.js"; +import { isSelfHost, toPuny } from "@/misc/convert-host.js"; +import { Users, DriveFiles, Blockings } from "@/models/index.js"; +import type { DbUserImportJobData } from "@/queue/types.js"; +import block from "@/services/blocking/create.js"; +import { IsNull } from "typeorm"; -const logger = queueLogger.createSubLogger('import-blocking'); +const logger = queueLogger.createSubLogger("import-blocking"); -export async function importBlocking(job: Bull.Job, done: any): Promise { +export async function importBlocking( + job: Bull.Job, + done: any, +): Promise { logger.info(`Importing blocking of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -33,20 +36,22 @@ export async function importBlocking(job: Bull.Job, done: a let linenum = 0; - for (const line of csv.trim().split('\n')) { + for (const line of csv.trim().split("\n")) { linenum++; try { - const acct = line.split(',')[0].trim(); + const acct = line.split(",")[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOneBy({ - host: IsNull(), - usernameLower: username.toLowerCase(), - }) : await Users.findOneBy({ - host: toPuny(host!), - usernameLower: username.toLowerCase(), - }); + let target = isSelfHost(host!) + ? await Users.findOneBy({ + host: IsNull(), + usernameLower: username.toLowerCase(), + }) + : await Users.findOneBy({ + host: toPuny(host!), + usernameLower: username.toLowerCase(), + }); if (host == null && target == null) continue; @@ -69,7 +74,6 @@ export async function importBlocking(job: Bull.Job, done: a } } - logger.succ('Imported'); + logger.succ("Imported"); done(); } - diff --git a/packages/backend/src/queue/processors/db/import-custom-emojis.ts b/packages/backend/src/queue/processors/db/import-custom-emojis.ts index 64dfe8537..45ab5ea9a 100644 --- a/packages/backend/src/queue/processors/db/import-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/import-custom-emojis.ts @@ -1,21 +1,24 @@ -import Bull from 'bull'; -import * as fs from 'node:fs'; -import unzipper from 'unzipper'; +import type Bull from "bull"; +import * as fs from "node:fs"; +import unzipper from "unzipper"; -import { queueLogger } from '../../logger.js'; -import { createTempDir } from '@/misc/create-temp.js'; -import { downloadUrl } from '@/misc/download-url.js'; -import { DriveFiles, Emojis } from '@/models/index.js'; -import { DbUserImportJobData } from '@/queue/types.js'; -import { addFile } from '@/services/drive/add-file.js'; -import { genId } from '@/misc/gen-id.js'; -import { db } from '@/db/postgre.js'; +import { queueLogger } from "../../logger.js"; +import { createTempDir } from "@/misc/create-temp.js"; +import { downloadUrl } from "@/misc/download-url.js"; +import { DriveFiles, Emojis } from "@/models/index.js"; +import type { DbUserImportJobData } from "@/queue/types.js"; +import { addFile } from "@/services/drive/add-file.js"; +import { genId } from "@/misc/gen-id.js"; +import { db } from "@/db/postgre.js"; -const logger = queueLogger.createSubLogger('import-custom-emojis'); +const logger = queueLogger.createSubLogger("import-custom-emojis"); // TODO: 名前衝突時の動作を選べるようにする -export async function importCustomEmojis(job: Bull.Job, done: any): Promise { - logger.info(`Importing custom emojis ...`); +export async function importCustomEmojis( + job: Bull.Job, + done: any, +): Promise { + logger.info("Importing custom emojis ..."); const file = await DriveFiles.findOneBy({ id: job.data.fileId, @@ -29,33 +32,39 @@ export async function importCustomEmojis(job: Bull.Job, don logger.info(`Temp dir is ${path}`); - const destPath = path + '/emojis.zip'; + const destPath = `${path}/emojis.zip`; try { - fs.writeFileSync(destPath, '', 'binary'); + fs.writeFileSync(destPath, "", "binary"); await downloadUrl(file.url, destPath); - } catch (e) { // TODO: 何度か再試行 - if (e instanceof Error || typeof e === 'string') { + } catch (e) { + // TODO: 何度か再試行 + if (e instanceof Error || typeof e === "string") { logger.error(e); } throw e; } - const outputPath = path + '/emojis'; + const outputPath = `${path}/emojis`; const unzipStream = fs.createReadStream(destPath); const extractor = unzipper.Extract({ path: outputPath }); - extractor.on('close', async () => { - const metaRaw = fs.readFileSync(outputPath + '/meta.json', 'utf-8'); + extractor.on("close", async () => { + const metaRaw = fs.readFileSync(`${outputPath}/meta.json`, "utf-8"); const meta = JSON.parse(metaRaw); for (const record of meta.emojis) { if (!record.downloaded) continue; const emojiInfo = record.emoji; - const emojiPath = outputPath + '/' + record.fileName; + const emojiPath = `${outputPath}/${record.fileName}`; await Emojis.delete({ name: emojiInfo.name, }); - const driveFile = await addFile({ user: null, path: emojiPath, name: record.fileName, force: true }); + const driveFile = await addFile({ + user: null, + path: emojiPath, + name: record.fileName, + force: true, + }); const emoji = await Emojis.insert({ id: genId(), updatedAt: new Date(), @@ -66,14 +75,14 @@ export async function importCustomEmojis(job: Bull.Job, don originalUrl: driveFile.url, publicUrl: driveFile.webpublicUrl ?? driveFile.url, type: driveFile.webpublicType ?? driveFile.type, - }).then(x => Emojis.findOneByOrFail(x.identifiers[0])); + }).then((x) => Emojis.findOneByOrFail(x.identifiers[0])); } - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); cleanup(); - - logger.succ('Imported'); + + logger.succ("Imported"); done(); }); unzipStream.pipe(extractor); diff --git a/packages/backend/src/queue/processors/db/import-following.ts b/packages/backend/src/queue/processors/db/import-following.ts index 6c40ebc1c..b1a7cd2c9 100644 --- a/packages/backend/src/queue/processors/db/import-following.ts +++ b/packages/backend/src/queue/processors/db/import-following.ts @@ -1,18 +1,21 @@ -import { IsNull } from 'typeorm'; -import follow from '@/services/following/create.js'; +import { IsNull } from "typeorm"; +import follow from "@/services/following/create.js"; -import * as Acct from '@/misc/acct.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { downloadTextFile } from '@/misc/download-text-file.js'; -import { isSelfHost, toPuny } from '@/misc/convert-host.js'; -import { Users, DriveFiles } from '@/models/index.js'; -import type { DbUserImportJobData } from '@/queue/types.js'; -import { queueLogger } from '../../logger.js'; -import type Bull from 'bull'; +import * as Acct from "@/misc/acct.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { downloadTextFile } from "@/misc/download-text-file.js"; +import { isSelfHost, toPuny } from "@/misc/convert-host.js"; +import { Users, DriveFiles } from "@/models/index.js"; +import type { DbUserImportJobData } from "@/queue/types.js"; +import { queueLogger } from "../../logger.js"; +import type Bull from "bull"; -const logger = queueLogger.createSubLogger('import-following'); +const logger = queueLogger.createSubLogger("import-following"); -export async function importFollowing(job: Bull.Job, done: any): Promise { +export async function importFollowing( + job: Bull.Job, + done: any, +): Promise { logger.info(`Importing following of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -33,18 +36,20 @@ export async function importFollowing(job: Bull.Job, done: let linenum = 0; - if (file.type.endsWith('json')) { + if (file.type.endsWith("json")) { for (const acct of JSON.parse(csv)) { try { const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOneBy({ - host: IsNull(), - usernameLower: username.toLowerCase(), - }) : await Users.findOneBy({ - host: toPuny(host!), - usernameLower: username.toLowerCase(), - }); + let target = isSelfHost(host!) + ? await Users.findOneBy({ + host: IsNull(), + usernameLower: username.toLowerCase(), + }) + : await Users.findOneBy({ + host: toPuny(host!), + usernameLower: username.toLowerCase(), + }); if (host == null && target == null) continue; @@ -66,22 +71,23 @@ export async function importFollowing(job: Bull.Job, done: logger.warn(`Error in line:${linenum} ${e}`); } } - } - else { - for (const line of csv.trim().split('\n')) { + } else { + for (const line of csv.trim().split("\n")) { linenum++; try { - const acct = line.split(',')[0].trim(); + const acct = line.split(",")[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOneBy({ - host: IsNull(), - usernameLower: username.toLowerCase(), - }) : await Users.findOneBy({ - host: toPuny(host!), - usernameLower: username.toLowerCase(), - }); + let target = isSelfHost(host!) + ? await Users.findOneBy({ + host: IsNull(), + usernameLower: username.toLowerCase(), + }) + : await Users.findOneBy({ + host: toPuny(host!), + usernameLower: username.toLowerCase(), + }); if (host == null && target == null) continue; @@ -105,6 +111,6 @@ export async function importFollowing(job: Bull.Job, done: } } - logger.succ('Imported'); + logger.succ("Imported"); done(); } diff --git a/packages/backend/src/queue/processors/db/import-muting.ts b/packages/backend/src/queue/processors/db/import-muting.ts index aa14ff526..80e056739 100644 --- a/packages/backend/src/queue/processors/db/import-muting.ts +++ b/packages/backend/src/queue/processors/db/import-muting.ts @@ -1,19 +1,22 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import * as Acct from '@/misc/acct.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { downloadTextFile } from '@/misc/download-text-file.js'; -import { isSelfHost, toPuny } from '@/misc/convert-host.js'; -import { Users, DriveFiles, Mutings } from '@/models/index.js'; -import { DbUserImportJobData } from '@/queue/types.js'; -import { User } from '@/models/entities/user.js'; -import { genId } from '@/misc/gen-id.js'; -import { IsNull } from 'typeorm'; +import { queueLogger } from "../../logger.js"; +import * as Acct from "@/misc/acct.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { downloadTextFile } from "@/misc/download-text-file.js"; +import { isSelfHost, toPuny } from "@/misc/convert-host.js"; +import { Users, DriveFiles, Mutings } from "@/models/index.js"; +import type { DbUserImportJobData } from "@/queue/types.js"; +import type { User } from "@/models/entities/user.js"; +import { genId } from "@/misc/gen-id.js"; +import { IsNull } from "typeorm"; -const logger = queueLogger.createSubLogger('import-muting'); +const logger = queueLogger.createSubLogger("import-muting"); -export async function importMuting(job: Bull.Job, done: any): Promise { +export async function importMuting( + job: Bull.Job, + done: any, +): Promise { logger.info(`Importing muting of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -34,20 +37,22 @@ export async function importMuting(job: Bull.Job, done: any let linenum = 0; - for (const line of csv.trim().split('\n')) { + for (const line of csv.trim().split("\n")) { linenum++; try { - const acct = line.split(',')[0].trim(); + const acct = line.split(",")[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOneBy({ - host: IsNull(), - usernameLower: username.toLowerCase(), - }) : await Users.findOneBy({ - host: toPuny(host!), - usernameLower: username.toLowerCase(), - }); + let target = isSelfHost(host!) + ? await Users.findOneBy({ + host: IsNull(), + usernameLower: username.toLowerCase(), + }) + : await Users.findOneBy({ + host: toPuny(host!), + usernameLower: username.toLowerCase(), + }); if (host == null && target == null) continue; @@ -70,7 +75,7 @@ export async function importMuting(job: Bull.Job, done: any } } - logger.succ('Imported'); + logger.succ("Imported"); done(); } diff --git a/packages/backend/src/queue/processors/db/import-user-lists.ts b/packages/backend/src/queue/processors/db/import-user-lists.ts index 9919b7c53..0c23f0699 100644 --- a/packages/backend/src/queue/processors/db/import-user-lists.ts +++ b/packages/backend/src/queue/processors/db/import-user-lists.ts @@ -1,19 +1,27 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import * as Acct from '@/misc/acct.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { pushUserToUserList } from '@/services/user-list/push.js'; -import { downloadTextFile } from '@/misc/download-text-file.js'; -import { isSelfHost, toPuny } from '@/misc/convert-host.js'; -import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { DbUserImportJobData } from '@/queue/types.js'; -import { IsNull } from 'typeorm'; +import { queueLogger } from "../../logger.js"; +import * as Acct from "@/misc/acct.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { pushUserToUserList } from "@/services/user-list/push.js"; +import { downloadTextFile } from "@/misc/download-text-file.js"; +import { isSelfHost, toPuny } from "@/misc/convert-host.js"; +import { + DriveFiles, + Users, + UserLists, + UserListJoinings, +} from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { DbUserImportJobData } from "@/queue/types.js"; +import { IsNull } from "typeorm"; -const logger = queueLogger.createSubLogger('import-user-lists'); +const logger = queueLogger.createSubLogger("import-user-lists"); -export async function importUserLists(job: Bull.Job, done: any): Promise { +export async function importUserLists( + job: Bull.Job, + done: any, +): Promise { logger.info(`Importing user lists of ${job.data.user.id} ...`); const user = await Users.findOneBy({ id: job.data.user.id }); @@ -34,12 +42,12 @@ export async function importUserLists(job: Bull.Job, done: let linenum = 0; - for (const line of csv.trim().split('\n')) { + for (const line of csv.trim().split("\n")) { linenum++; try { - const listName = line.split(',')[0].trim(); - const { username, host } = Acct.parse(line.split(',')[1].trim()); + const listName = line.split(",")[0].trim(); + const { username, host } = Acct.parse(line.split(",")[1].trim()); let list = await UserLists.findOneBy({ userId: user.id, @@ -52,22 +60,30 @@ export async function importUserLists(job: Bull.Job, done: createdAt: new Date(), userId: user.id, name: listName, - }).then(x => UserLists.findOneByOrFail(x.identifiers[0])); + }).then((x) => UserLists.findOneByOrFail(x.identifiers[0])); } - let target = isSelfHost(host!) ? await Users.findOneBy({ - host: IsNull(), - usernameLower: username.toLowerCase(), - }) : await Users.findOneBy({ - host: toPuny(host!), - usernameLower: username.toLowerCase(), - }); + let target = isSelfHost(host!) + ? await Users.findOneBy({ + host: IsNull(), + usernameLower: username.toLowerCase(), + }) + : await Users.findOneBy({ + host: toPuny(host!), + usernameLower: username.toLowerCase(), + }); if (target == null) { target = await resolveUser(username, host); } - if (await UserListJoinings.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue; + if ( + (await UserListJoinings.findOneBy({ + userListId: list!.id, + userId: target.id, + })) != null + ) + continue; pushUserToUserList(target, list!); } catch (e) { @@ -75,6 +91,6 @@ export async function importUserLists(job: Bull.Job, done: } } - logger.succ('Imported'); + logger.succ("Imported"); done(); } diff --git a/packages/backend/src/queue/processors/db/index.ts b/packages/backend/src/queue/processors/db/index.ts index e91d56977..90173053f 100644 --- a/packages/backend/src/queue/processors/db/index.ts +++ b/packages/backend/src/queue/processors/db/index.ts @@ -1,18 +1,18 @@ -import Bull from 'bull'; -import { DbJobData } from '@/queue/types.js'; -import { deleteDriveFiles } from './delete-drive-files.js'; -import { exportCustomEmojis } from './export-custom-emojis.js'; -import { exportNotes } from './export-notes.js'; -import { exportFollowing } from './export-following.js'; -import { exportMute } from './export-mute.js'; -import { exportBlocking } from './export-blocking.js'; -import { exportUserLists } from './export-user-lists.js'; -import { importFollowing } from './import-following.js'; -import { importUserLists } from './import-user-lists.js'; -import { deleteAccount } from './delete-account.js'; -import { importMuting } from './import-muting.js'; -import { importBlocking } from './import-blocking.js'; -import { importCustomEmojis } from './import-custom-emojis.js'; +import type Bull from "bull"; +import type { DbJobData } from "@/queue/types.js"; +import { deleteDriveFiles } from "./delete-drive-files.js"; +import { exportCustomEmojis } from "./export-custom-emojis.js"; +import { exportNotes } from "./export-notes.js"; +import { exportFollowing } from "./export-following.js"; +import { exportMute } from "./export-mute.js"; +import { exportBlocking } from "./export-blocking.js"; +import { exportUserLists } from "./export-user-lists.js"; +import { importFollowing } from "./import-following.js"; +import { importUserLists } from "./import-user-lists.js"; +import { deleteAccount } from "./delete-account.js"; +import { importMuting } from "./import-muting.js"; +import { importBlocking } from "./import-blocking.js"; +import { importCustomEmojis } from "./import-custom-emojis.js"; const jobs = { deleteDriveFiles, @@ -28,9 +28,13 @@ const jobs = { importUserLists, importCustomEmojis, deleteAccount, -} as Record | Bull.ProcessPromiseFunction>; +} as Record< + string, + | Bull.ProcessCallbackFunction + | Bull.ProcessPromiseFunction +>; -export default function(dbQueue: Bull.Queue) { +export default function (dbQueue: Bull.Queue) { for (const [k, v] of Object.entries(jobs)) { dbQueue.process(k, v); } diff --git a/packages/backend/src/queue/processors/deliver.ts b/packages/backend/src/queue/processors/deliver.ts index df8dbb23e..65471a559 100644 --- a/packages/backend/src/queue/processors/deliver.ts +++ b/packages/backend/src/queue/processors/deliver.ts @@ -1,17 +1,21 @@ -import { URL } from 'node:url'; -import request from '@/remote/activitypub/request.js'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; -import Logger from '@/services/logger.js'; -import { Instances } from '@/models/index.js'; -import { apRequestChart, federationChart, instanceChart } from '@/services/chart/index.js'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { StatusError } from '@/misc/fetch.js'; -import { shouldSkipInstance } from '@/misc/skipped-instances.js'; -import type { DeliverJobData } from '@/queue/types.js'; -import type Bull from 'bull'; +import { URL } from "node:url"; +import request from "@/remote/activitypub/request.js"; +import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; +import Logger from "@/services/logger.js"; +import { Instances } from "@/models/index.js"; +import { + apRequestChart, + federationChart, + instanceChart, +} from "@/services/chart/index.js"; +import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { StatusError } from "@/misc/fetch.js"; +import { shouldSkipInstance } from "@/misc/skipped-instances.js"; +import type { DeliverJobData } from "@/queue/types.js"; +import type Bull from "bull"; -const logger = new Logger('deliver'); +const logger = new Logger("deliver"); let latest: string | null = null; @@ -19,7 +23,7 @@ export default async (job: Bull.Job) => { const { host } = new URL(job.data.to); const puny = toPuny(host); - if (await shouldSkipInstance(puny)) return 'skip'; + if (await shouldSkipInstance(puny)) return "skip"; try { if (latest !== (latest = JSON.stringify(job.data.content, null, 2))) { @@ -29,7 +33,7 @@ export default async (job: Bull.Job) => { await request(job.data.user, job.data.to, job.data.content); // Update stats - registerOrFetchInstanceDoc(host).then(i => { + registerOrFetchInstanceDoc(host).then((i) => { Instances.update(i.id, { latestRequestSentAt: new Date(), latestStatus: 200, @@ -44,10 +48,10 @@ export default async (job: Bull.Job) => { federationChart.deliverd(i.host, true); }); - return 'Success'; + return "Success"; } catch (res) { // Update stats - registerOrFetchInstanceDoc(host).then(i => { + registerOrFetchInstanceDoc(host).then((i) => { Instances.update(i.id, { latestRequestSentAt: new Date(), latestStatus: res instanceof StatusError ? res.statusCode : null, diff --git a/packages/backend/src/queue/processors/ended-poll-notification.ts b/packages/backend/src/queue/processors/ended-poll-notification.ts index 6151c96ad..9fe57d8da 100644 --- a/packages/backend/src/queue/processors/ended-poll-notification.ts +++ b/packages/backend/src/queue/processors/ended-poll-notification.ts @@ -1,30 +1,33 @@ -import Bull from 'bull'; -import { In } from 'typeorm'; -import { Notes, Polls, PollVotes } from '@/models/index.js'; -import { queueLogger } from '../logger.js'; -import { EndedPollNotificationJobData } from '@/queue/types.js'; -import { createNotification } from '@/services/create-notification.js'; +import type Bull from "bull"; +import { In } from "typeorm"; +import { Notes, Polls, PollVotes } from "@/models/index.js"; +import { queueLogger } from "../logger.js"; +import type { EndedPollNotificationJobData } from "@/queue/types.js"; +import { createNotification } from "@/services/create-notification.js"; -const logger = queueLogger.createSubLogger('ended-poll-notification'); +const logger = queueLogger.createSubLogger("ended-poll-notification"); -export async function endedPollNotification(job: Bull.Job, done: any): Promise { +export async function endedPollNotification( + job: Bull.Job, + done: any, +): Promise { const note = await Notes.findOneBy({ id: job.data.noteId }); if (note == null || !note.hasPoll) { done(); return; } - const votes = await PollVotes.createQueryBuilder('vote') - .select('vote.userId') - .where('vote.noteId = :noteId', { noteId: note.id }) - .innerJoinAndSelect('vote.user', 'user') - .andWhere('user.host IS NULL') + const votes = await PollVotes.createQueryBuilder("vote") + .select("vote.userId") + .where("vote.noteId = :noteId", { noteId: note.id }) + .innerJoinAndSelect("vote.user", "user") + .andWhere("user.host IS NULL") .getMany(); - const userIds = [...new Set([note.userId, ...votes.map(v => v.userId)])]; + const userIds = [...new Set([note.userId, ...votes.map((v) => v.userId)])]; for (const userId of userIds) { - createNotification(userId, 'pollEnded', { + createNotification(userId, "pollEnded", { noteId: note.id, }); } diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index 33949672c..ca063a6f3 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -1,40 +1,45 @@ -import { URL } from 'node:url'; -import Bull from 'bull'; -import httpSignature from '@peertube/http-signature'; -import perform from '@/remote/activitypub/perform.js'; -import Logger from '@/services/logger.js'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; -import { Instances } from '@/models/index.js'; -import { apRequestChart, federationChart, instanceChart } from '@/services/chart/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { toPuny, extractDbHost } from '@/misc/convert-host.js'; -import { getApId } from '@/remote/activitypub/type.js'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; -import { InboxJobData } from '../types.js'; -import DbResolver from '@/remote/activitypub/db-resolver.js'; -import { resolvePerson } from '@/remote/activitypub/models/person.js'; -import { LdSignature } from '@/remote/activitypub/misc/ld-signature.js'; -import { StatusError } from '@/misc/fetch.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { UserPublickey } from '@/models/entities/user-publickey.js'; +import { URL } from "node:url"; +import type Bull from "bull"; +import httpSignature from "@peertube/http-signature"; +import perform from "@/remote/activitypub/perform.js"; +import Logger from "@/services/logger.js"; +import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; +import { Instances } from "@/models/index.js"; +import { + apRequestChart, + federationChart, + instanceChart, +} from "@/services/chart/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { toPuny, extractDbHost } from "@/misc/convert-host.js"; +import { getApId } from "@/remote/activitypub/type.js"; +import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; +import type { InboxJobData } from "../types.js"; +import DbResolver from "@/remote/activitypub/db-resolver.js"; +import { resolvePerson } from "@/remote/activitypub/models/person.js"; +import { LdSignature } from "@/remote/activitypub/misc/ld-signature.js"; +import { StatusError } from "@/misc/fetch.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { UserPublickey } from "@/models/entities/user-publickey.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; -const logger = new Logger('inbox'); +const logger = new Logger("inbox"); // Processing when an activity arrives in the user's inbox export default async (job: Bull.Job): Promise => { - const signature = job.data.signature; // HTTP-signature + const signature = job.data.signature; // HTTP-signature const activity = job.data.activity; //#region Log const info = Object.assign({}, activity) as any; - delete info['@context']; + info["@context"] = undefined; logger.debug(JSON.stringify(info, null, 2)); //#endregion const host = toPuny(new URL(signature.keyId).hostname); // interrupt if blocked const meta = await fetchMeta(); - if (meta.blockedHosts.includes(host)) { + if (await shouldBlockInstance(host, meta)) { return `Blocked request: ${host}`; } @@ -44,7 +49,7 @@ export default async (job: Bull.Job): Promise => { } const keyIdLower = signature.keyId.toLowerCase(); - if (keyIdLower.startsWith('acct:')) { + if (keyIdLower.startsWith("acct:")) { return `Old keyId is no longer supported. ${keyIdLower}`; } @@ -66,54 +71,63 @@ export default async (job: Bull.Job): Promise => { if (e.isClientError) { return `skip: Ignored deleted actors on both ends ${activity.actor} - ${e.statusCode}`; } - throw new Error(`Error in actor ${activity.actor} - ${e.statusCode || e}`); + throw new Error( + `Error in actor ${activity.actor} - ${e.statusCode || e}`, + ); } } } // それでもわからなければ終了 if (authUser == null) { - return `skip: failed to resolve user`; + return "skip: failed to resolve user"; } // publicKey がなくても終了 if (authUser.key == null) { - return `skip: failed to resolve user publicKey`; + return "skip: failed to resolve user publicKey"; } // HTTP-Signatureの検証 - const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem); + const httpSignatureValidated = httpSignature.verifySignature( + signature, + authUser.key.keyPem, + ); // また、signatureのsignerは、activity.actorと一致する必要がある if (!httpSignatureValidated || authUser.user.uri !== activity.actor) { // 一致しなくても、でもLD-Signatureがありそうならそっちも見る if (activity.signature) { - if (activity.signature.type !== 'RsaSignature2017') { + if (activity.signature.type !== "RsaSignature2017") { return `skip: unsupported LD-signature type ${activity.signature.type}`; } // activity.signature.creator: https://example.oom/users/user#main-key // みたいになっててUserを引っ張れば公開キーも入ることを期待する if (activity.signature.creator) { - const candicate = activity.signature.creator.replace(/#.*/, ''); + const candicate = activity.signature.creator.replace(/#.*/, ""); await resolvePerson(candicate).catch(() => null); } // keyIdからLD-Signatureのユーザーを取得 - authUser = await dbResolver.getAuthUserFromKeyId(activity.signature.creator); + authUser = await dbResolver.getAuthUserFromKeyId( + activity.signature.creator, + ); if (authUser == null) { - return `skip: LD-Signatureのユーザーが取得できませんでした`; + return "skip: LD-Signatureのユーザーが取得できませんでした"; } if (authUser.key == null) { - return `skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした`; + return "skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした"; } // LD-Signature検証 const ldSignature = new LdSignature(); - const verified = await ldSignature.verifyRsaSignature2017(activity, authUser.key.keyPem).catch(() => false); + const verified = await ldSignature + .verifyRsaSignature2017(activity, authUser.key.keyPem) + .catch(() => false); if (!verified) { - return `skip: LD-Signatureの検証に失敗しました`; + return "skip: LD-Signatureの検証に失敗しました"; } // もう一度actorチェック @@ -123,7 +137,7 @@ export default async (job: Bull.Job): Promise => { // ブロックしてたら中断 const ldHost = extractDbHost(authUser.user.uri); - if (meta.blockedHosts.includes(ldHost)) { + if (await shouldBlockInstance(ldHost, meta)) { return `Blocked request: ${ldHost}`; } } else { @@ -132,7 +146,7 @@ export default async (job: Bull.Job): Promise => { } // activity.idがあればホストが署名者のホストであることを確認する - if (typeof activity.id === 'string') { + if (typeof activity.id === "string") { const signerHost = extractDbHost(authUser.user.uri!); const activityIdHost = extractDbHost(activity.id); if (signerHost !== activityIdHost) { @@ -141,7 +155,7 @@ export default async (job: Bull.Job): Promise => { } // Update stats - registerOrFetchInstanceDoc(authUser.user.host).then(i => { + registerOrFetchInstanceDoc(authUser.user.host).then((i) => { Instances.update(i.id, { latestRequestReceivedAt: new Date(), lastCommunicatedAt: new Date(), @@ -157,5 +171,5 @@ export default async (job: Bull.Job): Promise => { // アクティビティを処理 await perform(authUser.user, activity); - return `ok`; + return "ok"; }; diff --git a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts index 77da162f6..fdfe05d1a 100644 --- a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts +++ b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts @@ -1,14 +1,17 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import { deleteFileSync } from '@/services/drive/delete-file.js'; -import { DriveFiles } from '@/models/index.js'; -import { MoreThan, Not, IsNull } from 'typeorm'; +import { queueLogger } from "../../logger.js"; +import { deleteFileSync } from "@/services/drive/delete-file.js"; +import { DriveFiles } from "@/models/index.js"; +import { MoreThan, Not, IsNull } from "typeorm"; -const logger = queueLogger.createSubLogger('clean-remote-files'); +const logger = queueLogger.createSubLogger("clean-remote-files"); -export default async function cleanRemoteFiles(job: Bull.Job>, done: any): Promise { - logger.info(`Deleting cached remote files...`); +export default async function cleanRemoteFiles( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Deleting cached remote files..."); let deletedCount = 0; let cursor: any = null; @@ -33,7 +36,7 @@ export default async function cleanRemoteFiles(job: Bull.Job deleteFileSync(file, true))); + await Promise.all(files.map((file) => deleteFileSync(file, true))); deletedCount += 8; @@ -45,6 +48,6 @@ export default async function cleanRemoteFiles(job: Bull.Job) => { const key: string = job.data.key; await deleteObjectStorageFile(key); - return 'Success'; + return "Success"; }; diff --git a/packages/backend/src/queue/processors/object-storage/index.ts b/packages/backend/src/queue/processors/object-storage/index.ts index ae6c481fe..5f90d4cd0 100644 --- a/packages/backend/src/queue/processors/object-storage/index.ts +++ b/packages/backend/src/queue/processors/object-storage/index.ts @@ -1,14 +1,18 @@ -import Bull from 'bull'; -import { ObjectStorageJobData } from '@/queue/types.js'; -import deleteFile from './delete-file.js'; -import cleanRemoteFiles from './clean-remote-files.js'; +import type Bull from "bull"; +import type { ObjectStorageJobData } from "@/queue/types.js"; +import deleteFile from "./delete-file.js"; +import cleanRemoteFiles from "./clean-remote-files.js"; const jobs = { deleteFile, cleanRemoteFiles, -} as Record | Bull.ProcessPromiseFunction>; +} as Record< + string, + | Bull.ProcessCallbackFunction + | Bull.ProcessPromiseFunction +>; -export default function(q: Bull.Queue) { +export default function (q: Bull.Queue) { for (const [k, v] of Object.entries(jobs)) { q.process(k, 16, v); } diff --git a/packages/backend/src/queue/processors/system/check-expired-mutings.ts b/packages/backend/src/queue/processors/system/check-expired-mutings.ts index 621269e7e..a482d0218 100644 --- a/packages/backend/src/queue/processors/system/check-expired-mutings.ts +++ b/packages/backend/src/queue/processors/system/check-expired-mutings.ts @@ -1,30 +1,33 @@ -import Bull from 'bull'; -import { In } from 'typeorm'; -import { Mutings } from '@/models/index.js'; -import { queueLogger } from '../../logger.js'; -import { publishUserEvent } from '@/services/stream.js'; +import type Bull from "bull"; +import { In } from "typeorm"; +import { Mutings } from "@/models/index.js"; +import { queueLogger } from "../../logger.js"; +import { publishUserEvent } from "@/services/stream.js"; -const logger = queueLogger.createSubLogger('check-expired-mutings'); +const logger = queueLogger.createSubLogger("check-expired-mutings"); -export async function checkExpiredMutings(job: Bull.Job>, done: any): Promise { - logger.info(`Checking expired mutings...`); +export async function checkExpiredMutings( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Checking expired mutings..."); - const expired = await Mutings.createQueryBuilder('muting') - .where('muting.expiresAt IS NOT NULL') - .andWhere('muting.expiresAt < :now', { now: new Date() }) - .innerJoinAndSelect('muting.mutee', 'mutee') + const expired = await Mutings.createQueryBuilder("muting") + .where("muting.expiresAt IS NOT NULL") + .andWhere("muting.expiresAt < :now", { now: new Date() }) + .innerJoinAndSelect("muting.mutee", "mutee") .getMany(); if (expired.length > 0) { await Mutings.delete({ - id: In(expired.map(m => m.id)), + id: In(expired.map((m) => m.id)), }); for (const m of expired) { - publishUserEvent(m.muterId, 'unmute', m.mutee!); + publishUserEvent(m.muterId, "unmute", m.mutee!); } } - logger.succ(`All expired mutings checked.`); + logger.succ("All expired mutings checked."); done(); } diff --git a/packages/backend/src/queue/processors/system/clean-charts.ts b/packages/backend/src/queue/processors/system/clean-charts.ts index c9169d5ac..dde5d95fe 100644 --- a/packages/backend/src/queue/processors/system/clean-charts.ts +++ b/packages/backend/src/queue/processors/system/clean-charts.ts @@ -1,12 +1,28 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import { activeUsersChart, driveChart, federationChart, hashtagChart, instanceChart, notesChart, perUserDriveChart, perUserFollowingChart, perUserNotesChart, perUserReactionsChart, usersChart, apRequestChart } from '@/services/chart/index.js'; +import { queueLogger } from "../../logger.js"; +import { + activeUsersChart, + driveChart, + federationChart, + hashtagChart, + instanceChart, + notesChart, + perUserDriveChart, + perUserFollowingChart, + perUserNotesChart, + perUserReactionsChart, + usersChart, + apRequestChart, +} from "@/services/chart/index.js"; -const logger = queueLogger.createSubLogger('clean-charts'); +const logger = queueLogger.createSubLogger("clean-charts"); -export async function cleanCharts(job: Bull.Job>, done: any): Promise { - logger.info(`Clean charts...`); +export async function cleanCharts( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Clean charts..."); await Promise.all([ federationChart.clean(), @@ -23,6 +39,6 @@ export async function cleanCharts(job: Bull.Job>, done: apRequestChart.clean(), ]); - logger.succ(`All charts successfully cleaned.`); + logger.succ("All charts successfully cleaned."); done(); } diff --git a/packages/backend/src/queue/processors/system/clean.ts b/packages/backend/src/queue/processors/system/clean.ts index c4f978d7c..fbd45b0bb 100644 --- a/packages/backend/src/queue/processors/system/clean.ts +++ b/packages/backend/src/queue/processors/system/clean.ts @@ -1,18 +1,21 @@ -import Bull from 'bull'; -import { LessThan } from 'typeorm'; -import { UserIps } from '@/models/index.js'; +import type Bull from "bull"; +import { LessThan } from "typeorm"; +import { UserIps } from "@/models/index.js"; -import { queueLogger } from '../../logger.js'; +import { queueLogger } from "../../logger.js"; -const logger = queueLogger.createSubLogger('clean'); +const logger = queueLogger.createSubLogger("clean"); -export async function clean(job: Bull.Job>, done: any): Promise { - logger.info('Cleaning...'); +export async function clean( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Cleaning..."); UserIps.delete({ - createdAt: LessThan(new Date(Date.now() - (1000 * 60 * 60 * 24 * 90))), + createdAt: LessThan(new Date(Date.now() - 1000 * 60 * 60 * 24 * 90)), }); - logger.succ('Cleaned.'); + logger.succ("Cleaned."); done(); } diff --git a/packages/backend/src/queue/processors/system/index.ts b/packages/backend/src/queue/processors/system/index.ts index 9527d40b0..68833d76f 100644 --- a/packages/backend/src/queue/processors/system/index.ts +++ b/packages/backend/src/queue/processors/system/index.ts @@ -1,9 +1,9 @@ -import Bull from 'bull'; -import { tickCharts } from './tick-charts.js'; -import { resyncCharts } from './resync-charts.js'; -import { cleanCharts } from './clean-charts.js'; -import { checkExpiredMutings } from './check-expired-mutings.js'; -import { clean } from './clean.js'; +import type Bull from "bull"; +import { tickCharts } from "./tick-charts.js"; +import { resyncCharts } from "./resync-charts.js"; +import { cleanCharts } from "./clean-charts.js"; +import { checkExpiredMutings } from "./check-expired-mutings.js"; +import { clean } from "./clean.js"; const jobs = { tickCharts, @@ -11,9 +11,13 @@ const jobs = { cleanCharts, checkExpiredMutings, clean, -} as Record> | Bull.ProcessPromiseFunction>>; +} as Record< + string, + | Bull.ProcessCallbackFunction> + | Bull.ProcessPromiseFunction> +>; -export default function(dbQueue: Bull.Queue>) { +export default function (dbQueue: Bull.Queue>) { for (const [k, v] of Object.entries(jobs)) { dbQueue.process(k, v); } diff --git a/packages/backend/src/queue/processors/system/resync-charts.ts b/packages/backend/src/queue/processors/system/resync-charts.ts index 20012513a..dbea0df73 100644 --- a/packages/backend/src/queue/processors/system/resync-charts.ts +++ b/packages/backend/src/queue/processors/system/resync-charts.ts @@ -1,12 +1,15 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import { driveChart, notesChart, usersChart } from '@/services/chart/index.js'; +import { queueLogger } from "../../logger.js"; +import { driveChart, notesChart, usersChart } from "@/services/chart/index.js"; -const logger = queueLogger.createSubLogger('resync-charts'); +const logger = queueLogger.createSubLogger("resync-charts"); -export async function resyncCharts(job: Bull.Job>, done: any): Promise { - logger.info(`Resync charts...`); +export async function resyncCharts( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Resync charts..."); // TODO: ユーザーごとのチャートも更新する // TODO: インスタンスごとのチャートも更新する @@ -16,6 +19,6 @@ export async function resyncCharts(job: Bull.Job>, done: usersChart.resync(), ]); - logger.succ(`All charts successfully resynced.`); + logger.succ("All charts successfully resynced."); done(); } diff --git a/packages/backend/src/queue/processors/system/tick-charts.ts b/packages/backend/src/queue/processors/system/tick-charts.ts index 13403f8f7..33eed8a59 100644 --- a/packages/backend/src/queue/processors/system/tick-charts.ts +++ b/packages/backend/src/queue/processors/system/tick-charts.ts @@ -1,12 +1,28 @@ -import Bull from 'bull'; +import type Bull from "bull"; -import { queueLogger } from '../../logger.js'; -import { activeUsersChart, driveChart, federationChart, hashtagChart, instanceChart, notesChart, perUserDriveChart, perUserFollowingChart, perUserNotesChart, perUserReactionsChart, usersChart, apRequestChart } from '@/services/chart/index.js'; +import { queueLogger } from "../../logger.js"; +import { + activeUsersChart, + driveChart, + federationChart, + hashtagChart, + instanceChart, + notesChart, + perUserDriveChart, + perUserFollowingChart, + perUserNotesChart, + perUserReactionsChart, + usersChart, + apRequestChart, +} from "@/services/chart/index.js"; -const logger = queueLogger.createSubLogger('tick-charts'); +const logger = queueLogger.createSubLogger("tick-charts"); -export async function tickCharts(job: Bull.Job>, done: any): Promise { - logger.info(`Tick charts...`); +export async function tickCharts( + job: Bull.Job>, + done: any, +): Promise { + logger.info("Tick charts..."); await Promise.all([ federationChart.tick(false), @@ -23,6 +39,6 @@ export async function tickCharts(job: Bull.Job>, done: a apRequestChart.tick(false), ]); - logger.succ(`All charts successfully ticked.`); + logger.succ("All charts successfully ticked."); done(); } diff --git a/packages/backend/src/queue/processors/webhook-deliver.ts b/packages/backend/src/queue/processors/webhook-deliver.ts index f69518388..a130fcd38 100644 --- a/packages/backend/src/queue/processors/webhook-deliver.ts +++ b/packages/backend/src/queue/processors/webhook-deliver.ts @@ -1,12 +1,12 @@ -import { URL } from 'node:url'; -import Bull from 'bull'; -import Logger from '@/services/logger.js'; -import { WebhookDeliverJobData } from '../types.js'; -import { getResponse, StatusError } from '@/misc/fetch.js'; -import { Webhooks } from '@/models/index.js'; -import config from '@/config/index.js'; +import { URL } from "node:url"; +import type Bull from "bull"; +import Logger from "@/services/logger.js"; +import type { WebhookDeliverJobData } from "../types.js"; +import { getResponse, StatusError } from "@/misc/fetch.js"; +import { Webhooks } from "@/models/index.js"; +import config from "@/config/index.js"; -const logger = new Logger('webhook'); +const logger = new Logger("webhook"); export default async (job: Bull.Job) => { try { @@ -14,12 +14,12 @@ export default async (job: Bull.Job) => { const res = await getResponse({ url: job.data.to, - method: 'POST', + method: "POST", headers: { - 'User-Agent': 'Calckey-Hooks', - 'X-Calckey-Host': config.host, - 'X-Calckey-Hook-Id': job.data.webhookId, - 'X-Calckey-Hook-Secret': job.data.secret, + "User-Agent": "Calckey-Hooks", + "X-Calckey-Host": config.host, + "X-Calckey-Hook-Id": job.data.webhookId, + "X-Calckey-Hook-Secret": job.data.secret, }, body: JSON.stringify({ hookId: job.data.webhookId, @@ -31,17 +31,23 @@ export default async (job: Bull.Job) => { }), }); - Webhooks.update({ id: job.data.webhookId }, { - latestSentAt: new Date(), - latestStatus: res.status, - }); + Webhooks.update( + { id: job.data.webhookId }, + { + latestSentAt: new Date(), + latestStatus: res.status, + }, + ); - return 'Success'; + return "Success"; } catch (res) { - Webhooks.update({ id: job.data.webhookId }, { - latestSentAt: new Date(), - latestStatus: res instanceof StatusError ? res.statusCode : 1, - }); + Webhooks.update( + { id: job.data.webhookId }, + { + latestSentAt: new Date(), + latestStatus: res instanceof StatusError ? res.statusCode : 1, + }, + ); if (res instanceof StatusError) { // 4xx diff --git a/packages/backend/src/queue/queues.ts b/packages/backend/src/queue/queues.ts index f3a267790..12d9d6620 100644 --- a/packages/backend/src/queue/queues.ts +++ b/packages/backend/src/queue/queues.ts @@ -1,14 +1,32 @@ -import config from '@/config/index.js'; -import { initialize as initializeQueue } from './initialize.js'; -import { DeliverJobData, InboxJobData, DbJobData, ObjectStorageJobData, EndedPollNotificationJobData, WebhookDeliverJobData } from './types.js'; +import config from "@/config/index.js"; +import { initialize as initializeQueue } from "./initialize.js"; +import type { + DeliverJobData, + InboxJobData, + DbJobData, + ObjectStorageJobData, + EndedPollNotificationJobData, + WebhookDeliverJobData, +} from "./types.js"; -export const systemQueue = initializeQueue>('system'); -export const endedPollNotificationQueue = initializeQueue('endedPollNotification'); -export const deliverQueue = initializeQueue('deliver', config.deliverJobPerSec || 128); -export const inboxQueue = initializeQueue('inbox', config.inboxJobPerSec || 16); -export const dbQueue = initializeQueue('db'); -export const objectStorageQueue = initializeQueue('objectStorage'); -export const webhookDeliverQueue = initializeQueue('webhookDeliver', 64); +export const systemQueue = initializeQueue>("system"); +export const endedPollNotificationQueue = + initializeQueue("endedPollNotification"); +export const deliverQueue = initializeQueue( + "deliver", + config.deliverJobPerSec || 128, +); +export const inboxQueue = initializeQueue( + "inbox", + config.inboxJobPerSec || 16, +); +export const dbQueue = initializeQueue("db"); +export const objectStorageQueue = + initializeQueue("objectStorage"); +export const webhookDeliverQueue = initializeQueue( + "webhookDeliver", + 64, +); export const queues = [ systemQueue, diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index 5ea472556..90e88f736 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -1,9 +1,9 @@ -import { DriveFile } from '@/models/entities/drive-file.js'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user.js'; -import { Webhook } from '@/models/entities/webhook'; -import { IActivity } from '@/remote/activitypub/type.js'; -import httpSignature from '@peertube/http-signature'; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { Note } from "@/models/entities/note"; +import type { User } from "@/models/entities/user.js"; +import type { Webhook } from "@/models/entities/webhook"; +import type { IActivity } from "@/remote/activitypub/type.js"; +import type httpSignature from "@peertube/http-signature"; export type DeliverJobData = { /** Actor */ @@ -19,7 +19,10 @@ export type InboxJobData = { signature: httpSignature.IParsedSignature; }; -export type DbJobData = DbUserJobData | DbUserImportJobData | DbUserDeleteJobData; +export type DbJobData = + | DbUserJobData + | DbUserImportJobData + | DbUserDeleteJobData; export type DbUserJobData = { user: ThinUser; @@ -34,24 +37,26 @@ export type DbUserDeleteJobData = { export type DbUserImportJobData = { user: ThinUser; - fileId: DriveFile['id']; + fileId: DriveFile["id"]; }; -export type ObjectStorageJobData = ObjectStorageFileJobData | Record; +export type ObjectStorageJobData = + | ObjectStorageFileJobData + | Record; export type ObjectStorageFileJobData = { key: string; }; export type EndedPollNotificationJobData = { - noteId: Note['id']; + noteId: Note["id"]; }; export type WebhookDeliverJobData = { type: string; content: unknown; - webhookId: Webhook['id']; - userId: User['id']; + webhookId: Webhook["id"]; + userId: User["id"]; to: string; secret: string; createdAt: number; @@ -59,5 +64,5 @@ export type WebhookDeliverJobData = { }; export type ThinUser = { - id: User['id']; + id: User["id"]; }; diff --git a/packages/backend/src/remote/activitypub/ap-request.ts b/packages/backend/src/remote/activitypub/ap-request.ts index 8b55f2247..d5a9ec053 100644 --- a/packages/backend/src/remote/activitypub/ap-request.ts +++ b/packages/backend/src/remote/activitypub/ap-request.ts @@ -1,5 +1,5 @@ -import * as crypto from 'node:crypto'; -import { URL } from 'node:url'; +import * as crypto from "node:crypto"; +import { URL } from "node:url"; type Request = { url: string; @@ -12,22 +12,38 @@ type PrivateKey = { keyId: string; }; -export function createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record }) { +export function createSignedPost(args: { + key: PrivateKey; + url: string; + body: string; + additionalHeaders: Record; +}) { const u = new URL(args.url); - const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`; + const digestHeader = `SHA-256=${crypto + .createHash("sha256") + .update(args.body) + .digest("base64")}`; const request: Request = { url: u.href, - method: 'POST', - headers: objectAssignWithLcKey({ - 'Date': new Date().toUTCString(), - 'Host': u.hostname, - 'Content-Type': 'application/activity+json', - 'Digest': digestHeader, - }, args.additionalHeaders), + method: "POST", + headers: objectAssignWithLcKey( + { + Date: new Date().toUTCString(), + Host: u.hostname, + "Content-Type": "application/activity+json", + Digest: digestHeader, + }, + args.additionalHeaders, + ), }; - const result = signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']); + const result = signToRequest(request, args.key, [ + "(request-target)", + "date", + "host", + "digest", + ]); return { request, @@ -37,20 +53,32 @@ export function createSignedPost(args: { key: PrivateKey, url: string, body: str }; } -export function createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record }) { +export function createSignedGet(args: { + key: PrivateKey; + url: string; + additionalHeaders: Record; +}) { const u = new URL(args.url); const request: Request = { url: u.href, - method: 'GET', - headers: objectAssignWithLcKey({ - 'Accept': 'application/activity+json, application/ld+json', - 'Date': new Date().toUTCString(), - 'Host': new URL(args.url).hostname, - }, args.additionalHeaders), + method: "GET", + headers: objectAssignWithLcKey( + { + Accept: "application/activity+json, application/ld+json", + Date: new Date().toUTCString(), + Host: new URL(args.url).hostname, + }, + args.additionalHeaders, + ), }; - const result = signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']); + const result = signToRequest(request, args.key, [ + "(request-target)", + "date", + "host", + "accept", + ]); return { request, @@ -60,10 +88,20 @@ export function createSignedGet(args: { key: PrivateKey, url: string, additional }; } -function signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]) { +function signToRequest( + request: Request, + key: PrivateKey, + includeHeaders: string[], +) { const signingString = genSigningString(request, includeHeaders); - const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64'); - const signatureHeader = `keyId="${key.keyId}",algorithm="rsa-sha256",headers="${includeHeaders.join(' ')}",signature="${signature}"`; + const signature = crypto + .sign("sha256", Buffer.from(signingString), key.privateKeyPem) + .toString("base64"); + const signatureHeader = `keyId="${ + key.keyId + }",algorithm="rsa-sha256",headers="${includeHeaders.join( + " ", + )}",signature="${signature}"`; request.headers = objectAssignWithLcKey(request.headers, { Signature: signatureHeader, @@ -82,23 +120,33 @@ function genSigningString(request: Request, includeHeaders: string[]) { const results: string[] = []; - for (const key of includeHeaders.map(x => x.toLowerCase())) { - if (key === '(request-target)') { - results.push(`(request-target): ${request.method.toLowerCase()} ${new URL(request.url).pathname}`); + for (const key of includeHeaders.map((x) => x.toLowerCase())) { + if (key === "(request-target)") { + results.push( + `(request-target): ${request.method.toLowerCase()} ${ + new URL(request.url).pathname + }`, + ); } else { results.push(`${key}: ${request.headers[key]}`); } } - return results.join('\n'); + return results.join("\n"); } function lcObjectKey(src: Record) { const dst: Record = {}; - for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key]; + for (const key of Object.keys(src).filter( + (x) => x !== "__proto__" && typeof src[x] === "string", + )) + dst[key.toLowerCase()] = src[key]; return dst; } -function objectAssignWithLcKey(a: Record, b: Record) { +function objectAssignWithLcKey( + a: Record, + b: Record, +) { return Object.assign(lcObjectKey(a), lcObjectKey(b)); } diff --git a/packages/backend/src/remote/activitypub/audience.ts b/packages/backend/src/remote/activitypub/audience.ts index 846ccf9c0..210d47573 100644 --- a/packages/backend/src/remote/activitypub/audience.ts +++ b/packages/backend/src/remote/activitypub/audience.ts @@ -1,32 +1,46 @@ -import { ApObject, getApIds } from './type.js'; -import Resolver from './resolver.js'; -import { resolvePerson } from './models/person.js'; -import { unique, concat } from '@/prelude/array.js'; -import promiseLimit from 'promise-limit'; -import { User, CacheableRemoteUser, CacheableUser } from '@/models/entities/user.js'; +import type { ApObject } from "./type.js"; +import { getApIds } from "./type.js"; +import type Resolver from "./resolver.js"; +import { resolvePerson } from "./models/person.js"; +import { unique, concat } from "@/prelude/array.js"; +import promiseLimit from "promise-limit"; +import type { + CacheableRemoteUser, + CacheableUser, +} from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; -type Visibility = 'public' | 'home' | 'followers' | 'specified'; +type Visibility = "public" | "home" | "followers" | "specified"; type AudienceInfo = { - visibility: Visibility, - mentionedUsers: CacheableUser[], - visibleUsers: CacheableUser[], + visibility: Visibility; + mentionedUsers: CacheableUser[]; + visibleUsers: CacheableUser[]; }; -export async function parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { +export async function parseAudience( + actor: CacheableRemoteUser, + to?: ApObject, + cc?: ApObject, + resolver?: Resolver, +): Promise { const toGroups = groupingAudience(getApIds(to), actor); const ccGroups = groupingAudience(getApIds(cc), actor); const others = unique(concat([toGroups.other, ccGroups.other])); const limit = promiseLimit(2); - const mentionedUsers = (await Promise.all( - others.map(id => limit(() => resolvePerson(id, resolver).catch(() => null))) - )).filter((x): x is CacheableUser => x != null); + const mentionedUsers = ( + await Promise.all( + others.map((id) => + limit(() => resolvePerson(id, resolver).catch(() => null)), + ), + ) + ).filter((x): x is CacheableUser => x != null); if (toGroups.public.length > 0) { return { - visibility: 'public', + visibility: "public", mentionedUsers, visibleUsers: [], }; @@ -34,7 +48,7 @@ export async function parseAudience(actor: CacheableRemoteUser, to?: ApObject, c if (ccGroups.public.length > 0) { return { - visibility: 'home', + visibility: "home", mentionedUsers, visibleUsers: [], }; @@ -42,14 +56,14 @@ export async function parseAudience(actor: CacheableRemoteUser, to?: ApObject, c if (toGroups.followers.length > 0) { return { - visibility: 'followers', + visibility: "followers", mentionedUsers, visibleUsers: [], }; } return { - visibility: 'specified', + visibility: "specified", mentionedUsers, visibleUsers: mentionedUsers, }; @@ -79,14 +93,12 @@ function groupingAudience(ids: string[], actor: CacheableRemoteUser) { function isPublic(id: string) { return [ - 'https://www.w3.org/ns/activitystreams#Public', - 'as#Public', - 'Public', + "https://www.w3.org/ns/activitystreams#Public", + "as#Public", + "Public", ].includes(id); } function isFollowers(id: string, actor: CacheableRemoteUser) { - return ( - id === (actor.followersUri || `${actor.uri}/followers`) - ); + return id === (actor.followersUri || `${actor.uri}/followers`); } diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts index 8a53396b6..a8bbe61b8 100644 --- a/packages/backend/src/remote/activitypub/check-fetch.ts +++ b/packages/backend/src/remote/activitypub/check-fetch.ts @@ -1,20 +1,35 @@ -import config from '@/config/index.js'; -import { IncomingMessage } from 'http'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import httpSignature from '@peertube/http-signature'; -import { URL } from 'url'; -import { toPuny } from '@/misc/convert-host.js'; -import DbResolver from '@/remote/activitypub/db-resolver.js'; -import { getApId } from '@/remote/activitypub/type.js'; +import { URL } from "url"; +import httpSignature from "@peertube/http-signature"; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { toPuny } from "@/misc/convert-host.js"; +import DbResolver from "@/remote/activitypub/db-resolver.js"; +import { getApId } from "@/remote/activitypub/type.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; +import type { IncomingMessage } from "http"; +export async function hasSignature(req: IncomingMessage): Promise { + const meta = await fetchMeta(); + const required = meta.secureMode || meta.privateMode; -export default async function checkFetch(req: IncomingMessage): Promise { + try { + httpSignature.parseRequest(req, { headers: [] }); + } catch (e) { + if (e instanceof Error && e.name === "MissingHeaderError") { + return required ? "missing" : "optional"; + } + return "invalid"; + } + return required ? "supplied" : "unneeded"; +} + +export async function checkFetch(req: IncomingMessage): Promise { const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { let signature; try { - signature = httpSignature.parseRequest(req, { 'headers': [] }); + signature = httpSignature.parseRequest(req, { headers: [] }); } catch (e) { return 401; } @@ -22,16 +37,20 @@ export default async function checkFetch(req: IncomingMessage): Promise const keyId = new URL(signature.keyId); const host = toPuny(keyId.hostname); - if (meta.blockedHosts.includes(host)) { + if (await shouldBlockInstance(host, meta)) { return 403; } - if (meta.privateMode && host !== config.host && !meta.allowedHosts.includes(host)) { + if ( + meta.privateMode && + host !== config.host && + !meta.allowedHosts.includes(host) + ) { return 403; } const keyIdLower = signature.keyId.toLowerCase(); - if (keyIdLower.startsWith('acct:')) { + if (keyIdLower.startsWith("acct:")) { // Old keyId is no longer supported. return 401; } @@ -44,8 +63,10 @@ export default async function checkFetch(req: IncomingMessage): Promise // keyIdでわからなければ、resolveしてみる if (authUser == null) { try { - keyId.hash = ''; - authUser = await dbResolver.getAuthUserFromApId(getApId(keyId.toString())); + keyId.hash = ""; + authUser = await dbResolver.getAuthUserFromApId( + getApId(keyId.toString()), + ); } catch (e) { // できなければ駄目 return 403; @@ -63,7 +84,10 @@ export default async function checkFetch(req: IncomingMessage): Promise } // HTTP-Signatureの検証 - const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem); + const httpSignatureValidated = httpSignature.verifySignature( + signature, + authUser.key.keyPem, + ); if (!httpSignatureValidated) { return 403; diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts index 1a02f675c..0a2aec9e8 100644 --- a/packages/backend/src/remote/activitypub/db-resolver.ts +++ b/packages/backend/src/remote/activitypub/db-resolver.ts @@ -1,39 +1,54 @@ -import escapeRegexp from 'escape-regexp'; -import config from '@/config/index.js'; -import { Note } from '@/models/entities/note.js'; -import { User, IRemoteUser, CacheableRemoteUser, CacheableUser } from '@/models/entities/user.js'; -import { UserPublickey } from '@/models/entities/user-publickey.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index.js'; -import { Cache } from '@/misc/cache.js'; -import { uriPersonCache, userByIdCache } from '@/services/user-cache.js'; -import { IObject, getApId } from './type.js'; -import { resolvePerson } from './models/person.js'; +import escapeRegexp from "escape-regexp"; +import config from "@/config/index.js"; +import type { Note } from "@/models/entities/note.js"; +import type { + CacheableRemoteUser, + CacheableUser, +} from "@/models/entities/user.js"; +import { User, IRemoteUser } from "@/models/entities/user.js"; +import type { UserPublickey } from "@/models/entities/user-publickey.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { + Notes, + Users, + UserPublickeys, + MessagingMessages, +} from "@/models/index.js"; +import { Cache } from "@/misc/cache.js"; +import { uriPersonCache, userByIdCache } from "@/services/user-cache.js"; +import type { IObject } from "./type.js"; +import { getApId } from "./type.js"; +import { resolvePerson } from "./models/person.js"; const publicKeyCache = new Cache(Infinity); const publicKeyByUserIdCache = new Cache(Infinity); -export type UriParseResult = { - /** wether the URI was generated by us */ - local: true; - /** id in DB */ - id: string; - /** hint of type, e.g. "notes", "users" */ - type: string; - /** any remaining text after type and id, not including the slash after id. undefined if empty */ - rest?: string; -} | { - /** wether the URI was generated by us */ - local: false; - /** uri in DB */ - uri: string; -}; +export type UriParseResult = + | { + /** wether the URI was generated by us */ + local: true; + /** id in DB */ + id: string; + /** hint of type, e.g. "notes", "users" */ + type: string; + /** any remaining text after type and id, not including the slash after id. undefined if empty */ + rest?: string; + } + | { + /** wether the URI was generated by us */ + local: false; + /** uri in DB */ + uri: string; + }; export function parseUri(value: string | IObject): UriParseResult { const uri = getApId(value); // the host part of a URL is case insensitive, so use the 'i' flag. - const localRegex = new RegExp('^' + escapeRegexp(config.url) + '/(\\w+)/(\\w+)(?:\/(.+))?', 'i'); + const localRegex = new RegExp( + `^${escapeRegexp(config.url)}/(\\w+)/(\\w+)(?:/(.+))?`, + "i", + ); const matchLocal = uri.match(localRegex); if (matchLocal) { @@ -52,8 +67,7 @@ export function parseUri(value: string | IObject): UriParseResult { } export default class DbResolver { - constructor() { - } + constructor() {} /** * AP Note => Misskey Note in DB @@ -62,7 +76,7 @@ export default class DbResolver { const parsed = parseUri(value); if (parsed.local) { - if (parsed.type !== 'notes') return null; + if (parsed.type !== "notes") return null; return await Notes.findOneBy({ id: parsed.id, @@ -74,11 +88,13 @@ export default class DbResolver { } } - public async getMessageFromApId(value: string | IObject): Promise { + public async getMessageFromApId( + value: string | IObject, + ): Promise { const parsed = parseUri(value); if (parsed.local) { - if (parsed.type !== 'notes') return null; + if (parsed.type !== "notes") return null; return await MessagingMessages.findOneBy({ id: parsed.id, @@ -93,19 +109,27 @@ export default class DbResolver { /** * AP Person => Misskey User in DB */ - public async getUserFromApId(value: string | IObject): Promise { + public async getUserFromApId( + value: string | IObject, + ): Promise { const parsed = parseUri(value); if (parsed.local) { - if (parsed.type !== 'users') return null; + if (parsed.type !== "users") return null; - return await userByIdCache.fetchMaybe(parsed.id, () => Users.findOneBy({ - id: parsed.id, - }).then(x => x ?? undefined)) ?? null; + return ( + (await userByIdCache.fetchMaybe(parsed.id, () => + Users.findOneBy({ + id: parsed.id, + }).then((x) => x ?? undefined), + )) ?? null + ); } else { - return await uriPersonCache.fetch(parsed.uri, () => Users.findOneBy({ - uri: parsed.uri, - })); + return await uriPersonCache.fetch(parsed.uri, () => + Users.findOneBy({ + uri: parsed.uri, + }), + ); } } @@ -116,20 +140,26 @@ export default class DbResolver { user: CacheableRemoteUser; key: UserPublickey; } | null> { - const key = await publicKeyCache.fetch(keyId, async () => { - const key = await UserPublickeys.findOneBy({ - keyId, - }); - - if (key == null) return null; + const key = await publicKeyCache.fetch( + keyId, + async () => { + const key = await UserPublickeys.findOneBy({ + keyId, + }); - return key; - }, key => key != null); + if (key == null) return null; + + return key; + }, + (key) => key != null, + ); if (key == null) return null; return { - user: await userByIdCache.fetch(key.userId, () => Users.findOneByOrFail({ id: key.userId })) as CacheableRemoteUser, + user: (await userByIdCache.fetch(key.userId, () => + Users.findOneByOrFail({ id: key.userId }), + )) as CacheableRemoteUser, key, }; } @@ -141,11 +171,15 @@ export default class DbResolver { user: CacheableRemoteUser; key: UserPublickey | null; } | null> { - const user = await resolvePerson(uri) as CacheableRemoteUser; + const user = (await resolvePerson(uri)) as CacheableRemoteUser; if (user == null) return null; - const key = await publicKeyByUserIdCache.fetch(user.id, () => UserPublickeys.findOneBy({ userId: user.id }), v => v != null); + const key = await publicKeyByUserIdCache.fetch( + user.id, + () => UserPublickeys.findOneBy({ userId: user.id }), + (v) => v != null, + ); return { user, diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index 1bcdcdfdb..400e04777 100644 --- a/packages/backend/src/remote/activitypub/deliver-manager.ts +++ b/packages/backend/src/remote/activitypub/deliver-manager.ts @@ -1,8 +1,8 @@ -import { IsNull, Not } from 'typeorm'; -import { Users, Followings } from '@/models/index.js'; -import type { ILocalUser, IRemoteUser, User } from '@/models/entities/user.js'; -import { deliver } from '@/queue/index.js'; -import { skippedInstances } from '@/misc/skipped-instances.js'; +import { IsNull, Not } from "typeorm"; +import { Users, Followings } from "@/models/index.js"; +import type { ILocalUser, IRemoteUser, User } from "@/models/entities/user.js"; +import { deliver } from "@/queue/index.js"; +import { skippedInstances } from "@/misc/skipped-instances.js"; //#region types interface IRecipe { @@ -10,23 +10,23 @@ interface IRecipe { } interface IFollowersRecipe extends IRecipe { - type: 'Followers'; + type: "Followers"; } interface IDirectRecipe extends IRecipe { - type: 'Direct'; + type: "Direct"; to: IRemoteUser; } const isFollowers = (recipe: any): recipe is IFollowersRecipe => - recipe.type === 'Followers'; + recipe.type === "Followers"; const isDirect = (recipe: any): recipe is IDirectRecipe => - recipe.type === 'Direct'; + recipe.type === "Direct"; //#endregion export default class DeliverManager { - private actor: { id: User['id']; host: null; }; + private actor: { id: User["id"]; host: null }; private activity: any; private recipes: IRecipe[] = []; @@ -35,7 +35,7 @@ export default class DeliverManager { * @param actor Actor * @param activity Activity to deliver */ - constructor(actor: { id: User['id']; host: null; }, activity: any) { + constructor(actor: { id: User["id"]; host: null }, activity: any) { this.actor = actor; this.activity = activity; } @@ -45,7 +45,7 @@ export default class DeliverManager { */ public addFollowersRecipe() { const deliver = { - type: 'Followers', + type: "Followers", } as IFollowersRecipe; this.addRecipe(deliver); @@ -57,7 +57,7 @@ export default class DeliverManager { */ public addDirectRecipe(to: IRemoteUser) { const recipe = { - type: 'Direct', + type: "Direct", to, } as IDirectRecipe; @@ -86,11 +86,11 @@ export default class DeliverManager { Process follower recipes first to avoid duplication when processing direct recipes later. */ - if (this.recipes.some(r => isFollowers(r))) { + if (this.recipes.some((r) => isFollowers(r))) { // followers deliver // TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう // ただ、sharedInboxがnullなリモートユーザーも稀におり、その対応ができなさそう? - const followers = await Followings.find({ + const followers = (await Followings.find({ where: { followeeId: this.actor.id, followerHost: Not(IsNull()), @@ -99,7 +99,7 @@ export default class DeliverManager { followerSharedInbox: true, followerInbox: true, }, - }) as { + })) as { followerSharedInbox: string | null; followerInbox: string; }[]; @@ -110,22 +110,23 @@ export default class DeliverManager { } } - this.recipes.filter((recipe): recipe is IDirectRecipe => - // followers recipes have already been processed - isDirect(recipe) - // check that shared inbox has not been added yet - && !(recipe.to.sharedInbox && inboxes.has(recipe.to.sharedInbox)) - // check that they actually have an inbox - && recipe.to.inbox != null, - ) - .forEach(recipe => inboxes.add(recipe.to.inbox!)); + this.recipes + .filter( + (recipe): recipe is IDirectRecipe => + // followers recipes have already been processed + isDirect(recipe) && + // check that shared inbox has not been added yet + !(recipe.to.sharedInbox && inboxes.has(recipe.to.sharedInbox)) && + // check that they actually have an inbox + recipe.to.inbox != null, + ) + .forEach((recipe) => inboxes.add(recipe.to.inbox!)); const instancesToSkip = await skippedInstances( // get (unique) list of hosts - Array.from(new Set( - Array.from(inboxes) - .map(inbox => new URL(inbox).host), - )), + Array.from( + new Set(Array.from(inboxes).map((inbox) => new URL(inbox).host)), + ), ); // deliver @@ -144,7 +145,10 @@ export default class DeliverManager { * @param activity Activity * @param from Followee */ -export async function deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) { +export async function deliverToFollowers( + actor: { id: ILocalUser["id"]; host: null }, + activity: any, +) { const manager = new DeliverManager(actor, activity); manager.addFollowersRecipe(); await manager.execute(); @@ -155,7 +159,11 @@ export async function deliverToFollowers(actor: { id: ILocalUser['id']; host: nu * @param activity Activity * @param to Target user */ -export async function deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) { +export async function deliverToUser( + actor: { id: ILocalUser["id"]; host: null }, + activity: any, + to: IRemoteUser, +) { const manager = new DeliverManager(actor, activity); manager.addDirectRecipe(to); await manager.execute(); diff --git a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts index 4350ef133..e430bbf57 100644 --- a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts @@ -1,21 +1,24 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import accept from '@/services/following/requests/accept.js'; -import { IFollow } from '../../type.js'; -import DbResolver from '../../db-resolver.js'; -import { relayAccepted } from '@/services/relay.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import accept from "@/services/following/requests/accept.js"; +import type { IFollow } from "../../type.js"; +import DbResolver from "../../db-resolver.js"; +import { relayAccepted } from "@/services/relay.js"; -export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IFollow, +): Promise => { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const dbResolver = new DbResolver(); const follower = await dbResolver.getUserFromApId(activity.actor); if (follower == null) { - return `skip: follower not found`; + return "skip: follower not found"; } if (follower.host != null) { - return `skip: follower is not a local user`; + return "skip: follower is not a local user"; } // relay @@ -25,5 +28,5 @@ export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IAccept, +): Promise => { const uri = activity.id || activity; logger.info(`Accept: ${uri}`); const resolver = new Resolver(); - const object = await resolver.resolve(activity.object).catch(e => { + const object = await resolver.resolve(activity.object).catch((e) => { logger.error(`Resolution failed: ${e}`); throw e; }); diff --git a/packages/backend/src/remote/activitypub/kernel/add/index.ts b/packages/backend/src/remote/activitypub/kernel/add/index.ts index c813414f9..b3606e5d9 100644 --- a/packages/backend/src/remote/activitypub/kernel/add/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/add/index.ts @@ -1,20 +1,23 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IAdd } from '../../type.js'; -import { resolveNote } from '../../models/note.js'; -import { addPinned } from '@/services/i/pin.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { IAdd } from "../../type.js"; +import { resolveNote } from "../../models/note.js"; +import { addPinned } from "@/services/i/pin.js"; -export default async (actor: CacheableRemoteUser, activity: IAdd): Promise => { - if ('actor' in activity && actor.uri !== activity.actor) { - throw new Error('invalid actor'); +export default async ( + actor: CacheableRemoteUser, + activity: IAdd, +): Promise => { + if ("actor" in activity && actor.uri !== activity.actor) { + throw new Error("invalid actor"); } if (activity.target == null) { - throw new Error('target is null'); + throw new Error("target is null"); } if (activity.target === actor.featured) { const note = await resolveNote(activity.object); - if (note == null) throw new Error('note not found'); + if (note == null) throw new Error("note not found"); await addPinned(actor, note.id); return; } diff --git a/packages/backend/src/remote/activitypub/kernel/announce/index.ts b/packages/backend/src/remote/activitypub/kernel/announce/index.ts index ae7e507c9..975e070f9 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/index.ts @@ -1,12 +1,16 @@ -import Resolver from '../../resolver.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import announceNote from './note.js'; -import { IAnnounce, getApId } from '../../type.js'; -import { apLogger } from '../../logger.js'; +import Resolver from "../../resolver.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import announceNote from "./note.js"; +import type { IAnnounce } from "../../type.js"; +import { getApId } from "../../type.js"; +import { apLogger } from "../../logger.js"; const logger = apLogger; -export default async (actor: CacheableRemoteUser, activity: IAnnounce): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IAnnounce, +): Promise => { const uri = getApId(activity); logger.info(`Announce: ${uri}`); diff --git a/packages/backend/src/remote/activitypub/kernel/announce/note.ts b/packages/backend/src/remote/activitypub/kernel/announce/note.ts index 759cb4ae8..6cdaa6166 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/note.ts @@ -1,63 +1,75 @@ -import Resolver from '../../resolver.js'; -import post from '@/services/note/create.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IAnnounce, getApId } from '../../type.js'; -import { fetchNote, resolveNote } from '../../models/note.js'; -import { apLogger } from '../../logger.js'; -import { extractDbHost } from '@/misc/convert-host.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { getApLock } from '@/misc/app-lock.js'; -import { parseAudience } from '../../audience.js'; -import { StatusError } from '@/misc/fetch.js'; -import { Notes } from '@/models/index.js'; +import type Resolver from "../../resolver.js"; +import post from "@/services/note/create.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { IAnnounce } from "../../type.js"; +import { getApId } from "../../type.js"; +import { fetchNote, resolveNote } from "../../models/note.js"; +import { apLogger } from "../../logger.js"; +import { extractDbHost } from "@/misc/convert-host.js"; +import { getApLock } from "@/misc/app-lock.js"; +import { parseAudience } from "../../audience.js"; +import { StatusError } from "@/misc/fetch.js"; +import { Notes } from "@/models/index.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; const logger = apLogger; /** - * アナウンスアクティビティを捌きます + * Handle announcement activities */ -export default async function(resolver: Resolver, actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise { +export default async function ( + resolver: Resolver, + actor: CacheableRemoteUser, + activity: IAnnounce, + targetUri: string, +): Promise { const uri = getApId(activity); if (actor.isSuspended) { return; } - // アナウンス先をブロックしてたら中断 - const meta = await fetchMeta(); - if (meta.blockedHosts.includes(extractDbHost(uri))) return; + // Interrupt if you block the announcement destination + if (await shouldBlockInstance(extractDbHost(uri))) return; const unlock = await getApLock(uri); try { - // 既に同じURIを持つものが登録されていないかチェック + // Check if something with the same URI is already registered const exist = await fetchNote(uri); if (exist) { return; } - // Announce対象をresolve + // Resolve Announce target let renote; try { renote = await resolveNote(targetUri); } catch (e) { - // 対象が4xxならスキップ + // Skip if target is 4xx if (e instanceof StatusError) { if (e.isClientError) { logger.warn(`Ignored announce target ${targetUri} - ${e.statusCode}`); return; } - logger.warn(`Error in announce target ${targetUri} - ${e.statusCode || e}`); + logger.warn( + `Error in announce target ${targetUri} - ${e.statusCode || e}`, + ); } throw e; } - if (!await Notes.isVisibleForMe(renote, actor.id)) return 'skip: invalid actor for this activity'; + if (!(await Notes.isVisibleForMe(renote, actor.id))) + return "skip: invalid actor for this activity"; logger.info(`Creating the (Re)Note: ${uri}`); - const activityAudience = await parseAudience(actor, activity.to, activity.cc); + const activityAudience = await parseAudience( + actor, + activity.to, + activity.cc, + ); await post(actor, { createdAt: activity.published ? new Date(activity.published) : null, diff --git a/packages/backend/src/remote/activitypub/kernel/block/index.ts b/packages/backend/src/remote/activitypub/kernel/block/index.ts index c8b60f7b9..4dc868ba1 100644 --- a/packages/backend/src/remote/activitypub/kernel/block/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/block/index.ts @@ -1,23 +1,29 @@ -import { IBlock } from '../../type.js'; -import block from '@/services/blocking/create.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import DbResolver from '../../db-resolver.js'; -import { Users } from '@/models/index.js'; +import type { IBlock } from "../../type.js"; +import block from "@/services/blocking/create.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import DbResolver from "../../db-resolver.js"; +import { Users } from "@/models/index.js"; -export default async (actor: CacheableRemoteUser, activity: IBlock): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IBlock, +): Promise => { // ※ There is a block target in activity.object, which should be a local user that exists. const dbResolver = new DbResolver(); const blockee = await dbResolver.getUserFromApId(activity.object); if (blockee == null) { - return `skip: blockee not found`; + return "skip: blockee not found"; } if (blockee.host != null) { - return `skip: The user you are trying to block is not a local user`; + return "skip: The user you are trying to block is not a local user"; } - await block(await Users.findOneByOrFail({ id: actor.id }), await Users.findOneByOrFail({ id: blockee.id })); - return `ok`; + await block( + await Users.findOneByOrFail({ id: actor.id }), + await Users.findOneByOrFail({ id: blockee.id }), + ); + return "ok"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/create/index.ts b/packages/backend/src/remote/activitypub/kernel/create/index.ts index c253f9f66..3dcf64824 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/index.ts @@ -1,21 +1,29 @@ -import Resolver from '../../resolver.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import createNote from './note.js'; -import { ICreate, getApId, isPost, getApType } from '../../type.js'; -import { apLogger } from '../../logger.js'; -import { toArray, concat, unique } from '@/prelude/array.js'; +import Resolver from "../../resolver.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import createNote from "./note.js"; +import type { ICreate } from "../../type.js"; +import { getApId, isPost, getApType } from "../../type.js"; +import { apLogger } from "../../logger.js"; +import { toArray, concat, unique } from "@/prelude/array.js"; const logger = apLogger; -export default async (actor: CacheableRemoteUser, activity: ICreate): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: ICreate, +): Promise => { const uri = getApId(activity); logger.info(`Create: ${uri}`); // copy audiences between activity <=> object. - if (typeof activity.object === 'object') { - const to = unique(concat([toArray(activity.to), toArray(activity.object.to)])); - const cc = unique(concat([toArray(activity.cc), toArray(activity.object.cc)])); + if (typeof activity.object === "object") { + const to = unique( + concat([toArray(activity.to), toArray(activity.object.to)]), + ); + const cc = unique( + concat([toArray(activity.cc), toArray(activity.object.cc)]), + ); activity.to = to; activity.cc = cc; @@ -24,13 +32,13 @@ export default async (actor: CacheableRemoteUser, activity: ICreate): Promise { + const object = await resolver.resolve(activity.object).catch((e) => { logger.error(`Resolution failed: ${e}`); throw e; }); diff --git a/packages/backend/src/remote/activitypub/kernel/create/note.ts b/packages/backend/src/remote/activitypub/kernel/create/note.ts index f8dabe06e..09c492730 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/note.ts @@ -1,25 +1,32 @@ -import Resolver from '../../resolver.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { createNote, fetchNote } from '../../models/note.js'; -import { getApId, IObject, ICreate } from '../../type.js'; -import { getApLock } from '@/misc/app-lock.js'; -import { extractDbHost } from '@/misc/convert-host.js'; -import { StatusError } from '@/misc/fetch.js'; +import type Resolver from "../../resolver.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { createNote, fetchNote } from "../../models/note.js"; +import type { IObject, ICreate } from "../../type.js"; +import { getApId } from "../../type.js"; +import { getApLock } from "@/misc/app-lock.js"; +import { extractDbHost } from "@/misc/convert-host.js"; +import { StatusError } from "@/misc/fetch.js"; /** - * 投稿作成アクティビティを捌きます + * Handle post creation activity */ -export default async function(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { +export default async function ( + resolver: Resolver, + actor: CacheableRemoteUser, + note: IObject, + silent = false, + activity?: ICreate, +): Promise { const uri = getApId(note); - if (typeof note === 'object') { + if (typeof note === "object") { if (actor.uri !== note.attributedTo) { - return `skip: actor.uri !== note.attributedTo`; + return "skip: actor.uri !== note.attributedTo"; } - if (typeof note.id === 'string') { + if (typeof note.id === "string") { if (extractDbHost(actor.uri) !== extractDbHost(note.id)) { - return `skip: host in actor.uri !== note.id`; + return "skip: host in actor.uri !== note.id"; } } } @@ -28,10 +35,10 @@ export default async function(resolver: Resolver, actor: CacheableRemoteUser, no try { const exist = await fetchNote(note); - if (exist) return 'skip: note exists'; + if (exist) return "skip: note exists"; await createNote(note, resolver, silent); - return 'ok'; + return "ok"; } catch (e) { if (e instanceof StatusError && e.isClientError) { return `skip ${e.statusCode}`; diff --git a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts index 1f94df033..3571135aa 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts @@ -1,11 +1,14 @@ -import { apLogger } from '../../logger.js'; -import { createDeleteAccountJob } from '@/queue/index.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; +import { apLogger } from "../../logger.js"; +import { createDeleteAccountJob } from "@/queue/index.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; const logger = apLogger; -export async function deleteActor(actor: CacheableRemoteUser, uri: string): Promise { +export async function deleteActor( + actor: CacheableRemoteUser, + uri: string, +): Promise { logger.info(`Deleting the Actor: ${uri}`); if (actor.uri !== uri) { @@ -14,7 +17,7 @@ export async function deleteActor(actor: CacheableRemoteUser, uri: string): Prom const user = await Users.findOneByOrFail({ id: actor.id }); if (user.isDeleted) { - logger.info(`skip: already deleted`); + logger.info("skip: already deleted"); } const job = await createDeleteAccountJob(actor); diff --git a/packages/backend/src/remote/activitypub/kernel/delete/index.ts b/packages/backend/src/remote/activitypub/kernel/delete/index.ts index c7064f553..f9ad52de5 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/index.ts @@ -1,22 +1,27 @@ -import deleteNote from './note.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type.js'; -import { toSingle } from '@/prelude/array.js'; -import { deleteActor } from './actor.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { toSingle } from "@/prelude/array.js"; +import { getApId, isTombstone, validPost, validActor } from "../../type.js"; +import deleteNote from "./note.js"; +import { deleteActor } from "./actor.js"; +import type { IDelete, IObject } from "../../type.js"; /** - * 削除アクティビティを捌きます + * Handle delete activity */ -export default async (actor: CacheableRemoteUser, activity: IDelete): Promise => { - if ('actor' in activity && actor.uri !== activity.actor) { - throw new Error('invalid actor'); +export default async ( + actor: CacheableRemoteUser, + activity: IDelete, +): Promise => { + if ("actor" in activity && actor.uri !== activity.actor) { + throw new Error("invalid actor"); } - // 削除対象objectのtype + // Type of object to be deleted let formerType: string | undefined; - if (typeof activity.object === 'string') { - // typeが不明だけど、どうせ消えてるのでremote resolveしない + if (typeof activity.object === "string") { + // The type is unknown, but it has disappeared + // anyway, so it does not remote resolve formerType = undefined; } else { const object = activity.object as IObject; @@ -29,14 +34,15 @@ export default async (actor: CacheableRemoteUser, activity: IDelete): Promise { +export default async function ( + actor: CacheableRemoteUser, + uri: string, +): Promise { logger.info(`Deleting the Note: ${uri}`); const unlock = await getApLock(uri); @@ -18,23 +21,23 @@ export default async function(actor: CacheableRemoteUser, uri: string): Promise< if (note == null) { const message = await dbResolver.getMessageFromApId(uri); - if (message == null) return 'message not found'; + if (message == null) return "message not found"; if (message.userId !== actor.id) { - return '投稿を削除しようとしているユーザーは投稿の作成者ではありません'; + return "The user trying to delete the post is not the post author"; } await deleteMessage(message); - return 'ok: message deleted'; + return "ok: message deleted"; } if (note.userId !== actor.id) { - return '投稿を削除しようとしているユーザーは投稿の作成者ではありません'; + return "The user trying to delete the post is not the post author"; } await deleteNode(actor, note); - return 'ok: note deleted'; + return "ok: note deleted"; } finally { unlock(); } diff --git a/packages/backend/src/remote/activitypub/kernel/flag/index.ts b/packages/backend/src/remote/activitypub/kernel/flag/index.ts index aa2f1f536..39ba8b3f4 100644 --- a/packages/backend/src/remote/activitypub/kernel/flag/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/flag/index.ts @@ -1,20 +1,27 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import config from '@/config/index.js'; -import { IFlag, getApIds } from '../../type.js'; -import { AbuseUserReports, Users } from '@/models/index.js'; -import { In } from 'typeorm'; -import { genId } from '@/misc/gen-id.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import config from "@/config/index.js"; +import type { IFlag } from "../../type.js"; +import { getApIds } from "../../type.js"; +import { AbuseUserReports, Users } from "@/models/index.js"; +import { In } from "typeorm"; +import { genId } from "@/misc/gen-id.js"; -export default async (actor: CacheableRemoteUser, activity: IFlag): Promise => { - // objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので - // 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する +export default async ( + actor: CacheableRemoteUser, + activity: IFlag, +): Promise => { + // The object is `(User | Note) | (User | Note) []`, but it cannot be + // matched with all patterns of the DB schema, so the target user is the first + // user and it is stored as a comment. const uris = getApIds(activity.object); - const userIds = uris.filter(uri => uri.startsWith(config.url + '/users/')).map(uri => uri.split('/').pop()!); + const userIds = uris + .filter((uri) => uri.startsWith(`${config.url}/users/`)) + .map((uri) => uri.split("/").pop()!); const users = await Users.findBy({ id: In(userIds), }); - if (users.length < 1) return `skip`; + if (users.length < 1) return "skip"; await AbuseUserReports.insert({ id: genId(), @@ -26,5 +33,5 @@ export default async (actor: CacheableRemoteUser, activity: IFlag): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IFollow, +): Promise => { const dbResolver = new DbResolver(); const followee = await dbResolver.getUserFromApId(activity.object); if (followee == null) { - return `skip: followee not found`; + return "skip: followee not found"; } if (followee.host != null) { - return `skip: フォローしようとしているユーザーはローカルユーザーではありません`; + return "skip: user you are trying to follow is not a local user"; } await follow(actor, followee, activity.id); - return `ok`; + return "ok"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/index.ts b/packages/backend/src/remote/activitypub/kernel/index.ts index b8af3dc48..58e354a51 100644 --- a/packages/backend/src/remote/activitypub/kernel/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/index.ts @@ -1,5 +1,5 @@ -import type { CacheableRemoteUser } from '@/models/entities/user.js'; -import { toArray } from '@/prelude/array.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { toArray } from "@/prelude/array.js"; import { isCreate, isDelete, @@ -18,35 +18,43 @@ import { isCollection, isFlag, isMove, -} from '../type.js'; -import { apLogger } from '../logger.js'; -import Resolver from '../resolver.js'; -import create from './create/index.js'; -import performDeleteActivity from './delete/index.js'; -import performUpdateActivity from './update/index.js'; -import { performReadActivity } from './read.js'; -import follow from './follow.js'; -import undo from './undo/index.js'; -import like from './like.js'; -import announce from './announce/index.js'; -import accept from './accept/index.js'; -import reject from './reject/index.js'; -import add from './add/index.js'; -import remove from './remove/index.js'; -import block from './block/index.js'; -import flag from './flag/index.js'; -import move from './move/index.js'; -import type { IObject } from '../type.js'; + getApId, +} from "../type.js"; +import { apLogger } from "../logger.js"; +import Resolver from "../resolver.js"; +import create from "./create/index.js"; +import performDeleteActivity from "./delete/index.js"; +import performUpdateActivity from "./update/index.js"; +import { performReadActivity } from "./read.js"; +import follow from "./follow.js"; +import undo from "./undo/index.js"; +import like from "./like.js"; +import announce from "./announce/index.js"; +import accept from "./accept/index.js"; +import reject from "./reject/index.js"; +import add from "./add/index.js"; +import remove from "./remove/index.js"; +import block from "./block/index.js"; +import flag from "./flag/index.js"; +import move from "./move/index.js"; +import type { IObject } from "../type.js"; +import { extractDbHost } from "@/misc/convert-host.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; -export async function performActivity(actor: CacheableRemoteUser, activity: IObject) { +export async function performActivity( + actor: CacheableRemoteUser, + activity: IObject, +) { if (isCollectionOrOrderedCollection(activity)) { const resolver = new Resolver(); - for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) { + for (const item of toArray( + isCollection(activity) ? activity.items : activity.orderedItems, + )) { const act = await resolver.resolve(item); try { await performOneActivity(actor, act); } catch (err) { - if (err instanceof Error || typeof err === 'string') { + if (err instanceof Error || typeof err === "string") { apLogger.error(err); } } @@ -56,9 +64,17 @@ export async function performActivity(actor: CacheableRemoteUser, activity: IObj } } -async function performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise { +async function performOneActivity( + actor: CacheableRemoteUser, + activity: IObject, +): Promise { if (actor.isSuspended) return; + if (typeof activity.id !== "undefined") { + const host = extractDbHost(getApId(activity)); + if (await shouldBlockInstance(host)) return; + } + if (isCreate(activity)) { await create(actor, activity); } else if (isDelete(activity)) { @@ -74,9 +90,9 @@ async function performOneActivity(actor: CacheableRemoteUser, activity: IObject) } else if (isReject(activity)) { await reject(actor, activity); } else if (isAdd(activity)) { - await add(actor, activity).catch(err => apLogger.error(err)); + await add(actor, activity).catch((err) => apLogger.error(err)); } else if (isRemove(activity)) { - await remove(actor, activity).catch(err => apLogger.error(err)); + await remove(actor, activity).catch((err) => apLogger.error(err)); } else if (isAnnounce(activity)) { await announce(actor, activity); } else if (isLike(activity)) { @@ -88,7 +104,7 @@ async function performOneActivity(actor: CacheableRemoteUser, activity: IObject) } else if (isFlag(activity)) { await flag(actor, activity); } else if (isMove(activity)) { - await move(actor,activity); + await move(actor, activity); } else { apLogger.warn(`unrecognized activity type: ${(activity as any).type}`); } diff --git a/packages/backend/src/remote/activitypub/kernel/like.ts b/packages/backend/src/remote/activitypub/kernel/like.ts index 2b65ff738..7b30d1cd5 100644 --- a/packages/backend/src/remote/activitypub/kernel/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/like.ts @@ -1,7 +1,8 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { ILike, getApId } from '../type.js'; -import create from '@/services/note/reaction/create.js'; -import { fetchNote, extractEmojis } from '../models/note.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { ILike } from "../type.js"; +import { getApId } from "../type.js"; +import create from "@/services/note/reaction/create.js"; +import { fetchNote, extractEmojis } from "../models/note.js"; export default async (actor: CacheableRemoteUser, activity: ILike) => { const targetUri = getApId(activity.object); @@ -11,11 +12,17 @@ export default async (actor: CacheableRemoteUser, activity: ILike) => { await extractEmojis(activity.tag || [], actor.host).catch(() => null); - return await create(actor, note, activity._misskey_reaction || activity.content || activity.name).catch(e => { - if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') { - return 'skip: already reacted'; - } else { - throw e; - } - }).then(() => 'ok'); + return await create( + actor, + note, + activity._misskey_reaction || activity.content || activity.name, + ) + .catch((e) => { + if (e.id === "51c42bb4-931a-456b-bff7-e5a8a70dd298") { + return "skip: already reacted"; + } else { + throw e; + } + }) + .then(() => "ok"); }; diff --git a/packages/backend/src/remote/activitypub/kernel/move/index.ts b/packages/backend/src/remote/activitypub/kernel/move/index.ts index 660e106c0..47a55b8ab 100644 --- a/packages/backend/src/remote/activitypub/kernel/move/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/move/index.ts @@ -1,56 +1,69 @@ -import type { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IRemoteUser, User } from '@/models/entities/user.js'; -import DbResolver from '@/remote/activitypub/db-resolver.js'; -import { getRemoteUser } from '@/server/api/common/getters.js'; -import { updatePerson } from '@/remote/activitypub/models/person.js'; -import { Followings, Users } from '@/models/index.js'; -import { makePaginationQuery } from '@/server/api/common/make-pagination-query.js'; -import deleteFollowing from '@/services/following/delete.js'; -import create from '@/services/following/create.js'; -import { getUser } from '@/server/api/common/getters.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { ApiError } from '@/server/api/error.js'; -import { meta } from '@/server/api/endpoints/following/create.js'; -import { IObject, IActor } from '../../type.js'; -import type { IMove } from '../../type.js'; -import Resolver from '@/remote/activitypub/resolver.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { IRemoteUser, User } from "@/models/entities/user.js"; +import DbResolver from "@/remote/activitypub/db-resolver.js"; +import { getRemoteUser } from "@/server/api/common/getters.js"; +import { updatePerson } from "@/remote/activitypub/models/person.js"; +import { Followings, Users } from "@/models/index.js"; +import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; +import deleteFollowing from "@/services/following/delete.js"; +import create from "@/services/following/create.js"; +import { getUser } from "@/server/api/common/getters.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import { ApiError } from "@/server/api/error.js"; +import { meta } from "@/server/api/endpoints/following/create.js"; +import { IObject } from "../../type.js"; +import type { IMove, IActor } from "../../type.js"; +import Resolver from "@/remote/activitypub/resolver.js"; -export default async (actor: CacheableRemoteUser, activity: IMove): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IMove, +): Promise => { // ※ There is a block target in activity.object, which should be a local user that exists. const dbResolver = new DbResolver(); const resolver = new Resolver(); let new_acc = await dbResolver.getUserFromApId(activity.target); let actor_new; - if (!new_acc) actor_new = await resolver.resolve(activity.target) as IActor; + if (!new_acc) + actor_new = (await resolver.resolve(activity.target)) as IActor; - if ((!new_acc || new_acc.uri === null) && (!actor_new || actor_new.id === null)) { - return 'move: new acc not found'; + if ( + (!new_acc || new_acc.uri === null) && + (!actor_new || actor_new.id === null) + ) { + return "move: new acc not found"; } - let newUri: string | null | undefined - newUri = new_acc ? new_acc.uri : - actor_new?.url?.toString(); + const newUri = new_acc ? new_acc.uri : actor_new?.url?.toString(); - if(newUri === null || newUri === undefined) return 'move: new acc not found #2'; + if (newUri === null || newUri === undefined) + return "move: new acc not found #2"; await updatePerson(newUri); await updatePerson(actor.uri!); new_acc = await dbResolver.getUserFromApId(newUri); - let old = await dbResolver.getUserFromApId(actor.uri!); + const old = await dbResolver.getUserFromApId(actor.uri!); - if (old === null || old.uri === null || !new_acc?.alsoKnownAs?.includes(old.uri)) return 'move: accounts invalid'; + if ( + old === null || + old.uri === null || + !new_acc?.alsoKnownAs?.includes(old.uri) + ) + return "move: accounts invalid"; old.movedToUri = new_acc.uri; - const followee = await getUser(actor.id).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const followee = await getUser(actor.id).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); - const followeeNew = await getUser(new_acc.id).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const followeeNew = await getUser(new_acc.id).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -58,19 +71,22 @@ export default async (actor: CacheableRemoteUser, activity: IMove): Promise { + followings.forEach(async (following) => { //if follower is local if (!following.followerHost) { - const follower = await getUser(following.followerId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const follower = await getUser(following.followerId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); await deleteFollowing(follower!, followee); try { await create(follower!, followeeNew); - } catch (e) { /* empty */ } + } catch (e) { + /* empty */ + } } }); - return 'ok'; + return "ok"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/read.ts b/packages/backend/src/remote/activitypub/kernel/read.ts index f7b0bcecd..7cc70976c 100644 --- a/packages/backend/src/remote/activitypub/kernel/read.ts +++ b/packages/backend/src/remote/activitypub/kernel/read.ts @@ -1,27 +1,33 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IRead, getApId } from '../type.js'; -import { isSelfHost, extractDbHost } from '@/misc/convert-host.js'; -import { MessagingMessages } from '@/models/index.js'; -import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { IRead } from "../type.js"; +import { getApId } from "../type.js"; +import { isSelfHost, extractDbHost } from "@/misc/convert-host.js"; +import { MessagingMessages } from "@/models/index.js"; +import { readUserMessagingMessage } from "../../../server/api/common/read-messaging-message.js"; -export const performReadActivity = async (actor: CacheableRemoteUser, activity: IRead): Promise => { +export const performReadActivity = async ( + actor: CacheableRemoteUser, + activity: IRead, +): Promise => { const id = await getApId(activity.object); if (!isSelfHost(extractDbHost(id))) { return `skip: Read to foreign host (${id})`; } - const messageId = id.split('/').pop(); + const messageId = id.split("/").pop(); const message = await MessagingMessages.findOneBy({ id: messageId }); if (message == null) { - return `skip: message not found`; + return "skip: message not found"; } if (actor.id !== message.recipientId) { - return `skip: actor is not a message recipient`; + return "skip: actor is not a message recipient"; } - await readUserMessagingMessage(message.recipientId!, message.userId, [message.id]); + await readUserMessagingMessage(message.recipientId!, message.userId, [ + message.id, + ]); return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`; }; diff --git a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts index 824ac69d7..670c1556f 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts @@ -1,22 +1,25 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { remoteReject } from '@/services/following/reject.js'; -import { IFollow } from '../../type.js'; -import DbResolver from '../../db-resolver.js'; -import { relayRejected } from '@/services/relay.js'; -import { Users } from '@/models/index.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { remoteReject } from "@/services/following/reject.js"; +import type { IFollow } from "../../type.js"; +import DbResolver from "../../db-resolver.js"; +import { relayRejected } from "@/services/relay.js"; +import { Users } from "@/models/index.js"; -export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { - // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある +export default async ( + actor: CacheableRemoteUser, + activity: IFollow, +): Promise => { + // ※ `activity.actor` must be an existing local user, since `activity` is a follow request thrown from us. const dbResolver = new DbResolver(); const follower = await dbResolver.getUserFromApId(activity.actor); if (follower == null) { - return `skip: follower not found`; + return "skip: follower not found"; } if (!Users.isLocalUser(follower)) { - return `skip: follower is not a local user`; + return "skip: follower is not a local user"; } // relay @@ -26,5 +29,5 @@ export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IReject, +): Promise => { const uri = activity.id || activity; logger.info(`Reject: ${uri}`); const resolver = new Resolver(); - const object = await resolver.resolve(activity.object).catch(e => { + const object = await resolver.resolve(activity.object).catch((e) => { logger.error(`Resolution failed: ${e}`); throw e; }); diff --git a/packages/backend/src/remote/activitypub/kernel/remove/index.ts b/packages/backend/src/remote/activitypub/kernel/remove/index.ts index 11a994a83..0b4be6b5f 100644 --- a/packages/backend/src/remote/activitypub/kernel/remove/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/remove/index.ts @@ -1,20 +1,23 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { IRemove } from '../../type.js'; -import { resolveNote } from '../../models/note.js'; -import { removePinned } from '@/services/i/pin.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { IRemove } from "../../type.js"; +import { resolveNote } from "../../models/note.js"; +import { removePinned } from "@/services/i/pin.js"; -export default async (actor: CacheableRemoteUser, activity: IRemove): Promise => { - if ('actor' in activity && actor.uri !== activity.actor) { - throw new Error('invalid actor'); +export default async ( + actor: CacheableRemoteUser, + activity: IRemove, +): Promise => { + if ("actor" in activity && actor.uri !== activity.actor) { + throw new Error("invalid actor"); } if (activity.target == null) { - throw new Error('target is null'); + throw new Error("target is null"); } if (activity.target === actor.featured) { const note = await resolveNote(activity.object); - if (note == null) throw new Error('note not found'); + if (note == null) throw new Error("note not found"); await removePinned(actor, note.id); return; } diff --git a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts index a6e3929b0..2cd05a77d 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts @@ -1,16 +1,19 @@ -import unfollow from '@/services/following/delete.js'; -import cancelRequest from '@/services/following/requests/cancel.js'; -import { IAccept } from '../../type.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { Followings } from '@/models/index.js'; -import DbResolver from '../../db-resolver.js'; +import unfollow from "@/services/following/delete.js"; +import cancelRequest from "@/services/following/requests/cancel.js"; +import type { IAccept } from "../../type.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { Followings } from "@/models/index.js"; +import DbResolver from "../../db-resolver.js"; -export default async (actor: CacheableRemoteUser, activity: IAccept): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IAccept, +): Promise => { const dbResolver = new DbResolver(); const follower = await dbResolver.getUserFromApId(activity.object); if (follower == null) { - return `skip: follower not found`; + return "skip: follower not found"; } const following = await Followings.findOneBy({ @@ -20,8 +23,8 @@ export default async (actor: CacheableRemoteUser, activity: IAccept): Promise => { +export const undoAnnounce = async ( + actor: CacheableRemoteUser, + activity: IAnnounce, +): Promise => { const uri = getApId(activity); const note = await Notes.findOneBy({ @@ -11,8 +15,8 @@ export const undoAnnounce = async (actor: CacheableRemoteUser, activity: IAnnoun userId: actor.id, }); - if (!note) return 'skip: no such Announce'; + if (!note) return "skip: no such Announce"; await deleteNote(actor, note); - return 'ok: deleted'; + return "ok: deleted"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/block.ts b/packages/backend/src/remote/activitypub/kernel/undo/block.ts index 4ac669857..b4e1d8ee4 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/block.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/block.ts @@ -1,21 +1,24 @@ -import { IBlock } from '../../type.js'; -import unblock from '@/services/blocking/delete.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import DbResolver from '../../db-resolver.js'; -import { Users } from '@/models/index.js'; +import type { IBlock } from "../../type.js"; +import unblock from "@/services/blocking/delete.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import DbResolver from "../../db-resolver.js"; +import { Users } from "@/models/index.js"; -export default async (actor: CacheableRemoteUser, activity: IBlock): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IBlock, +): Promise => { const dbResolver = new DbResolver(); const blockee = await dbResolver.getUserFromApId(activity.object); if (blockee == null) { - return `skip: blockee not found`; + return "skip: blockee not found"; } if (blockee.host != null) { - return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`; + return "skip: The user you are trying to unblock is not a local user"; } await unblock(await Users.findOneByOrFail({ id: actor.id }), blockee); - return `ok`; + return "ok"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts index 6a43c1444..1c4648cf9 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts @@ -1,20 +1,23 @@ -import unfollow from '@/services/following/delete.js'; -import cancelRequest from '@/services/following/requests/cancel.js'; -import { IFollow } from '../../type.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { FollowRequests, Followings } from '@/models/index.js'; -import DbResolver from '../../db-resolver.js'; +import unfollow from "@/services/following/delete.js"; +import cancelRequest from "@/services/following/requests/cancel.js"; +import type { IFollow } from "../../type.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { FollowRequests, Followings } from "@/models/index.js"; +import DbResolver from "../../db-resolver.js"; -export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IFollow, +): Promise => { const dbResolver = new DbResolver(); const followee = await dbResolver.getUserFromApId(activity.object); if (followee == null) { - return `skip: followee not found`; + return "skip: followee not found"; } if (followee.host != null) { - return `skip: フォロー解除しようとしているユーザーはローカルユーザーではありません`; + return "skip: The user you are trying to unfollow is not a local user"; } const req = await FollowRequests.findOneBy({ @@ -29,13 +32,13 @@ export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { - if ('actor' in activity && actor.uri !== activity.actor) { - throw new Error('invalid actor'); +export default async ( + actor: CacheableRemoteUser, + activity: IUndo, +): Promise => { + if ("actor" in activity && actor.uri !== activity.actor) { + throw new Error("invalid actor"); } const uri = activity.id || activity; @@ -21,7 +32,7 @@ export default async (actor: CacheableRemoteUser, activity: IUndo): Promise { + const object = await resolver.resolve(activity.object).catch((e) => { logger.error(`Resolution failed: ${e}`); throw e; }); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/like.ts b/packages/backend/src/remote/activitypub/kernel/undo/like.ts index 01aeba1fb..90220e203 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/like.ts @@ -1,7 +1,8 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { ILike, getApId } from '../../type.js'; -import deleteReaction from '@/services/note/reaction/delete.js'; -import { fetchNote } from '../../models/note.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { ILike } from "../../type.js"; +import { getApId } from "../../type.js"; +import deleteReaction from "@/services/note/reaction/delete.js"; +import { fetchNote } from "../../models/note.js"; /** * Process Undo.Like activity @@ -12,10 +13,10 @@ export default async (actor: CacheableRemoteUser, activity: ILike) => { const note = await fetchNote(targetUri); if (!note) return `skip: target note not found ${targetUri}`; - await deleteReaction(actor, note).catch(e => { - if (e.id === '60527ec9-b4cb-4a88-a6bd-32d3ad26817d') return; + await deleteReaction(actor, note).catch((e) => { + if (e.id === "60527ec9-b4cb-4a88-a6bd-32d3ad26817d") return; throw e; }); - return `ok`; + return "ok"; }; diff --git a/packages/backend/src/remote/activitypub/kernel/update/index.ts b/packages/backend/src/remote/activitypub/kernel/update/index.ts index 022be0ad8..4f1514ddd 100644 --- a/packages/backend/src/remote/activitypub/kernel/update/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/update/index.ts @@ -1,33 +1,37 @@ -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { getApType, IUpdate, isActor } from '../../type.js'; -import { apLogger } from '../../logger.js'; -import { updateQuestion } from '../../models/question.js'; -import Resolver from '../../resolver.js'; -import { updatePerson } from '../../models/person.js'; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import type { IUpdate } from "../../type.js"; +import { getApType, isActor } from "../../type.js"; +import { apLogger } from "../../logger.js"; +import { updateQuestion } from "../../models/question.js"; +import Resolver from "../../resolver.js"; +import { updatePerson } from "../../models/person.js"; /** - * Updateアクティビティを捌きます + * Handler for the Update activity */ -export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise => { - if ('actor' in activity && actor.uri !== activity.actor) { - return `skip: invalid actor`; +export default async ( + actor: CacheableRemoteUser, + activity: IUpdate, +): Promise => { + if ("actor" in activity && actor.uri !== activity.actor) { + return "skip: invalid actor"; } - apLogger.debug('Update'); + apLogger.debug("Update"); const resolver = new Resolver(); - const object = await resolver.resolve(activity.object).catch(e => { + const object = await resolver.resolve(activity.object).catch((e) => { apLogger.error(`Resolution failed: ${e}`); throw e; }); if (isActor(object)) { await updatePerson(actor.uri!, resolver, object); - return `ok: Person updated`; - } else if (getApType(object) === 'Question') { - await updateQuestion(object, resolver).catch(e => console.log(e)); - return `ok: Question updated`; + return "ok: Person updated"; + } else if (getApType(object) === "Question") { + await updateQuestion(object, resolver).catch((e) => console.log(e)); + return "ok: Question updated"; } else { return `skip: Unknown type: ${getApType(object)}`; } diff --git a/packages/backend/src/remote/activitypub/logger.ts b/packages/backend/src/remote/activitypub/logger.ts index cab51b3bf..47383cf7f 100644 --- a/packages/backend/src/remote/activitypub/logger.ts +++ b/packages/backend/src/remote/activitypub/logger.ts @@ -1,3 +1,3 @@ -import { remoteLogger } from '../logger.js'; +import { remoteLogger } from "../logger.js"; -export const apLogger = remoteLogger.createSubLogger('ap', 'magenta'); +export const apLogger = remoteLogger.createSubLogger("ap", "magenta"); diff --git a/packages/backend/src/remote/activitypub/misc/contexts.ts b/packages/backend/src/remote/activitypub/misc/contexts.ts index aee0d3629..8c97b5972 100644 --- a/packages/backend/src/remote/activitypub/misc/contexts.ts +++ b/packages/backend/src/remote/activitypub/misc/contexts.ts @@ -1,526 +1,525 @@ -/* eslint:disable:quotemark indent */ const id_v1 = { - '@context': { - 'id': '@id', - 'type': '@type', + "@context": { + id: "@id", + type: "@type", - 'cred': 'https://w3id.org/credentials#', - 'dc': 'http://purl.org/dc/terms/', - 'identity': 'https://w3id.org/identity#', - 'perm': 'https://w3id.org/permissions#', - 'ps': 'https://w3id.org/payswarm#', - 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - 'rdfs': 'http://www.w3.org/2000/01/rdf-schema#', - 'sec': 'https://w3id.org/security#', - 'schema': 'http://schema.org/', - 'xsd': 'http://www.w3.org/2001/XMLSchema#', + cred: "https://w3id.org/credentials#", + dc: "http://purl.org/dc/terms/", + identity: "https://w3id.org/identity#", + perm: "https://w3id.org/permissions#", + ps: "https://w3id.org/payswarm#", + rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + rdfs: "http://www.w3.org/2000/01/rdf-schema#", + sec: "https://w3id.org/security#", + schema: "http://schema.org/", + xsd: "http://www.w3.org/2001/XMLSchema#", - 'Group': 'https://www.w3.org/ns/activitystreams#Group', + Group: "https://www.w3.org/ns/activitystreams#Group", - 'claim': { '@id': 'cred:claim', '@type': '@id' }, - 'credential': { '@id': 'cred:credential', '@type': '@id' }, - 'issued': { '@id': 'cred:issued', '@type': 'xsd:dateTime' }, - 'issuer': { '@id': 'cred:issuer', '@type': '@id' }, - 'recipient': { '@id': 'cred:recipient', '@type': '@id' }, - 'Credential': 'cred:Credential', - 'CryptographicKeyCredential': 'cred:CryptographicKeyCredential', + claim: { "@id": "cred:claim", "@type": "@id" }, + credential: { "@id": "cred:credential", "@type": "@id" }, + issued: { "@id": "cred:issued", "@type": "xsd:dateTime" }, + issuer: { "@id": "cred:issuer", "@type": "@id" }, + recipient: { "@id": "cred:recipient", "@type": "@id" }, + Credential: "cred:Credential", + CryptographicKeyCredential: "cred:CryptographicKeyCredential", - 'about': { '@id': 'schema:about', '@type': '@id' }, - 'address': { '@id': 'schema:address', '@type': '@id' }, - 'addressCountry': 'schema:addressCountry', - 'addressLocality': 'schema:addressLocality', - 'addressRegion': 'schema:addressRegion', - 'comment': 'rdfs:comment', - 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, - 'creator': { '@id': 'dc:creator', '@type': '@id' }, - 'description': 'schema:description', - 'email': 'schema:email', - 'familyName': 'schema:familyName', - 'givenName': 'schema:givenName', - 'image': { '@id': 'schema:image', '@type': '@id' }, - 'label': 'rdfs:label', - 'name': 'schema:name', - 'postalCode': 'schema:postalCode', - 'streetAddress': 'schema:streetAddress', - 'title': 'dc:title', - 'url': { '@id': 'schema:url', '@type': '@id' }, - 'Person': 'schema:Person', - 'PostalAddress': 'schema:PostalAddress', - 'Organization': 'schema:Organization', + about: { "@id": "schema:about", "@type": "@id" }, + address: { "@id": "schema:address", "@type": "@id" }, + addressCountry: "schema:addressCountry", + addressLocality: "schema:addressLocality", + addressRegion: "schema:addressRegion", + comment: "rdfs:comment", + created: { "@id": "dc:created", "@type": "xsd:dateTime" }, + creator: { "@id": "dc:creator", "@type": "@id" }, + description: "schema:description", + email: "schema:email", + familyName: "schema:familyName", + givenName: "schema:givenName", + image: { "@id": "schema:image", "@type": "@id" }, + label: "rdfs:label", + name: "schema:name", + postalCode: "schema:postalCode", + streetAddress: "schema:streetAddress", + title: "dc:title", + url: { "@id": "schema:url", "@type": "@id" }, + Person: "schema:Person", + PostalAddress: "schema:PostalAddress", + Organization: "schema:Organization", - 'identityService': { '@id': 'identity:identityService', '@type': '@id' }, - 'idp': { '@id': 'identity:idp', '@type': '@id' }, - 'Identity': 'identity:Identity', + identityService: { "@id": "identity:identityService", "@type": "@id" }, + idp: { "@id": "identity:idp", "@type": "@id" }, + Identity: "identity:Identity", - 'paymentProcessor': 'ps:processor', - 'preferences': { '@id': 'ps:preferences', '@type': '@vocab' }, + paymentProcessor: "ps:processor", + preferences: { "@id": "ps:preferences", "@type": "@vocab" }, - 'cipherAlgorithm': 'sec:cipherAlgorithm', - 'cipherData': 'sec:cipherData', - 'cipherKey': 'sec:cipherKey', - 'digestAlgorithm': 'sec:digestAlgorithm', - 'digestValue': 'sec:digestValue', - 'domain': 'sec:domain', - 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, - 'initializationVector': 'sec:initializationVector', - 'member': { '@id': 'schema:member', '@type': '@id' }, - 'memberOf': { '@id': 'schema:memberOf', '@type': '@id' }, - 'nonce': 'sec:nonce', - 'normalizationAlgorithm': 'sec:normalizationAlgorithm', - 'owner': { '@id': 'sec:owner', '@type': '@id' }, - 'password': 'sec:password', - 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, - 'privateKeyPem': 'sec:privateKeyPem', - 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, - 'publicKeyPem': 'sec:publicKeyPem', - 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, - 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, - 'signature': 'sec:signature', - 'signatureAlgorithm': 'sec:signatureAlgorithm', - 'signatureValue': 'sec:signatureValue', - 'CryptographicKey': 'sec:Key', - 'EncryptedMessage': 'sec:EncryptedMessage', - 'GraphSignature2012': 'sec:GraphSignature2012', - 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', + cipherAlgorithm: "sec:cipherAlgorithm", + cipherData: "sec:cipherData", + cipherKey: "sec:cipherKey", + digestAlgorithm: "sec:digestAlgorithm", + digestValue: "sec:digestValue", + domain: "sec:domain", + expires: { "@id": "sec:expiration", "@type": "xsd:dateTime" }, + initializationVector: "sec:initializationVector", + member: { "@id": "schema:member", "@type": "@id" }, + memberOf: { "@id": "schema:memberOf", "@type": "@id" }, + nonce: "sec:nonce", + normalizationAlgorithm: "sec:normalizationAlgorithm", + owner: { "@id": "sec:owner", "@type": "@id" }, + password: "sec:password", + privateKey: { "@id": "sec:privateKey", "@type": "@id" }, + privateKeyPem: "sec:privateKeyPem", + publicKey: { "@id": "sec:publicKey", "@type": "@id" }, + publicKeyPem: "sec:publicKeyPem", + publicKeyService: { "@id": "sec:publicKeyService", "@type": "@id" }, + revoked: { "@id": "sec:revoked", "@type": "xsd:dateTime" }, + signature: "sec:signature", + signatureAlgorithm: "sec:signatureAlgorithm", + signatureValue: "sec:signatureValue", + CryptographicKey: "sec:Key", + EncryptedMessage: "sec:EncryptedMessage", + GraphSignature2012: "sec:GraphSignature2012", + LinkedDataSignature2015: "sec:LinkedDataSignature2015", - 'accessControl': { '@id': 'perm:accessControl', '@type': '@id' }, - 'writePermission': { '@id': 'perm:writePermission', '@type': '@id' }, + accessControl: { "@id": "perm:accessControl", "@type": "@id" }, + writePermission: { "@id": "perm:writePermission", "@type": "@id" }, }, }; const security_v1 = { - '@context': { - 'id': '@id', - 'type': '@type', + "@context": { + id: "@id", + type: "@type", - 'dc': 'http://purl.org/dc/terms/', - 'sec': 'https://w3id.org/security#', - 'xsd': 'http://www.w3.org/2001/XMLSchema#', + dc: "http://purl.org/dc/terms/", + sec: "https://w3id.org/security#", + xsd: "http://www.w3.org/2001/XMLSchema#", - 'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016', - 'Ed25519Signature2018': 'sec:Ed25519Signature2018', - 'EncryptedMessage': 'sec:EncryptedMessage', - 'GraphSignature2012': 'sec:GraphSignature2012', - 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', - 'LinkedDataSignature2016': 'sec:LinkedDataSignature2016', - 'CryptographicKey': 'sec:Key', + EcdsaKoblitzSignature2016: "sec:EcdsaKoblitzSignature2016", + Ed25519Signature2018: "sec:Ed25519Signature2018", + EncryptedMessage: "sec:EncryptedMessage", + GraphSignature2012: "sec:GraphSignature2012", + LinkedDataSignature2015: "sec:LinkedDataSignature2015", + LinkedDataSignature2016: "sec:LinkedDataSignature2016", + CryptographicKey: "sec:Key", - 'authenticationTag': 'sec:authenticationTag', - 'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm', - 'cipherAlgorithm': 'sec:cipherAlgorithm', - 'cipherData': 'sec:cipherData', - 'cipherKey': 'sec:cipherKey', - 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, - 'creator': { '@id': 'dc:creator', '@type': '@id' }, - 'digestAlgorithm': 'sec:digestAlgorithm', - 'digestValue': 'sec:digestValue', - 'domain': 'sec:domain', - 'encryptionKey': 'sec:encryptionKey', - 'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, - 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, - 'initializationVector': 'sec:initializationVector', - 'iterationCount': 'sec:iterationCount', - 'nonce': 'sec:nonce', - 'normalizationAlgorithm': 'sec:normalizationAlgorithm', - 'owner': { '@id': 'sec:owner', '@type': '@id' }, - 'password': 'sec:password', - 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, - 'privateKeyPem': 'sec:privateKeyPem', - 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, - 'publicKeyBase58': 'sec:publicKeyBase58', - 'publicKeyPem': 'sec:publicKeyPem', - 'publicKeyWif': 'sec:publicKeyWif', - 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, - 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, - 'salt': 'sec:salt', - 'signature': 'sec:signature', - 'signatureAlgorithm': 'sec:signingAlgorithm', - 'signatureValue': 'sec:signatureValue', + authenticationTag: "sec:authenticationTag", + canonicalizationAlgorithm: "sec:canonicalizationAlgorithm", + cipherAlgorithm: "sec:cipherAlgorithm", + cipherData: "sec:cipherData", + cipherKey: "sec:cipherKey", + created: { "@id": "dc:created", "@type": "xsd:dateTime" }, + creator: { "@id": "dc:creator", "@type": "@id" }, + digestAlgorithm: "sec:digestAlgorithm", + digestValue: "sec:digestValue", + domain: "sec:domain", + encryptionKey: "sec:encryptionKey", + expiration: { "@id": "sec:expiration", "@type": "xsd:dateTime" }, + expires: { "@id": "sec:expiration", "@type": "xsd:dateTime" }, + initializationVector: "sec:initializationVector", + iterationCount: "sec:iterationCount", + nonce: "sec:nonce", + normalizationAlgorithm: "sec:normalizationAlgorithm", + owner: { "@id": "sec:owner", "@type": "@id" }, + password: "sec:password", + privateKey: { "@id": "sec:privateKey", "@type": "@id" }, + privateKeyPem: "sec:privateKeyPem", + publicKey: { "@id": "sec:publicKey", "@type": "@id" }, + publicKeyBase58: "sec:publicKeyBase58", + publicKeyPem: "sec:publicKeyPem", + publicKeyWif: "sec:publicKeyWif", + publicKeyService: { "@id": "sec:publicKeyService", "@type": "@id" }, + revoked: { "@id": "sec:revoked", "@type": "xsd:dateTime" }, + salt: "sec:salt", + signature: "sec:signature", + signatureAlgorithm: "sec:signingAlgorithm", + signatureValue: "sec:signatureValue", }, }; const activitystreams = { - '@context': { - '@vocab': '_:', - 'xsd': 'http://www.w3.org/2001/XMLSchema#', - 'as': 'https://www.w3.org/ns/activitystreams#', - 'ldp': 'http://www.w3.org/ns/ldp#', - 'vcard': 'http://www.w3.org/2006/vcard/ns#', - 'id': '@id', - 'type': '@type', - 'Accept': 'as:Accept', - 'Activity': 'as:Activity', - 'IntransitiveActivity': 'as:IntransitiveActivity', - 'Add': 'as:Add', - 'Announce': 'as:Announce', - 'Application': 'as:Application', - 'Arrive': 'as:Arrive', - 'Article': 'as:Article', - 'Audio': 'as:Audio', - 'Block': 'as:Block', - 'Collection': 'as:Collection', - 'CollectionPage': 'as:CollectionPage', - 'Relationship': 'as:Relationship', - 'Create': 'as:Create', - 'Delete': 'as:Delete', - 'Dislike': 'as:Dislike', - 'Document': 'as:Document', - 'Event': 'as:Event', - 'Follow': 'as:Follow', - 'Flag': 'as:Flag', - 'Group': 'as:Group', - 'Ignore': 'as:Ignore', - 'Image': 'as:Image', - 'Invite': 'as:Invite', - 'Join': 'as:Join', - 'Leave': 'as:Leave', - 'Like': 'as:Like', - 'Link': 'as:Link', - 'Mention': 'as:Mention', - 'Note': 'as:Note', - 'Object': 'as:Object', - 'Offer': 'as:Offer', - 'OrderedCollection': 'as:OrderedCollection', - 'OrderedCollectionPage': 'as:OrderedCollectionPage', - 'Organization': 'as:Organization', - 'Page': 'as:Page', - 'Person': 'as:Person', - 'Place': 'as:Place', - 'Profile': 'as:Profile', - 'Question': 'as:Question', - 'Reject': 'as:Reject', - 'Remove': 'as:Remove', - 'Service': 'as:Service', - 'TentativeAccept': 'as:TentativeAccept', - 'TentativeReject': 'as:TentativeReject', - 'Tombstone': 'as:Tombstone', - 'Undo': 'as:Undo', - 'Update': 'as:Update', - 'Video': 'as:Video', - 'View': 'as:View', - 'Listen': 'as:Listen', - 'Read': 'as:Read', - 'Move': 'as:Move', - 'Travel': 'as:Travel', - 'IsFollowing': 'as:IsFollowing', - 'IsFollowedBy': 'as:IsFollowedBy', - 'IsContact': 'as:IsContact', - 'IsMember': 'as:IsMember', - 'subject': { - '@id': 'as:subject', - '@type': '@id', - }, - 'relationship': { - '@id': 'as:relationship', - '@type': '@id', - }, - 'actor': { - '@id': 'as:actor', - '@type': '@id', - }, - 'attributedTo': { - '@id': 'as:attributedTo', - '@type': '@id', - }, - 'attachment': { - '@id': 'as:attachment', - '@type': '@id', - }, - 'bcc': { - '@id': 'as:bcc', - '@type': '@id', - }, - 'bto': { - '@id': 'as:bto', - '@type': '@id', - }, - 'cc': { - '@id': 'as:cc', - '@type': '@id', - }, - 'context': { - '@id': 'as:context', - '@type': '@id', - }, - 'current': { - '@id': 'as:current', - '@type': '@id', - }, - 'first': { - '@id': 'as:first', - '@type': '@id', - }, - 'generator': { - '@id': 'as:generator', - '@type': '@id', - }, - 'icon': { - '@id': 'as:icon', - '@type': '@id', - }, - 'image': { - '@id': 'as:image', - '@type': '@id', - }, - 'inReplyTo': { - '@id': 'as:inReplyTo', - '@type': '@id', - }, - 'items': { - '@id': 'as:items', - '@type': '@id', - }, - 'instrument': { - '@id': 'as:instrument', - '@type': '@id', - }, - 'orderedItems': { - '@id': 'as:items', - '@type': '@id', - '@container': '@list', - }, - 'last': { - '@id': 'as:last', - '@type': '@id', - }, - 'location': { - '@id': 'as:location', - '@type': '@id', - }, - 'next': { - '@id': 'as:next', - '@type': '@id', - }, - 'object': { - '@id': 'as:object', - '@type': '@id', - }, - 'oneOf': { - '@id': 'as:oneOf', - '@type': '@id', - }, - 'anyOf': { - '@id': 'as:anyOf', - '@type': '@id', - }, - 'closed': { - '@id': 'as:closed', - '@type': 'xsd:dateTime', - }, - 'origin': { - '@id': 'as:origin', - '@type': '@id', - }, - 'accuracy': { - '@id': 'as:accuracy', - '@type': 'xsd:float', - }, - 'prev': { - '@id': 'as:prev', - '@type': '@id', - }, - 'preview': { - '@id': 'as:preview', - '@type': '@id', - }, - 'replies': { - '@id': 'as:replies', - '@type': '@id', - }, - 'result': { - '@id': 'as:result', - '@type': '@id', - }, - 'audience': { - '@id': 'as:audience', - '@type': '@id', - }, - 'partOf': { - '@id': 'as:partOf', - '@type': '@id', - }, - 'tag': { - '@id': 'as:tag', - '@type': '@id', - }, - 'target': { - '@id': 'as:target', - '@type': '@id', - }, - 'to': { - '@id': 'as:to', - '@type': '@id', - }, - 'url': { - '@id': 'as:url', - '@type': '@id', - }, - 'altitude': { - '@id': 'as:altitude', - '@type': 'xsd:float', - }, - 'content': 'as:content', - 'contentMap': { - '@id': 'as:content', - '@container': '@language', - }, - 'name': 'as:name', - 'nameMap': { - '@id': 'as:name', - '@container': '@language', - }, - 'duration': { - '@id': 'as:duration', - '@type': 'xsd:duration', - }, - 'endTime': { - '@id': 'as:endTime', - '@type': 'xsd:dateTime', - }, - 'height': { - '@id': 'as:height', - '@type': 'xsd:nonNegativeInteger', - }, - 'href': { - '@id': 'as:href', - '@type': '@id', - }, - 'hreflang': 'as:hreflang', - 'latitude': { - '@id': 'as:latitude', - '@type': 'xsd:float', - }, - 'longitude': { - '@id': 'as:longitude', - '@type': 'xsd:float', - }, - 'mediaType': 'as:mediaType', - 'published': { - '@id': 'as:published', - '@type': 'xsd:dateTime', - }, - 'radius': { - '@id': 'as:radius', - '@type': 'xsd:float', - }, - 'rel': 'as:rel', - 'startIndex': { - '@id': 'as:startIndex', - '@type': 'xsd:nonNegativeInteger', - }, - 'startTime': { - '@id': 'as:startTime', - '@type': 'xsd:dateTime', - }, - 'summary': 'as:summary', - 'summaryMap': { - '@id': 'as:summary', - '@container': '@language', - }, - 'totalItems': { - '@id': 'as:totalItems', - '@type': 'xsd:nonNegativeInteger', - }, - 'units': 'as:units', - 'updated': { - '@id': 'as:updated', - '@type': 'xsd:dateTime', - }, - 'width': { - '@id': 'as:width', - '@type': 'xsd:nonNegativeInteger', - }, - 'describes': { - '@id': 'as:describes', - '@type': '@id', - }, - 'formerType': { - '@id': 'as:formerType', - '@type': '@id', - }, - 'deleted': { - '@id': 'as:deleted', - '@type': 'xsd:dateTime', - }, - 'inbox': { - '@id': 'ldp:inbox', - '@type': '@id', - }, - 'outbox': { - '@id': 'as:outbox', - '@type': '@id', - }, - 'following': { - '@id': 'as:following', - '@type': '@id', - }, - 'followers': { - '@id': 'as:followers', - '@type': '@id', - }, - 'streams': { - '@id': 'as:streams', - '@type': '@id', - }, - 'preferredUsername': 'as:preferredUsername', - 'endpoints': { - '@id': 'as:endpoints', - '@type': '@id', - }, - 'uploadMedia': { - '@id': 'as:uploadMedia', - '@type': '@id', - }, - 'proxyUrl': { - '@id': 'as:proxyUrl', - '@type': '@id', - }, - 'liked': { - '@id': 'as:liked', - '@type': '@id', - }, - 'oauthAuthorizationEndpoint': { - '@id': 'as:oauthAuthorizationEndpoint', - '@type': '@id', - }, - 'oauthTokenEndpoint': { - '@id': 'as:oauthTokenEndpoint', - '@type': '@id', - }, - 'provideClientKey': { - '@id': 'as:provideClientKey', - '@type': '@id', - }, - 'signClientKey': { - '@id': 'as:signClientKey', - '@type': '@id', - }, - 'sharedInbox': { - '@id': 'as:sharedInbox', - '@type': '@id', - }, - 'Public': { - '@id': 'as:Public', - '@type': '@id', - }, - 'source': 'as:source', - 'likes': { - '@id': 'as:likes', - '@type': '@id', - }, - 'shares': { - '@id': 'as:shares', - '@type': '@id', - }, - 'alsoKnownAs': { - '@id': 'as:alsoKnownAs', - '@type': '@id', + "@context": { + "@vocab": "_:", + xsd: "http://www.w3.org/2001/XMLSchema#", + as: "https://www.w3.org/ns/activitystreams#", + ldp: "http://www.w3.org/ns/ldp#", + vcard: "http://www.w3.org/2006/vcard/ns#", + id: "@id", + type: "@type", + Accept: "as:Accept", + Activity: "as:Activity", + IntransitiveActivity: "as:IntransitiveActivity", + Add: "as:Add", + Announce: "as:Announce", + Application: "as:Application", + Arrive: "as:Arrive", + Article: "as:Article", + Audio: "as:Audio", + Block: "as:Block", + Collection: "as:Collection", + CollectionPage: "as:CollectionPage", + Relationship: "as:Relationship", + Create: "as:Create", + Delete: "as:Delete", + Dislike: "as:Dislike", + Document: "as:Document", + Event: "as:Event", + Follow: "as:Follow", + Flag: "as:Flag", + Group: "as:Group", + Ignore: "as:Ignore", + Image: "as:Image", + Invite: "as:Invite", + Join: "as:Join", + Leave: "as:Leave", + Like: "as:Like", + Link: "as:Link", + Mention: "as:Mention", + Note: "as:Note", + Object: "as:Object", + Offer: "as:Offer", + OrderedCollection: "as:OrderedCollection", + OrderedCollectionPage: "as:OrderedCollectionPage", + Organization: "as:Organization", + Page: "as:Page", + Person: "as:Person", + Place: "as:Place", + Profile: "as:Profile", + Question: "as:Question", + Reject: "as:Reject", + Remove: "as:Remove", + Service: "as:Service", + TentativeAccept: "as:TentativeAccept", + TentativeReject: "as:TentativeReject", + Tombstone: "as:Tombstone", + Undo: "as:Undo", + Update: "as:Update", + Video: "as:Video", + View: "as:View", + Listen: "as:Listen", + Read: "as:Read", + Move: "as:Move", + Travel: "as:Travel", + IsFollowing: "as:IsFollowing", + IsFollowedBy: "as:IsFollowedBy", + IsContact: "as:IsContact", + IsMember: "as:IsMember", + subject: { + "@id": "as:subject", + "@type": "@id", + }, + relationship: { + "@id": "as:relationship", + "@type": "@id", + }, + actor: { + "@id": "as:actor", + "@type": "@id", + }, + attributedTo: { + "@id": "as:attributedTo", + "@type": "@id", + }, + attachment: { + "@id": "as:attachment", + "@type": "@id", + }, + bcc: { + "@id": "as:bcc", + "@type": "@id", + }, + bto: { + "@id": "as:bto", + "@type": "@id", + }, + cc: { + "@id": "as:cc", + "@type": "@id", + }, + context: { + "@id": "as:context", + "@type": "@id", + }, + current: { + "@id": "as:current", + "@type": "@id", + }, + first: { + "@id": "as:first", + "@type": "@id", + }, + generator: { + "@id": "as:generator", + "@type": "@id", + }, + icon: { + "@id": "as:icon", + "@type": "@id", + }, + image: { + "@id": "as:image", + "@type": "@id", + }, + inReplyTo: { + "@id": "as:inReplyTo", + "@type": "@id", + }, + items: { + "@id": "as:items", + "@type": "@id", + }, + instrument: { + "@id": "as:instrument", + "@type": "@id", + }, + orderedItems: { + "@id": "as:items", + "@type": "@id", + "@container": "@list", + }, + last: { + "@id": "as:last", + "@type": "@id", + }, + location: { + "@id": "as:location", + "@type": "@id", + }, + next: { + "@id": "as:next", + "@type": "@id", + }, + object: { + "@id": "as:object", + "@type": "@id", + }, + oneOf: { + "@id": "as:oneOf", + "@type": "@id", + }, + anyOf: { + "@id": "as:anyOf", + "@type": "@id", + }, + closed: { + "@id": "as:closed", + "@type": "xsd:dateTime", + }, + origin: { + "@id": "as:origin", + "@type": "@id", + }, + accuracy: { + "@id": "as:accuracy", + "@type": "xsd:float", + }, + prev: { + "@id": "as:prev", + "@type": "@id", + }, + preview: { + "@id": "as:preview", + "@type": "@id", + }, + replies: { + "@id": "as:replies", + "@type": "@id", + }, + result: { + "@id": "as:result", + "@type": "@id", + }, + audience: { + "@id": "as:audience", + "@type": "@id", + }, + partOf: { + "@id": "as:partOf", + "@type": "@id", + }, + tag: { + "@id": "as:tag", + "@type": "@id", + }, + target: { + "@id": "as:target", + "@type": "@id", + }, + to: { + "@id": "as:to", + "@type": "@id", + }, + url: { + "@id": "as:url", + "@type": "@id", + }, + altitude: { + "@id": "as:altitude", + "@type": "xsd:float", + }, + content: "as:content", + contentMap: { + "@id": "as:content", + "@container": "@language", + }, + name: "as:name", + nameMap: { + "@id": "as:name", + "@container": "@language", + }, + duration: { + "@id": "as:duration", + "@type": "xsd:duration", + }, + endTime: { + "@id": "as:endTime", + "@type": "xsd:dateTime", + }, + height: { + "@id": "as:height", + "@type": "xsd:nonNegativeInteger", + }, + href: { + "@id": "as:href", + "@type": "@id", + }, + hreflang: "as:hreflang", + latitude: { + "@id": "as:latitude", + "@type": "xsd:float", + }, + longitude: { + "@id": "as:longitude", + "@type": "xsd:float", + }, + mediaType: "as:mediaType", + published: { + "@id": "as:published", + "@type": "xsd:dateTime", + }, + radius: { + "@id": "as:radius", + "@type": "xsd:float", + }, + rel: "as:rel", + startIndex: { + "@id": "as:startIndex", + "@type": "xsd:nonNegativeInteger", + }, + startTime: { + "@id": "as:startTime", + "@type": "xsd:dateTime", + }, + summary: "as:summary", + summaryMap: { + "@id": "as:summary", + "@container": "@language", + }, + totalItems: { + "@id": "as:totalItems", + "@type": "xsd:nonNegativeInteger", + }, + units: "as:units", + updated: { + "@id": "as:updated", + "@type": "xsd:dateTime", + }, + width: { + "@id": "as:width", + "@type": "xsd:nonNegativeInteger", + }, + describes: { + "@id": "as:describes", + "@type": "@id", + }, + formerType: { + "@id": "as:formerType", + "@type": "@id", + }, + deleted: { + "@id": "as:deleted", + "@type": "xsd:dateTime", + }, + inbox: { + "@id": "ldp:inbox", + "@type": "@id", + }, + outbox: { + "@id": "as:outbox", + "@type": "@id", + }, + following: { + "@id": "as:following", + "@type": "@id", + }, + followers: { + "@id": "as:followers", + "@type": "@id", + }, + streams: { + "@id": "as:streams", + "@type": "@id", + }, + preferredUsername: "as:preferredUsername", + endpoints: { + "@id": "as:endpoints", + "@type": "@id", + }, + uploadMedia: { + "@id": "as:uploadMedia", + "@type": "@id", + }, + proxyUrl: { + "@id": "as:proxyUrl", + "@type": "@id", + }, + liked: { + "@id": "as:liked", + "@type": "@id", + }, + oauthAuthorizationEndpoint: { + "@id": "as:oauthAuthorizationEndpoint", + "@type": "@id", + }, + oauthTokenEndpoint: { + "@id": "as:oauthTokenEndpoint", + "@type": "@id", + }, + provideClientKey: { + "@id": "as:provideClientKey", + "@type": "@id", + }, + signClientKey: { + "@id": "as:signClientKey", + "@type": "@id", + }, + sharedInbox: { + "@id": "as:sharedInbox", + "@type": "@id", + }, + Public: { + "@id": "as:Public", + "@type": "@id", + }, + source: "as:source", + likes: { + "@id": "as:likes", + "@type": "@id", + }, + shares: { + "@id": "as:shares", + "@type": "@id", + }, + alsoKnownAs: { + "@id": "as:alsoKnownAs", + "@type": "@id", }, }, }; export const CONTEXTS: Record = { - 'https://w3id.org/identity/v1': id_v1, - 'https://w3id.org/security/v1': security_v1, - 'https://www.w3.org/ns/activitystreams': activitystreams, + "https://w3id.org/identity/v1": id_v1, + "https://w3id.org/security/v1": security_v1, + "https://www.w3.org/ns/activitystreams": activitystreams, }; diff --git a/packages/backend/src/remote/activitypub/misc/get-note-html.ts b/packages/backend/src/remote/activitypub/misc/get-note-html.ts index 389039ebe..cb5294f73 100644 --- a/packages/backend/src/remote/activitypub/misc/get-note-html.ts +++ b/packages/backend/src/remote/activitypub/misc/get-note-html.ts @@ -1,8 +1,8 @@ -import * as mfm from 'mfm-js'; -import { Note } from '@/models/entities/note.js'; -import { toHtml } from '../../../mfm/to-html.js'; +import * as mfm from "mfm-js"; +import type { Note } from "@/models/entities/note.js"; +import { toHtml } from "../../../mfm/to-html.js"; -export default function(note: Note) { - if (!note.text) return ''; +export default function (note: Note) { + if (!note.text) return ""; return toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)); } diff --git a/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts b/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts index bb1ba7925..9d71a46a3 100644 --- a/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts +++ b/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts @@ -1,9 +1,11 @@ -import { IObject } from '../type.js'; -import { extractApHashtagObjects } from '../models/tag.js'; -import { fromHtml } from '../../../mfm/from-html.js'; +import type { IObject } from "../type.js"; +import { extractApHashtagObjects } from "../models/tag.js"; +import { fromHtml } from "../../../mfm/from-html.js"; export function htmlToMfm(html: string, tag?: IObject | IObject[]) { - const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null); + const hashtagNames = extractApHashtagObjects(tag) + .map((x) => x.name) + .filter((x): x is string => x != null); return fromHtml(html, hashtagNames); } diff --git a/packages/backend/src/remote/activitypub/misc/ld-signature.ts b/packages/backend/src/remote/activitypub/misc/ld-signature.ts index 7c2083a27..0a4ec3a53 100644 --- a/packages/backend/src/remote/activitypub/misc/ld-signature.ts +++ b/packages/backend/src/remote/activitypub/misc/ld-signature.ts @@ -1,8 +1,8 @@ -import * as crypto from 'node:crypto'; -import jsonld from 'jsonld'; -import { CONTEXTS } from './contexts.js'; -import fetch from 'node-fetch'; -import { httpAgent, httpsAgent } from '@/misc/fetch.js'; +import * as crypto from "node:crypto"; +import jsonld from "jsonld"; +import { CONTEXTS } from "./contexts.js"; +import fetch from "node-fetch"; +import { httpAgent, httpsAgent } from "@/misc/fetch.js"; // RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017 @@ -11,15 +11,20 @@ export class LdSignature { public preLoad = true; public loderTimeout = 10 * 1000; - constructor() { - } + constructor() {} - public async signRsaSignature2017(data: any, privateKey: string, creator: string, domain?: string, created?: Date): Promise { + public async signRsaSignature2017( + data: any, + privateKey: string, + creator: string, + domain?: string, + created?: Date, + ): Promise { const options = { - type: 'RsaSignature2017', + type: "RsaSignature2017", creator, domain, - nonce: crypto.randomBytes(16).toString('hex'), + nonce: crypto.randomBytes(16).toString("hex"), created: (created || new Date()).toISOString(), } as { type: string; @@ -30,12 +35,12 @@ export class LdSignature { }; if (!domain) { - delete options.domain; + options.domain = undefined; } const toBeSigned = await this.createVerifyData(data, options); - const signer = crypto.createSign('sha256'); + const signer = crypto.createSign("sha256"); signer.update(toBeSigned); signer.end(); @@ -45,30 +50,33 @@ export class LdSignature { ...data, signature: { ...options, - signatureValue: signature.toString('base64'), + signatureValue: signature.toString("base64"), }, }; } - public async verifyRsaSignature2017(data: any, publicKey: string): Promise { + public async verifyRsaSignature2017( + data: any, + publicKey: string, + ): Promise { const toBeSigned = await this.createVerifyData(data, data.signature); - const verifier = crypto.createVerify('sha256'); + const verifier = crypto.createVerify("sha256"); verifier.update(toBeSigned); - return verifier.verify(publicKey, data.signature.signatureValue, 'base64'); + return verifier.verify(publicKey, data.signature.signatureValue, "base64"); } public async createVerifyData(data: any, options: any) { const transformedOptions = { ...options, - '@context': 'https://w3id.org/identity/v1', + "@context": "https://w3id.org/identity/v1", }; - delete transformedOptions['type']; - delete transformedOptions['id']; - delete transformedOptions['signatureValue']; + transformedOptions["type"] = undefined; + transformedOptions["id"] = undefined; + transformedOptions["signatureValue"] = undefined; const canonizedOptions = await this.normalize(transformedOptions); const optionsHash = this.sha256(canonizedOptions); const transformedData = { ...data }; - delete transformedData['signature']; + transformedData["signature"] = undefined; const cannonidedData = await this.normalize(transformedData); if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`); const documentHash = this.sha256(cannonidedData); @@ -85,7 +93,7 @@ export class LdSignature { private getLoader() { return async (url: string): Promise => { - if (!url.match('^https?\:\/\/')) throw new Error(`Invalid URL ${url}`); + if (!url.match("^https?://")) throw new Error(`Invalid URL ${url}`); if (this.preLoad) { if (url in CONTEXTS) { @@ -111,12 +119,12 @@ export class LdSignature { private async fetchDocument(url: string) { const json = await fetch(url, { headers: { - Accept: 'application/ld+json, application/json', + Accept: "application/ld+json, application/json", }, // TODO //timeout: this.loderTimeout, - agent: u => u.protocol === 'http:' ? httpAgent : httpsAgent, - }).then(res => { + agent: (u) => (u.protocol === "http:" ? httpAgent : httpsAgent), + }).then((res) => { if (!res.ok) { throw new Error(`${res.status} ${res.statusText}`); } else { @@ -128,8 +136,8 @@ export class LdSignature { } public sha256(data: string): string { - const hash = crypto.createHash('sha256'); + const hash = crypto.createHash("sha256"); hash.update(data); - return hash.digest('hex'); + return hash.digest("hex"); } } diff --git a/packages/backend/src/remote/activitypub/models/image.ts b/packages/backend/src/remote/activitypub/models/image.ts index 102b7b134..415f7c400 100644 --- a/packages/backend/src/remote/activitypub/models/image.ts +++ b/packages/backend/src/remote/activitypub/models/image.ts @@ -1,28 +1,32 @@ -import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; -import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js'; -import Resolver from '../resolver.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { apLogger } from '../logger.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles, Users } from '@/models/index.js'; -import { truncate } from '@/misc/truncate.js'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { IRemoteUser } from "@/models/entities/user.js"; +import Resolver from "../resolver.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { apLogger } from "../logger.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles, Users } from "@/models/index.js"; +import { truncate } from "@/misc/truncate.js"; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; const logger = apLogger; /** - * Imageを作成します。 + * create an Image. */ -export async function createImage(actor: CacheableRemoteUser, value: any): Promise { - // 投稿者が凍結されていたらスキップ +export async function createImage( + actor: CacheableRemoteUser, + value: any, +): Promise { + // Skip if author is frozen. if (actor.isSuspended) { - throw new Error('actor has been suspended'); + throw new Error("actor has been suspended"); } - const image = await new Resolver().resolve(value) as any; + const image = (await new Resolver().resolve(value)) as any; if (image.url == null) { - throw new Error('invalid image: url not privided'); + throw new Error("invalid image: url not privided"); } logger.info(`Creating the Image: ${image.url}`); @@ -35,17 +39,20 @@ export async function createImage(actor: CacheableRemoteUser, value: any): Promi uri: image.url, sensitive: image.sensitive, isLink: !instance.cacheRemoteFiles, - comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH) + comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH), }); if (file.isLink) { - // URLが異なっている場合、同じ画像が以前に異なるURLで登録されていたということなので、 - // URLを更新する + // If the URL is different, it means that the same image was previously + // registered with a different URL, so update the URL if (file.url !== image.url) { - await DriveFiles.update({ id: file.id }, { - url: image.url, - uri: image.url, - }); + await DriveFiles.update( + { id: file.id }, + { + url: image.url, + uri: image.url, + }, + ); file = await DriveFiles.findOneByOrFail({ id: file.id }); } @@ -55,14 +62,17 @@ export async function createImage(actor: CacheableRemoteUser, value: any): Promi } /** - * Imageを解決します。 + * Resolve Image. * - * Misskeyに対象のImageが登録されていればそれを返し、そうでなければ - * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 + * If the target Image is registered in Calckey, return it, otherwise + * Fetch from remote server, register with Calckey and return it. */ -export async function resolveImage(actor: CacheableRemoteUser, value: any): Promise { +export async function resolveImage( + actor: CacheableRemoteUser, + value: any, +): Promise { // TODO - // リモートサーバーからフェッチしてきて登録 + // Fetch from remote server and register return await createImage(actor, value); } diff --git a/packages/backend/src/remote/activitypub/models/mention.ts b/packages/backend/src/remote/activitypub/models/mention.ts index 13f77424e..b888fa21a 100644 --- a/packages/backend/src/remote/activitypub/models/mention.ts +++ b/packages/backend/src/remote/activitypub/models/mention.ts @@ -1,24 +1,36 @@ -import promiseLimit from 'promise-limit'; -import { toArray, unique } from '@/prelude/array.js'; -import { CacheableUser, User } from '@/models/entities/user.js'; -import { IObject, isMention, IApMention } from '../type.js'; -import Resolver from '../resolver.js'; -import { resolvePerson } from './person.js'; +import promiseLimit from "promise-limit"; +import { toArray, unique } from "@/prelude/array.js"; +import type { CacheableUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import type { IObject, IApMention } from "../type.js"; +import { isMention } from "../type.js"; +import Resolver from "../resolver.js"; +import { resolvePerson } from "./person.js"; -export async function extractApMentions(tags: IObject | IObject[] | null | undefined) { - const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string)); +export async function extractApMentions( + tags: IObject | IObject[] | null | undefined, +) { + const hrefs = unique( + extractApMentionObjects(tags).map((x) => x.href as string), + ); const resolver = new Resolver(); const limit = promiseLimit(2); - const mentionedUsers = (await Promise.all( - hrefs.map(x => limit(() => resolvePerson(x, resolver).catch(() => null))), - )).filter((x): x is CacheableUser => x != null); + const mentionedUsers = ( + await Promise.all( + hrefs.map((x) => + limit(() => resolvePerson(x, resolver).catch(() => null)), + ), + ) + ).filter((x): x is CacheableUser => x != null); return mentionedUsers; } -export function extractApMentionObjects(tags: IObject | IObject[] | null | undefined): IApMention[] { +export function extractApMentionObjects( + tags: IObject | IObject[] | null | undefined, +): IApMention[] { if (tags == null) return []; return toArray(tags).filter(isMention); } diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index d5db2a2cf..72953c5bf 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -1,32 +1,41 @@ -import promiseLimit from 'promise-limit'; +import promiseLimit from "promise-limit"; -import config from '@/config/index.js'; -import Resolver from '../resolver.js'; -import post from '@/services/note/create.js'; -import { resolvePerson } from './person.js'; -import { resolveImage } from './image.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { htmlToMfm } from '../misc/html-to-mfm.js'; -import { extractApHashtags } from './tag.js'; -import { unique, toArray, toSingle } from '@/prelude/array.js'; -import { extractPollFromQuestion } from './question.js'; -import vote from '@/services/note/polls/vote.js'; -import { apLogger } from '../logger.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; -import { extractDbHost, toPuny } from '@/misc/convert-host.js'; -import { Emojis, Polls, MessagingMessages } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { genId } from '@/misc/gen-id.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { getApLock } from '@/misc/app-lock.js'; -import { createMessage } from '@/services/messages/create.js'; -import { parseAudience } from '../audience.js'; -import { extractApMentions } from './mention.js'; -import DbResolver from '../db-resolver.js'; -import { StatusError } from '@/misc/fetch.js'; +import config from "@/config/index.js"; +import Resolver from "../resolver.js"; +import post from "@/services/note/create.js"; +import { resolvePerson } from "./person.js"; +import { resolveImage } from "./image.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { htmlToMfm } from "../misc/html-to-mfm.js"; +import { extractApHashtags } from "./tag.js"; +import { unique, toArray, toSingle } from "@/prelude/array.js"; +import { extractPollFromQuestion } from "./question.js"; +import vote from "@/services/note/polls/vote.js"; +import { apLogger } from "../logger.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; +import { extractDbHost, toPuny } from "@/misc/convert-host.js"; +import { Emojis, Polls, MessagingMessages } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import type { IObject, IPost } from "../type.js"; +import { + getOneApId, + getApId, + getOneApHrefNullable, + validPost, + isEmoji, + getApType, +} from "../type.js"; +import type { Emoji } from "@/models/entities/emoji.js"; +import { genId } from "@/misc/gen-id.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { getApLock } from "@/misc/app-lock.js"; +import { createMessage } from "@/services/messages/create.js"; +import { parseAudience } from "../audience.js"; +import { extractApMentions } from "./mention.js"; +import DbResolver from "../db-resolver.js"; +import { StatusError } from "@/misc/fetch.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; const logger = apLogger; @@ -34,7 +43,7 @@ export function validateNote(object: any, uri: string) { const expectHost = extractDbHost(uri); if (object == null) { - return new Error('invalid Note: object is null'); + return new Error("invalid Note: object is null"); } if (!validPost.includes(getApType(object))) { @@ -42,30 +51,47 @@ export function validateNote(object: any, uri: string) { } if (object.id && extractDbHost(object.id) !== expectHost) { - return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(object.id)}`); + return new Error( + `invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost( + object.id, + )}`, + ); } - if (object.attributedTo && extractDbHost(getOneApId(object.attributedTo)) !== expectHost) { - return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(object.attributedTo)}`); + if ( + object.attributedTo && + extractDbHost(getOneApId(object.attributedTo)) !== expectHost + ) { + return new Error( + `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost( + object.attributedTo, + )}`, + ); } return null; } /** - * Noteをフェッチします。 + * Fetch Notes. * - * Misskeyに対象のNoteが登録されていればそれを返します。 + * If the target Note is registered in Calckey, it will be returned. */ -export async function fetchNote(object: string | IObject): Promise { +export async function fetchNote( + object: string | IObject, +): Promise { const dbResolver = new DbResolver(); return await dbResolver.getNoteFromApId(object); } /** - * Noteを作成します。 + * Create a Note. */ -export async function createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise { +export async function createNote( + value: string | IObject, + resolver?: Resolver, + silent = false, +): Promise { if (resolver == null) resolver = new Resolver(); const object: any = await resolver.resolve(value); @@ -80,7 +106,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s value: value, object: object, }); - throw new Error('invalid note'); + throw new Error("invalid note"); } const note: IPost = object; @@ -89,132 +115,176 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s logger.info(`Creating the Note: ${note.id}`); - // 投稿者をフェッチ - const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser; + // Fetch author + const actor = (await resolvePerson( + getOneApId(note.attributedTo), + resolver, + )) as CacheableRemoteUser; - // 投稿者が凍結されていたらスキップ + // Skip if author is suspended. if (actor.isSuspended) { - throw new Error('actor has been suspended'); + throw new Error("actor has been suspended"); } const noteAudience = await parseAudience(actor, note.to, note.cc); let visibility = noteAudience.visibility; const visibleUsers = noteAudience.visibleUsers; - // Audience (to, cc) が指定されてなかった場合 - if (visibility === 'specified' && visibleUsers.length === 0) { - if (typeof value === 'string') { // 入力がstringならばresolverでGETが発生している - // こちらから匿名GET出来たものならばpublic - visibility = 'public'; + // If Audience (to, cc) was not specified + if (visibility === "specified" && visibleUsers.length === 0) { + if (typeof value === "string") { + // If the input is a string, GET occurs in resolver + // Public if you can GET anonymously from here + visibility = "public"; } } - let isTalk = note._misskey_talk && visibility === 'specified'; + let isTalk = note._misskey_talk && visibility === "specified"; const apMentions = await extractApMentions(note.tag); const apHashtags = await extractApHashtags(note.tag); - // 添付ファイル + // Attachments // TODO: attachmentは必ずしもImageではない // TODO: attachmentは必ずしも配列ではない // Noteがsensitiveなら添付もsensitiveにする const limit = promiseLimit(2); - note.attachment = Array.isArray(note.attachment) ? note.attachment : note.attachment ? [note.attachment] : []; - const files = note.attachment - .map(attach => attach.sensitive = note.sensitive) - ? (await Promise.all(note.attachment.map(x => limit(() => resolveImage(actor, x)) as Promise))) - .filter(image => image != null) + note.attachment = Array.isArray(note.attachment) + ? note.attachment + : note.attachment + ? [note.attachment] + : []; + const files = note.attachment.map( + (attach) => (attach.sensitive = note.sensitive), + ) + ? ( + await Promise.all( + note.attachment.map( + (x) => limit(() => resolveImage(actor, x)) as Promise, + ), + ) + ).filter((image) => image != null) : []; - // リプライ + // Reply const reply: Note | null = note.inReplyTo - ? await resolveNote(note.inReplyTo, resolver).then(x => { - if (x == null) { - logger.warn(`Specified inReplyTo, but nout found`); - throw new Error('inReplyTo not found'); - } else { - return x; - } - }).catch(async e => { - // トークだったらinReplyToのエラーは無視 - const uri = getApId(note.inReplyTo); - if (uri.startsWith(config.url + '/')) { - const id = uri.split('/').pop(); - const talk = await MessagingMessages.findOneBy({ id }); - if (talk) { - isTalk = true; - return null; - } - } + ? await resolveNote(note.inReplyTo, resolver) + .then((x) => { + if (x == null) { + logger.warn("Specified inReplyTo, but nout found"); + throw new Error("inReplyTo not found"); + } else { + return x; + } + }) + .catch(async (e) => { + // トークだったらinReplyToのエラーは無視 + const uri = getApId(note.inReplyTo); + if (uri.startsWith(`${config.url}/`)) { + const id = uri.split("/").pop(); + const talk = await MessagingMessages.findOneBy({ id }); + if (talk) { + isTalk = true; + return null; + } + } - logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`); - throw e; - }) + logger.warn( + `Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`, + ); + throw e; + }) : null; - // 引用 + // Quote let quote: Note | undefined | null; - if (note._misskey_quote || note.quoteUrl) { - const tryResolveNote = async (uri: string): Promise<{ - status: 'ok'; - res: Note | null; - } | { - status: 'permerror' | 'temperror'; - }> => { - if (typeof uri !== 'string' || !uri.match(/^https?:/)) return { status: 'permerror' }; + if (note._misskey_quote || note.quoteUrl || note.quoteUri) { + const tryResolveNote = async ( + uri: string, + ): Promise< + | { + status: "ok"; + res: Note | null; + } + | { + status: "permerror" | "temperror"; + } + > => { + if (typeof uri !== "string" || !uri.match(/^https?:/)) + return { status: "permerror" }; try { const res = await resolveNote(uri); if (res) { return { - status: 'ok', + status: "ok", res, }; } else { return { - status: 'permerror', + status: "permerror", }; } } catch (e) { return { - status: (e instanceof StatusError && e.isClientError) ? 'permerror' : 'temperror', + status: + e instanceof StatusError && e.isClientError + ? "permerror" + : "temperror", }; } }; - const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string')); - const results = await Promise.all(uris.map(uri => tryResolveNote(uri))); + const uris = unique( + [note._misskey_quote, note.quoteUrl, note.quoteUri].filter( + (x): x is string => typeof x === "string", + ), + ); + const results = await Promise.all(uris.map((uri) => tryResolveNote(uri))); - quote = results.filter((x): x is { status: 'ok', res: Note | null } => x.status === 'ok').map(x => x.res).find(x => x); + quote = results + .filter((x): x is { status: "ok"; res: Note | null } => x.status === "ok") + .map((x) => x.res) + .find((x) => x); if (!quote) { - if (results.some(x => x.status === 'temperror')) { - throw new Error('quote resolve failed'); + if (results.some((x) => x.status === "temperror")) { + throw new Error("quote resolve failed"); } } } - const cw = note.summary === '' ? null : note.summary; + const cw = note.summary === "" ? null : note.summary; - // テキストのパース + // Text parsing let text: string | null = null; - if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source?.content === 'string') { + if ( + note.source?.mediaType === "text/x.misskeymarkdown" && + typeof note.source?.content === "string" + ) { text = note.source.content; - } else if (typeof note._misskey_content !== 'undefined') { + } else if (typeof note._misskey_content !== "undefined") { text = note._misskey_content; - } else if (typeof note.content === 'string') { + } else if (typeof note.content === "string") { text = htmlToMfm(note.content, note.tag); } // vote - if (reply && reply.hasPoll) { + if (reply?.hasPoll) { const poll = await Polls.findOneByOrFail({ noteId: reply.id }); - const tryCreateVote = async (name: string, index: number): Promise => { + const tryCreateVote = async ( + name: string, + index: number, + ): Promise => { if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) { - logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`); + logger.warn( + `vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`, + ); } else if (index >= 0) { - logger.info(`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`); + logger.info( + `vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`, + ); await vote(actor, reply, index); // リモートフォロワーにUpdate配信 @@ -224,64 +294,87 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s }; if (note.name) { - return await tryCreateVote(note.name, poll.choices.findIndex(x => x === note.name)); + return await tryCreateVote( + note.name, + poll.choices.findIndex((x) => x === note.name), + ); } } - const emojis = await extractEmojis(note.tag || [], actor.host).catch(e => { + const emojis = await extractEmojis(note.tag || [], actor.host).catch((e) => { logger.info(`extractEmojis: ${e}`); return [] as Emoji[]; }); - const apEmojis = emojis.map(emoji => emoji.name); + const apEmojis = emojis.map((emoji) => emoji.name); - const poll = await extractPollFromQuestion(note, resolver).catch(() => undefined); + const poll = await extractPollFromQuestion(note, resolver).catch( + () => undefined, + ); if (isTalk) { for (const recipient of visibleUsers) { - await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id); + await createMessage( + actor, + recipient, + undefined, + text || undefined, + files && files.length > 0 ? files[0] : null, + object.id, + ); return null; } } - return await post(actor, { - createdAt: note.published ? new Date(note.published) : null, - files, - reply, - renote: quote, - name: note.name, - cw, - text, - localOnly: false, - visibility, - visibleUsers, - apMentions, - apHashtags, - apEmojis, - poll, - uri: note.id, - url: getOneApHrefNullable(note.url), - }, silent); + return await post( + actor, + { + createdAt: note.published ? new Date(note.published) : null, + files, + reply, + renote: quote, + name: note.name, + cw, + text, + localOnly: false, + visibility, + visibleUsers, + apMentions, + apHashtags, + apEmojis, + poll, + uri: note.id, + url: getOneApHrefNullable(note.url), + }, + silent, + ); } /** - * Noteを解決します。 + * Resolve Note. * - * Misskeyに対象のNoteが登録されていればそれを返し、そうでなければ - * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 + * If the target Note is registered in Calckey, return it, otherwise + * Fetch from remote server, register with Calckey and return it. */ -export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise { - const uri = typeof value === 'string' ? value : value.id; - if (uri == null) throw new Error('missing uri'); +export async function resolveNote( + value: string | IObject, + resolver?: Resolver, +): Promise { + const uri = typeof value === "string" ? value : value.id; + if (uri == null) throw new Error("missing uri"); - // ブロックしてたら中断 - const meta = await fetchMeta(); - if (meta.blockedHosts.includes(extractDbHost(uri))) throw new StatusError('host blocked', 451, `host ${extractDbHost(uri)} is blocked`); + // Abort if origin host is blocked + if (await shouldBlockInstance(extractDbHost(uri))) + throw new StatusError( + "host blocked", + 451, + `host ${extractDbHost(uri)} is blocked`, + ); const unlock = await getApLock(uri); try { - //#region このサーバーに既に登録されていたらそれを返す + //#region Returns if already registered with this server const exist = await fetchNote(uri); if (exist) { @@ -290,70 +383,87 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver): //#endregion if (uri.startsWith(config.url)) { - throw new StatusError('cannot resolve local note', 400, 'cannot resolve local note'); + throw new StatusError( + "cannot resolve local note", + 400, + "cannot resolve local note", + ); } - // リモートサーバーからフェッチしてきて登録 - // ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが - // 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。 + // Fetch from remote server and register + // If the attached `Note` Object is specified here instead of the uri, the note will be generated without going through the server fetch. + // Since the attached Note Object may be disguised, always specify the uri and fetch it from the server. return await createNote(uri, resolver, true); } finally { unlock(); } } -export async function extractEmojis(tags: IObject | IObject[], host: string): Promise { +export async function extractEmojis( + tags: IObject | IObject[], + host: string, +): Promise { host = toPuny(host); if (!tags) return []; const eomjiTags = toArray(tags).filter(isEmoji); - return await Promise.all(eomjiTags.map(async tag => { - const name = tag.name!.replace(/^:/, '').replace(/:$/, ''); - tag.icon = toSingle(tag.icon); + return await Promise.all( + eomjiTags.map(async (tag) => { + const name = tag.name!.replace(/^:/, "").replace(/:$/, ""); + tag.icon = toSingle(tag.icon); - const exists = await Emojis.findOneBy({ - host, - name, - }); + const exists = await Emojis.findOneBy({ + host, + name, + }); - if (exists) { - if ((tag.updated != null && exists.updatedAt == null) - || (tag.id != null && exists.uri == null) - || (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt) - || (tag.icon!.url !== exists.originalUrl) - ) { - await Emojis.update({ - host, - name, - }, { - uri: tag.id, - originalUrl: tag.icon!.url, - publicUrl: tag.icon!.url, - updatedAt: new Date(), - }); + if (exists) { + if ( + (tag.updated != null && exists.updatedAt == null) || + (tag.id != null && exists.uri == null) || + (tag.updated != null && + exists.updatedAt != null && + new Date(tag.updated) > exists.updatedAt) || + tag.icon!.url !== exists.originalUrl + ) { + await Emojis.update( + { + host, + name, + }, + { + uri: tag.id, + originalUrl: tag.icon!.url, + publicUrl: tag.icon!.url, + updatedAt: new Date(), + }, + ); - return await Emojis.findOneBy({ - host, - name, - }) as Emoji; + return (await Emojis.findOneBy({ + host, + name, + })) as Emoji; + } + + return exists; } - return exists; - } + logger.info(`register emoji host=${host}, name=${name}`); - logger.info(`register emoji host=${host}, name=${name}`); - - return await Emojis.insert({ - id: genId(), - host, - name, - uri: tag.id, - originalUrl: tag.icon!.url, - publicUrl: tag.icon!.url, - updatedAt: new Date(), - aliases: [], - } as Partial).then(x => Emojis.findOneByOrFail(x.identifiers[0])); - })); + return await Emojis.insert({ + id: genId(), + host, + name, + uri: tag.id, + originalUrl: tag.icon!.url, + publicUrl: tag.icon!.url, + updatedAt: new Date(), + aliases: [], + } as Partial).then((x) => + Emojis.findOneByOrFail(x.identifiers[0]), + ); + }), + ); } diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 21ef83af7..0ec671f0a 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -1,36 +1,53 @@ -import { URL } from 'node:url'; -import promiseLimit from 'promise-limit'; +import { URL } from "node:url"; +import promiseLimit from "promise-limit"; -import config from '@/config/index.js'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; -import { Note } from '@/models/entities/note.js'; -import { updateUsertags } from '@/services/update-hashtag.js'; -import { Users, Instances, DriveFiles, Followings, UserProfiles, UserPublickeys } from '@/models/index.js'; -import { User, IRemoteUser, CacheableUser } from '@/models/entities/user.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { UserNotePining } from '@/models/entities/user-note-pining.js'; -import { genId } from '@/misc/gen-id.js'; -import { instanceChart, usersChart } from '@/services/chart/index.js'; -import { UserPublickey } from '@/models/entities/user-publickey.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { toArray } from '@/prelude/array.js'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { truncate } from '@/misc/truncate.js'; -import { StatusError } from '@/misc/fetch.js'; -import { uriPersonCache } from '@/services/user-cache.js'; -import { publishInternalEvent } from '@/services/stream.js'; -import { db } from '@/db/postgre.js'; -import { apLogger } from '../logger.js'; -import { htmlToMfm } from '../misc/html-to-mfm.js'; -import { fromHtml } from '../../../mfm/from-html.js'; -import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType, isActor } from '../type.js'; -import Resolver from '../resolver.js'; -import { extractApHashtags } from './tag.js'; -import { resolveNote, extractEmojis } from './note.js'; -import { resolveImage } from './image.js'; +import config from "@/config/index.js"; +import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; +import type { Note } from "@/models/entities/note.js"; +import { updateUsertags } from "@/services/update-hashtag.js"; +import { + Users, + Instances, + DriveFiles, + Followings, + UserProfiles, + UserPublickeys, +} from "@/models/index.js"; +import type { IRemoteUser, CacheableUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import type { Emoji } from "@/models/entities/emoji.js"; +import { UserNotePining } from "@/models/entities/user-note-pining.js"; +import { genId } from "@/misc/gen-id.js"; +import { instanceChart, usersChart } from "@/services/chart/index.js"; +import { UserPublickey } from "@/models/entities/user-publickey.js"; +import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { UserProfile } from "@/models/entities/user-profile.js"; +import { toArray } from "@/prelude/array.js"; +import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; +import { truncate } from "@/misc/truncate.js"; +import { StatusError } from "@/misc/fetch.js"; +import { uriPersonCache } from "@/services/user-cache.js"; +import { publishInternalEvent } from "@/services/stream.js"; +import { db } from "@/db/postgre.js"; +import { apLogger } from "../logger.js"; +import { htmlToMfm } from "../misc/html-to-mfm.js"; +import { fromHtml } from "../../../mfm/from-html.js"; +import type { IActor, IObject, IApPropertyValue } from "../type.js"; +import { + isCollectionOrOrderedCollection, + isCollection, + getApId, + getOneApHrefNullable, + isPropertyValue, + getApType, + isActor, +} from "../type.js"; +import Resolver from "../resolver.js"; +import { extractApHashtags } from "./tag.js"; +import { resolveNote, extractEmojis } from "./note.js"; +import { resolveImage } from "./image.js"; const logger = apLogger; @@ -46,54 +63,61 @@ function validateActor(x: IObject, uri: string): IActor { const expectHost = toPuny(new URL(uri).hostname); if (x == null) { - throw new Error('invalid Actor: object is null'); + throw new Error("invalid Actor: object is null"); } if (!isActor(x)) { throw new Error(`invalid Actor type '${x.type}'`); } - if (!(typeof x.id === 'string' && x.id.length > 0)) { - throw new Error('invalid Actor: wrong id'); + if (!(typeof x.id === "string" && x.id.length > 0)) { + throw new Error("invalid Actor: wrong id"); } - if (!(typeof x.inbox === 'string' && x.inbox.length > 0)) { - throw new Error('invalid Actor: wrong inbox'); + if (!(typeof x.inbox === "string" && x.inbox.length > 0)) { + throw new Error("invalid Actor: wrong inbox"); } - if (!(typeof x.preferredUsername === 'string' && x.preferredUsername.length > 0 && x.preferredUsername.length <= 128 && /^\w([\w-.]*\w)?$/.test(x.preferredUsername))) { - throw new Error('invalid Actor: wrong username'); + if ( + !( + typeof x.preferredUsername === "string" && + x.preferredUsername.length > 0 && + x.preferredUsername.length <= 128 && + /^\w([\w-.]*\w)?$/.test(x.preferredUsername) + ) + ) { + throw new Error("invalid Actor: wrong username"); } // These fields are only informational, and some AP software allows these // fields to be very long. If they are too long, we cut them off. This way // we can at least see these users and their activities. if (x.name) { - if (!(typeof x.name === 'string' && x.name.length > 0)) { - throw new Error('invalid Actor: wrong name'); + if (!(typeof x.name === "string" && x.name.length > 0)) { + throw new Error("invalid Actor: wrong name"); } x.name = truncate(x.name, nameLength); } if (x.summary) { - if (!(typeof x.summary === 'string' && x.summary.length > 0)) { - throw new Error('invalid Actor: wrong summary'); + if (!(typeof x.summary === "string" && x.summary.length > 0)) { + throw new Error("invalid Actor: wrong summary"); } x.summary = truncate(x.summary, summaryLength); } const idHost = toPuny(new URL(x.id!).hostname); if (idHost !== expectHost) { - throw new Error('invalid Actor: id has different host'); + throw new Error("invalid Actor: id has different host"); } if (x.publicKey) { - if (typeof x.publicKey.id !== 'string') { - throw new Error('invalid Actor: publicKey.id is not a string'); + if (typeof x.publicKey.id !== "string") { + throw new Error("invalid Actor: publicKey.id is not a string"); } const publicKeyIdHost = toPuny(new URL(x.publicKey.id).hostname); if (publicKeyIdHost !== expectHost) { - throw new Error('invalid Actor: publicKey.id has different host'); + throw new Error("invalid Actor: publicKey.id has different host"); } } @@ -101,25 +125,28 @@ function validateActor(x: IObject, uri: string): IActor { } /** - * Personをフェッチします。 + * Fetch a Person. * - * Misskeyに対象のPersonが登録されていればそれを返します。 + * If the target Person is registered in Calckey, it will be returned. */ -export async function fetchPerson(uri: string, resolver?: Resolver): Promise { - if (typeof uri !== 'string') throw new Error('uri is not string'); +export async function fetchPerson( + uri: string, + resolver?: Resolver, +): Promise { + if (typeof uri !== "string") throw new Error("uri is not string"); const cached = uriPersonCache.get(uri); if (cached) return cached; - // URIがこのサーバーを指しているならデータベースからフェッチ - if (uri.startsWith(config.url + '/')) { - const id = uri.split('/').pop(); + // Fetch from the database if the URI points to this server + if (uri.startsWith(`${config.url}/`)) { + const id = uri.split("/").pop(); const u = await Users.findOneBy({ id }); if (u) uriPersonCache.set(uri, u); return u; } - //#region このサーバーに既に登録されていたらそれを返す + //#region Returns if already registered with this server const exist = await Users.findOneBy({ uri }); if (exist) { @@ -132,18 +159,25 @@ export async function fetchPerson(uri: string, resolver?: Resolver): Promise { - if (typeof uri !== 'string') throw new Error('uri is not string'); +export async function createPerson( + uri: string, + resolver?: Resolver, +): Promise { + if (typeof uri !== "string") throw new Error("uri is not string"); if (uri.startsWith(config.url)) { - throw new StatusError('cannot resolve local user', 400, 'cannot resolve local user'); + throw new StatusError( + "cannot resolve local user", + 400, + "cannot resolve local user", + ); } if (resolver == null) resolver = new Resolver(); - const object = await resolver.resolve(uri) as any; + const object = (await resolver.resolve(uri)) as any; const person = validateActor(object, uri); @@ -153,64 +187,78 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise normalizeForSearch(tag)).splice(0, 32); + const tags = extractApHashtags(person.tag) + .map((tag) => normalizeForSearch(tag)) + .splice(0, 32); - const isBot = getApType(object) === 'Service'; + const isBot = getApType(object) === "Service"; - const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/); + const bday = person["vcard:bday"]?.match(/^\d{4}-\d{2}-\d{2}/); // Create user let user: IRemoteUser; try { // Start transaction - await db.transaction(async transactionalEntityManager => { - user = await transactionalEntityManager.save(new User({ - id: genId(), - avatarId: null, - bannerId: null, - createdAt: new Date(), - lastFetchedAt: new Date(), - name: truncate(person.name, nameLength), - isLocked: !!person.manuallyApprovesFollowers, - movedToUri: person.movedTo, - alsoKnownAs: person.alsoKnownAs, - isExplorable: !!person.discoverable, - username: person.preferredUsername, - usernameLower: person.preferredUsername!.toLowerCase(), - host, - inbox: person.inbox, - sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined), - followersUri: person.followers ? getApId(person.followers) : undefined, - featured: person.featured ? getApId(person.featured) : undefined, - uri: person.id, - tags, - isBot, - isCat: (person as any).isCat === true, - showTimelineReplies: false, - })) as IRemoteUser; + await db.transaction(async (transactionalEntityManager) => { + user = (await transactionalEntityManager.save( + new User({ + id: genId(), + avatarId: null, + bannerId: null, + createdAt: new Date(), + lastFetchedAt: new Date(), + name: truncate(person.name, nameLength), + isLocked: !!person.manuallyApprovesFollowers, + movedToUri: person.movedTo, + alsoKnownAs: person.alsoKnownAs, + isExplorable: !!person.discoverable, + username: person.preferredUsername, + usernameLower: person.preferredUsername!.toLowerCase(), + host, + inbox: person.inbox, + sharedInbox: + person.sharedInbox || + (person.endpoints ? person.endpoints.sharedInbox : undefined), + followersUri: person.followers + ? getApId(person.followers) + : undefined, + featured: person.featured ? getApId(person.featured) : undefined, + uri: person.id, + tags, + isBot, + isCat: (person as any).isCat === true, + showTimelineReplies: false, + }), + )) as IRemoteUser; - await transactionalEntityManager.save(new UserProfile({ - userId: user.id, - description: person.summary ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null, - url: getOneApHrefNullable(person.url), - fields, - birthday: bday ? bday[0] : null, - location: person['vcard:Address'] || null, - userHost: host, - })); + await transactionalEntityManager.save( + new UserProfile({ + userId: user.id, + description: person.summary + ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) + : null, + url: getOneApHrefNullable(person.url), + fields, + birthday: bday ? bday[0] : null, + location: person["vcard:Address"] || null, + userHost: host, + }), + ); if (person.publicKey) { - await transactionalEntityManager.save(new UserPublickey({ - userId: user.id, - keyId: person.publicKey.id, - keyPem: person.publicKey.publicKeyPem, - })); + await transactionalEntityManager.save( + new UserPublickey({ + userId: user.id, + keyId: person.publicKey.id, + keyPem: person.publicKey.publicKeyPem, + }), + ); } }); } catch (e) { // duplicate key error if (isDuplicateKeyValueError(e)) { - // /users/@a => /users/:id のように入力がaliasなときにエラーになることがあるのを対応 + // /users/@a => /users/:id Corresponds to an error that may occur when the input is an alias like const u = await Users.findOneBy({ uri: person.id, }); @@ -218,7 +266,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { - Instances.increment({ id: i.id }, 'usersCount', 1); + registerOrFetchInstanceDoc(host).then((i) => { + Instances.increment({ id: i.id }, "usersCount", 1); instanceChart.newUser(i.host); fetchInstanceMetadata(i); }); usersChart.update(user!, true); - // ハッシュタグ更新 + // Hashtag update updateUsertags(user!, tags); - //#region アバターとヘッダー画像をフェッチ - const [avatar, banner] = await Promise.all([ - person.icon, - person.image, - ].map(img => - img == null - ? Promise.resolve(null) - : resolveImage(user!, img).catch(() => null), - )); + //#region Fetch avatar and header image + const [avatar, banner] = await Promise.all( + [person.icon, person.image].map((img) => + img == null + ? Promise.resolve(null) + : resolveImage(user!, img).catch(() => null), + ), + ); const avatarId = avatar ? avatar.id : null; const bannerId = banner ? banner.id : null; @@ -260,20 +307,20 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { + //#region Get custom emoji + const emojis = await extractEmojis(person.tag || [], host).catch((e) => { logger.info(`extractEmojis: ${e}`); return [] as Emoji[]; }); - const emojiNames = emojis.map(emoji => emoji.name); + const emojiNames = emojis.map((emoji) => emoji.name); await Users.update(user!.id, { emojis: emojiNames, }); //#endregion - await updateFeatured(user!.id, resolver).catch(err => logger.error(err)); + await updateFeatured(user!.id, resolver).catch((err) => logger.error(err)); return user!; } @@ -285,16 +332,20 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { - if (typeof uri !== 'string') throw new Error('uri is not string'); +export async function updatePerson( + uri: string, + resolver?: Resolver | null, + hint?: IObject, +): Promise { + if (typeof uri !== "string") throw new Error("uri is not string"); // Skip if the URI points to this server - if (uri.startsWith(config.url + '/')) { + if (uri.startsWith(`${config.url}/`)) { return; } //#region Already registered on this server? - const exist = await Users.findOneBy({ uri }) as IRemoteUser; + const exist = (await Users.findOneBy({ uri })) as IRemoteUser; if (exist == null) { return; @@ -303,46 +354,51 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint if (resolver == null) resolver = new Resolver(); - const object = hint || await resolver.resolve(uri); + const object = hint || (await resolver.resolve(uri)); const person = validateActor(object, uri); logger.info(`Updating the Person: ${person.id}`); // Fetch avatar and header image - const [avatar, banner] = await Promise.all([ - person.icon, - person.image, - ].map(img => - img == null - ? Promise.resolve(null) - : resolveImage(exist, img).catch(() => null), - )); + const [avatar, banner] = await Promise.all( + [person.icon, person.image].map((img) => + img == null + ? Promise.resolve(null) + : resolveImage(exist, img).catch(() => null), + ), + ); // Custom pictogram acquisition - const emojis = await extractEmojis(person.tag || [], exist.host).catch(e => { - logger.info(`extractEmojis: ${e}`); - return [] as Emoji[]; - }); + const emojis = await extractEmojis(person.tag || [], exist.host).catch( + (e) => { + logger.info(`extractEmojis: ${e}`); + return [] as Emoji[]; + }, + ); - const emojiNames = emojis.map(emoji => emoji.name); + const emojiNames = emojis.map((emoji) => emoji.name); const { fields } = analyzeAttachments(person.attachment || []); - const tags = extractApHashtags(person.tag).map(tag => normalizeForSearch(tag)).splice(0, 32); + const tags = extractApHashtags(person.tag) + .map((tag) => normalizeForSearch(tag)) + .splice(0, 32); - const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/); + const bday = person["vcard:bday"]?.match(/^\d{4}-\d{2}-\d{2}/); const updates = { lastFetchedAt: new Date(), inbox: person.inbox, - sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined), + sharedInbox: + person.sharedInbox || + (person.endpoints ? person.endpoints.sharedInbox : undefined), followersUri: person.followers ? getApId(person.followers) : undefined, featured: person.featured, emojis: emojiNames, name: truncate(person.name, nameLength), tags, - isBot: getApType(object) === 'Service', + isBot: getApType(object) === "Service", isCat: (person as any).isCat === true, isLocked: !!person.manuallyApprovesFollowers, movedToUri: person.movedTo, @@ -362,43 +418,59 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint await Users.update(exist.id, updates); if (person.publicKey) { - await UserPublickeys.update({ userId: exist.id }, { - keyId: person.publicKey.id, - keyPem: person.publicKey.publicKeyPem, - }); + await UserPublickeys.update( + { userId: exist.id }, + { + keyId: person.publicKey.id, + keyPem: person.publicKey.publicKeyPem, + }, + ); } - await UserProfiles.update({ userId: exist.id }, { - url: getOneApHrefNullable(person.url), - fields, - description: person.summary ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null, - birthday: bday ? bday[0] : null, - location: person['vcard:Address'] || null, - }); + await UserProfiles.update( + { userId: exist.id }, + { + url: getOneApHrefNullable(person.url), + fields, + description: person.summary + ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) + : null, + birthday: bday ? bday[0] : null, + location: person["vcard:Address"] || null, + }, + ); - publishInternalEvent('remoteUserUpdated', { id: exist.id }); + publishInternalEvent("remoteUserUpdated", { id: exist.id }); // Hashtag Update updateUsertags(exist, tags); // If the user in question is a follower, followers will also be updated. - await Followings.update({ - followerId: exist.id, - }, { - followerSharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined), - }); + await Followings.update( + { + followerId: exist.id, + }, + { + followerSharedInbox: + person.sharedInbox || + (person.endpoints ? person.endpoints.sharedInbox : undefined), + }, + ); - await updateFeatured(exist.id, resolver).catch(err => logger.error(err)); + await updateFeatured(exist.id, resolver).catch((err) => logger.error(err)); } /** * Resolve Person. * - * If the target person is registered in Calckey, it returns it; + * If the target person is registered in Calckey, it returns it; * otherwise, it fetches it from the remote server, registers it in Calckey, and returns it. */ -export async function resolvePerson(uri: string, resolver?: Resolver): Promise { - if (typeof uri !== 'string') throw new Error('uri is not string'); +export async function resolvePerson( + uri: string, + resolver?: Resolver, +): Promise { + if (typeof uri !== "string") throw new Error("uri is not string"); //#region If already registered on this server, return it. const exist = await fetchPerson(uri); @@ -414,39 +486,44 @@ export async function resolvePerson(uri: string, resolver?: Resolver): Promise any - } = { - 'misskey:authentication:twitter': (userId, screenName) => ({ userId, screenName }), - 'misskey:authentication:github': (id, login) => ({ id, login }), - 'misskey:authentication:discord': (id, name) => $discord(id, name), - }; + [x: string]: (id: string, username: string) => any; +} = { + "misskey:authentication:twitter": (userId, screenName) => ({ + userId, + screenName, + }), + "misskey:authentication:github": (id, login) => ({ id, login }), + "misskey:authentication:discord": (id, name) => $discord(id, name), +}; const $discord = (id: string, name: string) => { - if (typeof name !== 'string') { - name = 'unknown#0000'; + if (typeof name !== "string") { + name = "unknown#0000"; } - const [username, discriminator] = name.split('#'); + const [username, discriminator] = name.split("#"); return { id, username, discriminator }; }; function addService(target: { [x: string]: any }, source: IApPropertyValue) { const service = services[source.name]; - if (typeof source.value !== 'string') { - source.value = 'unknown'; + if (typeof source.value !== "string") { + source.value = "unknown"; } - const [id, username] = source.value.split('@'); + const [id, username] = source.value.split("@"); if (service) { - target[source.name.split(':')[2]] = service(id, username); + target[source.name.split(":")[2]] = service(id, username); } } -export function analyzeAttachments(attachments: IObject | IObject[] | undefined) { +export function analyzeAttachments( + attachments: IObject | IObject[] | undefined, +) { const fields: { - name: string, - value: string + name: string; + value: string; }[] = []; const services: { [x: string]: any } = {}; @@ -466,7 +543,7 @@ export function analyzeAttachments(attachments: IObject | IObject[] | undefined) return { fields, services }; } -export async function updateFeatured(userId: User['id'], resolver?: Resolver) { +export async function updateFeatured(userId: User["id"], resolver?: Resolver) { const user = await Users.findOneByOrFail({ id: userId }); if (!Users.isRemoteUser(user)) return; if (!user.featured) return; @@ -477,25 +554,34 @@ export async function updateFeatured(userId: User['id'], resolver?: Resolver) { // Resolve to (Ordered)Collection Object const collection = await resolver.resolveCollection(user.featured); - if (!isCollectionOrOrderedCollection(collection)) throw new Error('Object is not Collection or OrderedCollection'); + if (!isCollectionOrOrderedCollection(collection)) + throw new Error("Object is not Collection or OrderedCollection"); // Resolve to Object(may be Note) arrays - const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems; - const items = await Promise.all(toArray(unresolvedItems).map(x => resolver.resolve(x))); + const unresolvedItems = isCollection(collection) + ? collection.items + : collection.orderedItems; + const items = await Promise.all( + toArray(unresolvedItems).map((x) => resolver.resolve(x)), + ); // Resolve and regist Notes const limit = promiseLimit(2); - const featuredNotes = await Promise.all(items - .filter(item => getApType(item) === 'Note') // TODO: Maybe it doesn't have to be a Note. - .slice(0, 5) - .map(item => limit(() => resolveNote(item, resolver)))); + const featuredNotes = await Promise.all( + items + .filter((item) => getApType(item) === "Note") // TODO: Maybe it doesn't have to be a Note. + .slice(0, 5) + .map((item) => limit(() => resolveNote(item, resolver))), + ); - await db.transaction(async transactionalEntityManager => { - await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); + await db.transaction(async (transactionalEntityManager) => { + await transactionalEntityManager.delete(UserNotePining, { + userId: user.id, + }); // For now, generate the id at a different time and maintain the order. let td = 0; - for (const note of featuredNotes.filter(note => note != null)) { + for (const note of featuredNotes.filter((note) => note != null)) { td -= 1000; transactionalEntityManager.insert(UserNotePining, { id: genId(new Date(Date.now() + td)), diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 94a50d4f7..520b9fee9 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -1,31 +1,41 @@ -import config from '@/config/index.js'; -import Resolver from '../resolver.js'; -import { IObject, IQuestion, isQuestion } from '../type.js'; -import { apLogger } from '../logger.js'; -import { Notes, Polls } from '@/models/index.js'; -import { IPoll } from '@/models/entities/poll.js'; +import config from "@/config/index.js"; +import Resolver from "../resolver.js"; +import type { IObject, IQuestion } from "../type.js"; +import { isQuestion } from "../type.js"; +import { apLogger } from "../logger.js"; +import { Notes, Polls } from "@/models/index.js"; +import type { IPoll } from "@/models/entities/poll.js"; -export async function extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise { +export async function extractPollFromQuestion( + source: string | IObject, + resolver?: Resolver, +): Promise { if (resolver == null) resolver = new Resolver(); const question = await resolver.resolve(source); if (!isQuestion(question)) { - throw new Error('invalid type'); + throw new Error("invalid type"); } const multiple = !question.oneOf; - const expiresAt = question.endTime ? new Date(question.endTime) : question.closed ? new Date(question.closed) : null; + const expiresAt = question.endTime + ? new Date(question.endTime) + : question.closed + ? new Date(question.closed) + : null; if (multiple && !question.anyOf) { - throw new Error('invalid question'); + throw new Error("invalid question"); } - const choices = question[multiple ? 'anyOf' : 'oneOf']! - .map((x, i) => x.name!); + const choices = question[multiple ? "anyOf" : "oneOf"]!.map( + (x, i) => x.name!, + ); - const votes = question[multiple ? 'anyOf' : 'oneOf']! - .map((x, i) => x.replies && x.replies.totalItems || x._misskey_votes || 0); + const votes = question[multiple ? "anyOf" : "oneOf"]!.map( + (x, i) => x.replies?.totalItems || x._misskey_votes || 0, + ); return { choices, @@ -41,25 +51,25 @@ export async function extractPollFromQuestion(source: string | IObject, resolver * @returns true if updated */ export async function updateQuestion(value: any, resolver?: Resolver) { - const uri = typeof value === 'string' ? value : value.id; + const uri = typeof value === "string" ? value : value.id; - // URIがこのサーバーを指しているならスキップ - if (uri.startsWith(config.url + '/')) throw new Error('uri points local'); + // Skip if URI points to this server + if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); - //#region このサーバーに既に登録されているか + //#region Already registered with this server? const note = await Notes.findOneBy({ uri }); - if (note == null) throw new Error('Question is not registed'); + if (note == null) throw new Error("Question is not registed"); const poll = await Polls.findOneBy({ noteId: note.id }); - if (poll == null) throw new Error('Question is not registed'); + if (poll == null) throw new Error("Question is not registed"); //#endregion // resolve new Question object if (resolver == null) resolver = new Resolver(); - const question = await resolver.resolve(value) as IQuestion; + const question = (await resolver.resolve(value)) as IQuestion; apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`); - if (question.type !== 'Question') throw new Error('object is not a Question'); + if (question.type !== "Question") throw new Error("object is not a Question"); const apChoices = question.oneOf || question.anyOf; @@ -67,7 +77,8 @@ export async function updateQuestion(value: any, resolver?: Resolver) { for (const choice of poll.choices) { const oldCount = poll.votes[poll.choices.indexOf(choice)]; - const newCount = apChoices!.filter(ap => ap.name === choice)[0].replies!.totalItems; + const newCount = apChoices!.filter((ap) => ap.name === choice)[0].replies! + .totalItems; if (oldCount !== newCount) { changed = true; @@ -75,9 +86,12 @@ export async function updateQuestion(value: any, resolver?: Resolver) { } } - await Polls.update({ noteId: note.id }, { - votes: poll.votes, - }); + await Polls.update( + { noteId: note.id }, + { + votes: poll.votes, + }, + ); return changed; } diff --git a/packages/backend/src/remote/activitypub/models/tag.ts b/packages/backend/src/remote/activitypub/models/tag.ts index 964dabad0..537cdecbd 100644 --- a/packages/backend/src/remote/activitypub/models/tag.ts +++ b/packages/backend/src/remote/activitypub/models/tag.ts @@ -1,18 +1,25 @@ -import { toArray } from '@/prelude/array.js'; -import { IObject, isHashtag, IApHashtag } from '../type.js'; +import { toArray } from "@/prelude/array.js"; +import type { IObject, IApHashtag } from "../type.js"; +import { isHashtag } from "../type.js"; -export function extractApHashtags(tags: IObject | IObject[] | null | undefined) { +export function extractApHashtags( + tags: IObject | IObject[] | null | undefined, +) { if (tags == null) return []; const hashtags = extractApHashtagObjects(tags); - return hashtags.map(tag => { - const m = tag.name.match(/^#(.+)/); - return m ? m[1] : null; - }).filter((x): x is string => x != null); + return hashtags + .map((tag) => { + const m = tag.name.match(/^#(.+)/); + return m ? m[1] : null; + }) + .filter((x): x is string => x != null); } -export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] { +export function extractApHashtagObjects( + tags: IObject | IObject[] | null | undefined, +): IApHashtag[] { if (tags == null) return []; return toArray(tags).filter(isHashtag); } diff --git a/packages/backend/src/remote/activitypub/perform.ts b/packages/backend/src/remote/activitypub/perform.ts index a3c10ba94..0d2cdb4a5 100644 --- a/packages/backend/src/remote/activitypub/perform.ts +++ b/packages/backend/src/remote/activitypub/perform.ts @@ -1,14 +1,20 @@ -import { IObject } from './type.js'; -import { CacheableRemoteUser } from '@/models/entities/user.js'; -import { performActivity } from './kernel/index.js'; -import { updatePerson } from './models/person.js'; +import type { IObject } from "./type.js"; +import type { CacheableRemoteUser } from "@/models/entities/user.js"; +import { performActivity } from "./kernel/index.js"; +import { updatePerson } from "./models/person.js"; -export default async (actor: CacheableRemoteUser, activity: IObject): Promise => { +export default async ( + actor: CacheableRemoteUser, + activity: IObject, +): Promise => { await performActivity(actor, activity); - // ついでにリモートユーザーの情報が古かったら更新しておく + // Update the remote user information if it is out of date if (actor.uri) { - if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { + if ( + actor.lastFetchedAt == null || + Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24 + ) { setImmediate(() => { updatePerson(actor.uri!); }); diff --git a/packages/backend/src/remote/activitypub/renderer/accept.ts b/packages/backend/src/remote/activitypub/renderer/accept.ts index cb01f6a91..fd145dcf9 100644 --- a/packages/backend/src/remote/activitypub/renderer/accept.ts +++ b/packages/backend/src/remote/activitypub/renderer/accept.ts @@ -1,8 +1,8 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; -export default (object: any, user: { id: User['id']; host: null }) => ({ - type: 'Accept', +export default (object: any, user: { id: User["id"]; host: null }) => ({ + type: "Accept", actor: `${config.url}/users/${user.id}`, object, }); diff --git a/packages/backend/src/remote/activitypub/renderer/add.ts b/packages/backend/src/remote/activitypub/renderer/add.ts index ec4788429..d8203ac1e 100644 --- a/packages/backend/src/remote/activitypub/renderer/add.ts +++ b/packages/backend/src/remote/activitypub/renderer/add.ts @@ -1,8 +1,8 @@ -import config from '@/config/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; export default (user: ILocalUser, target: any, object: any) => ({ - type: 'Add', + type: "Add", actor: `${config.url}/users/${user.id}`, target, object, diff --git a/packages/backend/src/remote/activitypub/renderer/announce.ts b/packages/backend/src/remote/activitypub/renderer/announce.ts index 2709fea51..cff79a3f7 100644 --- a/packages/backend/src/remote/activitypub/renderer/announce.ts +++ b/packages/backend/src/remote/activitypub/renderer/announce.ts @@ -1,5 +1,5 @@ -import config from '@/config/index.js'; -import { Note } from '@/models/entities/note.js'; +import config from "@/config/index.js"; +import type { Note } from "@/models/entities/note.js"; export default (object: any, note: Note) => { const attributedTo = `${config.url}/users/${note.userId}`; @@ -7,12 +7,12 @@ export default (object: any, note: Note) => { let to: string[] = []; let cc: string[] = []; - if (note.visibility === 'public') { - to = ['https://www.w3.org/ns/activitystreams#Public']; + if (note.visibility === "public") { + to = ["https://www.w3.org/ns/activitystreams#Public"]; cc = [`${attributedTo}/followers`]; - } else if (note.visibility === 'home') { + } else if (note.visibility === "home") { to = [`${attributedTo}/followers`]; - cc = ['https://www.w3.org/ns/activitystreams#Public']; + cc = ["https://www.w3.org/ns/activitystreams#Public"]; } else { return null; } @@ -20,7 +20,7 @@ export default (object: any, note: Note) => { return { id: `${config.url}/notes/${note.id}/activity`, actor: `${config.url}/users/${note.userId}`, - type: 'Announce', + type: "Announce", published: note.createdAt.toISOString(), to, cc, diff --git a/packages/backend/src/remote/activitypub/renderer/block.ts b/packages/backend/src/remote/activitypub/renderer/block.ts index 802d7280b..c2ea267f3 100644 --- a/packages/backend/src/remote/activitypub/renderer/block.ts +++ b/packages/backend/src/remote/activitypub/renderer/block.ts @@ -1,5 +1,5 @@ -import config from '@/config/index.js'; -import { Blocking } from '@/models/entities/blocking.js'; +import config from "@/config/index.js"; +import type { Blocking } from "@/models/entities/blocking.js"; /** * Renders a block into its ActivityPub representation. @@ -8,11 +8,11 @@ import { Blocking } from '@/models/entities/blocking.js'; */ export function renderBlock(block: Blocking) { if (block.blockee?.uri == null) { - throw new Error('renderBlock: missing blockee uri'); + throw new Error("renderBlock: missing blockee uri"); } return { - type: 'Block', + type: "Block", id: `${config.url}/blocks/${block.id}`, actor: `${config.url}/users/${block.blockerId}`, object: block.blockee.uri, diff --git a/packages/backend/src/remote/activitypub/renderer/create.ts b/packages/backend/src/remote/activitypub/renderer/create.ts index 281a3cb2a..857f5722c 100644 --- a/packages/backend/src/remote/activitypub/renderer/create.ts +++ b/packages/backend/src/remote/activitypub/renderer/create.ts @@ -1,11 +1,11 @@ -import config from '@/config/index.js'; -import { Note } from '@/models/entities/note.js'; +import config from "@/config/index.js"; +import type { Note } from "@/models/entities/note.js"; export default (object: any, note: Note) => { const activity = { id: `${config.url}/notes/${note.id}/activity`, actor: `${config.url}/users/${note.userId}`, - type: 'Create', + type: "Create", published: note.createdAt.toISOString(), object, } as any; diff --git a/packages/backend/src/remote/activitypub/renderer/delete.ts b/packages/backend/src/remote/activitypub/renderer/delete.ts index 4edd3a880..70bdc3492 100644 --- a/packages/backend/src/remote/activitypub/renderer/delete.ts +++ b/packages/backend/src/remote/activitypub/renderer/delete.ts @@ -1,8 +1,8 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; -export default (object: any, user: { id: User['id']; host: null }) => ({ - type: 'Delete', +export default (object: any, user: { id: User["id"]; host: null }) => ({ + type: "Delete", actor: `${config.url}/users/${user.id}`, object, published: new Date().toISOString(), diff --git a/packages/backend/src/remote/activitypub/renderer/document.ts b/packages/backend/src/remote/activitypub/renderer/document.ts index c973de4c4..1c2ca89d9 100644 --- a/packages/backend/src/remote/activitypub/renderer/document.ts +++ b/packages/backend/src/remote/activitypub/renderer/document.ts @@ -1,8 +1,8 @@ -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles } from '@/models/index.js'; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles } from "@/models/index.js"; export default (file: DriveFile) => ({ - type: 'Document', + type: "Document", mediaType: file.type, url: DriveFiles.getPublicUrl(file), name: file.comment, diff --git a/packages/backend/src/remote/activitypub/renderer/emoji.ts b/packages/backend/src/remote/activitypub/renderer/emoji.ts index 0bf15eefd..3d9b8cd55 100644 --- a/packages/backend/src/remote/activitypub/renderer/emoji.ts +++ b/packages/backend/src/remote/activitypub/renderer/emoji.ts @@ -1,14 +1,17 @@ -import config from '@/config/index.js'; -import { Emoji } from '@/models/entities/emoji.js'; +import config from "@/config/index.js"; +import type { Emoji } from "@/models/entities/emoji.js"; export default (emoji: Emoji) => ({ id: `${config.url}/emojis/${emoji.name}`, - type: 'Emoji', + type: "Emoji", name: `:${emoji.name}:`, - updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString, + updated: + emoji.updatedAt != null + ? emoji.updatedAt.toISOString() + : new Date().toISOString, icon: { - type: 'Image', - mediaType: emoji.type || 'image/png', + type: "Image", + mediaType: emoji.type || "image/png", url: emoji.publicUrl || emoji.originalUrl, // || emoji.originalUrl してるのは後方互換性のため }, }); diff --git a/packages/backend/src/remote/activitypub/renderer/flag.ts b/packages/backend/src/remote/activitypub/renderer/flag.ts index 58eadddba..f94d508e1 100644 --- a/packages/backend/src/remote/activitypub/renderer/flag.ts +++ b/packages/backend/src/remote/activitypub/renderer/flag.ts @@ -1,13 +1,18 @@ -import config from '@/config/index.js'; -import { IObject, IActivity } from '@/remote/activitypub/type.js'; -import { ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { getInstanceActor } from '@/services/instance-actor.js'; +import config from "@/config/index.js"; +import { IObject, IActivity } from "@/remote/activitypub/type.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { IRemoteUser } from "@/models/entities/user.js"; +import { getInstanceActor } from "@/services/instance-actor.js"; // to anonymise reporters, the reporting actor must be a system user // object has to be a uri or array of uris -export const renderFlag = (user: ILocalUser, object: [string], content: string) => { +export const renderFlag = ( + user: ILocalUser, + object: [string], + content: string, +) => { return { - type: 'Flag', + type: "Flag", actor: `${config.url}/users/${user.id}`, content, object, diff --git a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts index 2c9678090..ad7f05bf8 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts @@ -1,13 +1,13 @@ -import config from '@/config/index.js'; -import { Relay } from '@/models/entities/relay.js'; -import { ILocalUser } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { Relay } from "@/models/entities/relay.js"; +import type { ILocalUser } from "@/models/entities/user.js"; export function renderFollowRelay(relay: Relay, relayActor: ILocalUser) { const follow = { id: `${config.url}/activities/follow-relay/${relay.id}`, - type: 'Follow', + type: "Follow", actor: `${config.url}/users/${relayActor.id}`, - object: 'https://www.w3.org/ns/activitystreams#Public', + object: "https://www.w3.org/ns/activitystreams#Public", }; return follow; diff --git a/packages/backend/src/remote/activitypub/renderer/follow-user.ts b/packages/backend/src/remote/activitypub/renderer/follow-user.ts index 9a8a16d74..22ee429ff 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow-user.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow-user.ts @@ -1,12 +1,12 @@ -import config from '@/config/index.js'; -import { Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import { Users } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; /** * Convert (local|remote)(Follower|Followee)ID to URL * @param id Follower|Followee ID */ -export default async function renderFollowUser(id: User['id']): Promise { +export default async function renderFollowUser(id: User["id"]): Promise { const user = await Users.findOneByOrFail({ id: id }); return Users.isLocalUser(user) ? `${config.url}/users/${user.id}` : user.uri; } diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts index 00fac18ad..3ff89c12a 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow.ts @@ -1,13 +1,21 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; -export default (follower: { id: User['id']; host: User['host']; uri: User['host'] }, followee: { id: User['id']; host: User['host']; uri: User['host'] }, requestId?: string) => { +export default ( + follower: { id: User["id"]; host: User["host"]; uri: User["host"] }, + followee: { id: User["id"]; host: User["host"]; uri: User["host"] }, + requestId?: string, +) => { const follow = { id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`, - type: 'Follow', - actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri, - object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri, + type: "Follow", + actor: Users.isLocalUser(follower) + ? `${config.url}/users/${follower.id}` + : follower.uri, + object: Users.isLocalUser(followee) + ? `${config.url}/users/${followee.id}` + : followee.uri, } as any; return follow; diff --git a/packages/backend/src/remote/activitypub/renderer/hashtag.ts b/packages/backend/src/remote/activitypub/renderer/hashtag.ts index a7b441e00..a00cd1ff5 100644 --- a/packages/backend/src/remote/activitypub/renderer/hashtag.ts +++ b/packages/backend/src/remote/activitypub/renderer/hashtag.ts @@ -1,7 +1,7 @@ -import config from '@/config/index.js'; +import config from "@/config/index.js"; export default (tag: string) => ({ - type: 'Hashtag', + type: "Hashtag", href: `${config.url}/tags/${encodeURIComponent(tag)}`, name: `#${tag}`, }); diff --git a/packages/backend/src/remote/activitypub/renderer/image.ts b/packages/backend/src/remote/activitypub/renderer/image.ts index c7d5a31a2..96183c7ad 100644 --- a/packages/backend/src/remote/activitypub/renderer/image.ts +++ b/packages/backend/src/remote/activitypub/renderer/image.ts @@ -1,8 +1,8 @@ -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles } from '@/models/index.js'; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles } from "@/models/index.js"; export default (file: DriveFile) => ({ - type: 'Image', + type: "Image", url: DriveFiles.getPublicUrl(file), sensitive: file.isSensitive, name: file.comment, diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index 2e1fbf1dd..7b98cf2d7 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -1,60 +1,73 @@ -import { v4 as uuid } from 'uuid'; -import config from '@/config/index.js'; -import { getUserKeypair } from '@/misc/keypair-store.js'; -import type { User } from '@/models/entities/user.js'; -import { LdSignature } from '../misc/ld-signature.js'; -import type { IActivity } from '../type.js'; +import { v4 as uuid } from "uuid"; +import config from "@/config/index.js"; +import { getUserKeypair } from "@/misc/keypair-store.js"; +import type { User } from "@/models/entities/user.js"; +import { LdSignature } from "../misc/ld-signature.js"; +import type { IActivity } from "../type.js"; export const renderActivity = (x: any): IActivity | null => { if (x == null) return null; - if (typeof x === 'object' && x.id == null) { + if (typeof x === "object" && x.id == null) { x.id = `${config.url}/${uuid()}`; } - return Object.assign({ - '@context': [ - 'https://www.w3.org/ns/activitystreams', - 'https://w3id.org/security/v1', - { - // as non-standards - manuallyApprovesFollowers: 'as:manuallyApprovesFollowers', - movedToUri: 'as:movedTo', - sensitive: 'as:sensitive', - Hashtag: 'as:Hashtag', - quoteUrl: 'as:quoteUrl', - // Mastodon - toot: 'http://joinmastodon.org/ns#', - Emoji: 'toot:Emoji', - featured: 'toot:featured', - discoverable: 'toot:discoverable', - // schema - schema: 'http://schema.org#', - PropertyValue: 'schema:PropertyValue', - value: 'schema:value', - // Misskey - misskey: 'https://misskey-hub.net/ns#', - '_misskey_content': 'misskey:_misskey_content', - '_misskey_quote': 'misskey:_misskey_quote', - '_misskey_reaction': 'misskey:_misskey_reaction', - '_misskey_votes': 'misskey:_misskey_votes', - '_misskey_talk': 'misskey:_misskey_talk', - 'isCat': 'misskey:isCat', - // vcard - vcard: 'http://www.w3.org/2006/vcard/ns#', - }, - ], - }, x); + return Object.assign( + { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + // as non-standards + manuallyApprovesFollowers: "as:manuallyApprovesFollowers", + movedToUri: "as:movedTo", + sensitive: "as:sensitive", + Hashtag: "as:Hashtag", + quoteUri: "fedibird:quoteUri", + quoteUrl: "as:quoteUrl", + // Mastodon + toot: "http://joinmastodon.org/ns#", + Emoji: "toot:Emoji", + featured: "toot:featured", + discoverable: "toot:discoverable", + // schema + schema: "http://schema.org#", + PropertyValue: "schema:PropertyValue", + value: "schema:value", + // Misskey + misskey: "https://misskey-hub.net/ns#", + _misskey_content: "misskey:_misskey_content", + _misskey_quote: "misskey:_misskey_quote", + _misskey_reaction: "misskey:_misskey_reaction", + _misskey_votes: "misskey:_misskey_votes", + _misskey_talk: "misskey:_misskey_talk", + isCat: "misskey:isCat", + // Fedibird + fedibird: "http://fedibird.com/ns#", + // vcard + vcard: "http://www.w3.org/2006/vcard/ns#", + }, + ], + }, + x, + ); }; -export const attachLdSignature = async (activity: any, user: { id: User['id']; host: null; }): Promise => { +export const attachLdSignature = async ( + activity: any, + user: { id: User["id"]; host: null }, +): Promise => { if (activity == null) return null; const keypair = await getUserKeypair(user.id); const ldSignature = new LdSignature(); ldSignature.debug = false; - activity = await ldSignature.signRsaSignature2017(activity, keypair.privateKey, `${config.url}/users/${user.id}#main-key`); + activity = await ldSignature.signRsaSignature2017( + activity, + keypair.privateKey, + `${config.url}/users/${user.id}#main-key`, + ); return activity; }; diff --git a/packages/backend/src/remote/activitypub/renderer/key.ts b/packages/backend/src/remote/activitypub/renderer/key.ts index c4f3d464f..084bb5361 100644 --- a/packages/backend/src/remote/activitypub/renderer/key.ts +++ b/packages/backend/src/remote/activitypub/renderer/key.ts @@ -1,14 +1,14 @@ -import config from '@/config/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { UserKeypair } from '@/models/entities/user-keypair.js'; -import { createPublicKey } from 'node:crypto'; +import config from "@/config/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import type { UserKeypair } from "@/models/entities/user-keypair.js"; +import { createPublicKey } from "node:crypto"; export default (user: ILocalUser, key: UserKeypair, postfix?: string) => ({ - id: `${config.url}/users/${user.id}${postfix || '/publickey'}`, - type: 'Key', + id: `${config.url}/users/${user.id}${postfix || "/publickey"}`, + type: "Key", owner: `${config.url}/users/${user.id}`, publicKeyPem: createPublicKey(key.publicKey).export({ - type: 'spki', - format: 'pem', + type: "spki", + format: "pem", }), }); diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts index 12477d637..53c66c5c9 100644 --- a/packages/backend/src/remote/activitypub/renderer/like.ts +++ b/packages/backend/src/remote/activitypub/renderer/like.ts @@ -1,32 +1,36 @@ -import { IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import { Note } from '@/models/entities/note.js'; -import { Emojis } from '@/models/index.js'; -import renderEmoji from './emoji.js'; +import { IsNull } from "typeorm"; +import config from "@/config/index.js"; +import type { NoteReaction } from "@/models/entities/note-reaction.js"; +import type { Note } from "@/models/entities/note.js"; +import { Emojis } from "@/models/index.js"; +import renderEmoji from "./emoji.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; export const renderLike = async (noteReaction: NoteReaction, note: Note) => { const reaction = noteReaction.reaction; + const meta = await fetchMeta(); const object = { - type: 'Like', + type: "Like", id: `${config.url}/likes/${noteReaction.id}`, actor: `${config.url}/users/${noteReaction.userId}`, object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`, - ... (!['\u2b50', '\u1f44d'].includes(reaction) ? { - content: reaction, - _misskey_reaction: reaction, - } : {}), + ...(!meta.defaultReaction.includes(reaction) + ? { + content: reaction, + _misskey_reaction: reaction, + } + : {}), } as any; - if (reaction.startsWith(':')) { - const name = reaction.replace(/:/g, ''); + if (reaction.startsWith(":")) { + const name = reaction.replace(/:/g, ""); const emoji = await Emojis.findOneBy({ name, host: IsNull(), }); - if (emoji) object.tag = [ renderEmoji(emoji) ]; + if (emoji) object.tag = [renderEmoji(emoji)]; } return object; diff --git a/packages/backend/src/remote/activitypub/renderer/mention.ts b/packages/backend/src/remote/activitypub/renderer/mention.ts index c7e62e884..e7f0435c1 100644 --- a/packages/backend/src/remote/activitypub/renderer/mention.ts +++ b/packages/backend/src/remote/activitypub/renderer/mention.ts @@ -1,9 +1,13 @@ -import config from '@/config/index.js'; -import { User, ILocalUser } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; +import config from "@/config/index.js"; +import type { User, ILocalUser } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; export default (mention: User) => ({ - type: 'Mention', - href: Users.isRemoteUser(mention) ? mention.uri : `${config.url}/users/${(mention as ILocalUser).id}`, - name: Users.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as ILocalUser).username}`, + type: "Mention", + href: Users.isRemoteUser(mention) + ? mention.uri + : `${config.url}/users/${(mention as ILocalUser).id}`, + name: Users.isRemoteUser(mention) + ? `@${mention.username}@${mention.host}` + : `@${(mention as ILocalUser).username}`, }); diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index b3bafaa3a..2ad2fec9f 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -1,21 +1,27 @@ -import { In, IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles, Notes, Users, Emojis, Polls } from '@/models/index.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { Poll } from '@/models/entities/poll.js'; -import toHtml from '../misc/get-note-html.js'; -import renderEmoji from './emoji.js'; -import renderMention from './mention.js'; -import renderHashtag from './hashtag.js'; -import renderDocument from './document.js'; +import { In, IsNull } from "typeorm"; +import config from "@/config/index.js"; +import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js"; +import type { Emoji } from "@/models/entities/emoji.js"; +import type { Poll } from "@/models/entities/poll.js"; +import toHtml from "../misc/get-note-html.js"; +import renderEmoji from "./emoji.js"; +import renderMention from "./mention.js"; +import renderHashtag from "./hashtag.js"; +import renderDocument from "./document.js"; -export default async function renderNote(note: Note, dive = true, isTalk = false): Promise> { +export default async function renderNote( + note: Note, + dive = true, + isTalk = false, +): Promise> { const getPromisedFiles = async (ids: string[]) => { if (!ids || ids.length === 0) return []; const items = await DriveFiles.findBy({ id: In(ids) }); - return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[]; + return ids + .map((id) => items.find((item) => item.id === id)) + .filter((item) => item != null) as DriveFile[]; }; let inReplyTo; @@ -55,34 +61,39 @@ export default async function renderNote(note: Note, dive = true, isTalk = false const attributedTo = `${config.url}/users/${note.userId}`; - const mentions = (JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers).map(x => x.uri); + const mentions = ( + JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers + ).map((x) => x.uri); let to: string[] = []; let cc: string[] = []; - if (note.visibility === 'public') { - to = ['https://www.w3.org/ns/activitystreams#Public']; + if (note.visibility === "public") { + to = ["https://www.w3.org/ns/activitystreams#Public"]; cc = [`${attributedTo}/followers`].concat(mentions); - } else if (note.visibility === 'home') { + } else if (note.visibility === "home") { to = [`${attributedTo}/followers`]; - cc = ['https://www.w3.org/ns/activitystreams#Public'].concat(mentions); - } else if (note.visibility === 'followers') { + cc = ["https://www.w3.org/ns/activitystreams#Public"].concat(mentions); + } else if (note.visibility === "followers") { to = [`${attributedTo}/followers`]; cc = mentions; } else { to = mentions; } - const mentionedUsers = note.mentions.length > 0 ? await Users.findBy({ - id: In(note.mentions), - }) : []; + const mentionedUsers = + note.mentions.length > 0 + ? await Users.findBy({ + id: In(note.mentions), + }) + : []; - const hashtagTags = (note.tags || []).map(tag => renderHashtag(tag)); - const mentionTags = mentionedUsers.map(u => renderMention(u)); + const hashtagTags = (note.tags || []).map((tag) => renderHashtag(tag)); + const mentionTags = mentionedUsers.map((u) => renderMention(u)); const files = await getPromisedFiles(note.fileIds); - const text = note.text ?? ''; + const text = note.text ?? ""; let poll: Poll | null = null; if (note.hasPoll) { @@ -95,44 +106,49 @@ export default async function renderNote(note: Note, dive = true, isTalk = false apText += `\n\nRE: ${quote}`; } - const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw; + const summary = note.cw === "" ? String.fromCharCode(0x200b) : note.cw; - const content = toHtml(Object.assign({}, note, { - text: apText, - })); + const content = toHtml( + Object.assign({}, note, { + text: apText, + }), + ); const emojis = await getEmojis(note.emojis); - const apemojis = emojis.map(emoji => renderEmoji(emoji)); + const apemojis = emojis.map((emoji) => renderEmoji(emoji)); - const tag = [ - ...hashtagTags, - ...mentionTags, - ...apemojis, - ]; + const tag = [...hashtagTags, ...mentionTags, ...apemojis]; - const asPoll = poll ? { - type: 'Question', - content: toHtml(Object.assign({}, note, { - text: text, - })), - [poll.expiresAt && poll.expiresAt < new Date() ? 'closed' : 'endTime']: poll.expiresAt, - [poll.multiple ? 'anyOf' : 'oneOf']: poll.choices.map((text, i) => ({ - type: 'Note', - name: text, - replies: { - type: 'Collection', - totalItems: poll!.votes[i], - }, - })), - } : {}; + const asPoll = poll + ? { + type: "Question", + content: toHtml( + Object.assign({}, note, { + text: text, + }), + ), + [poll.expiresAt && poll.expiresAt < new Date() ? "closed" : "endTime"]: + poll.expiresAt, + [poll.multiple ? "anyOf" : "oneOf"]: poll.choices.map((text, i) => ({ + type: "Note", + name: text, + replies: { + type: "Collection", + totalItems: poll!.votes[i], + }, + })), + } + : {}; - const asTalk = isTalk ? { - _misskey_talk: true, - } : {}; + const asTalk = isTalk + ? { + _misskey_talk: true, + } + : {}; return { id: `${config.url}/notes/${note.id}`, - type: 'Note', + type: "Note", attributedTo, summary, content, @@ -142,13 +158,14 @@ export default async function renderNote(note: Note, dive = true, isTalk = false mediaType: "text/x.misskeymarkdown", }, _misskey_quote: quote, + quoteUri: quote, quoteUrl: quote, published: note.createdAt.toISOString(), to, cc, inReplyTo, attachment: files.map(renderDocument), - sensitive: note.cw != null || files.some(file => file.isSensitive), + sensitive: note.cw != null || files.some((file) => file.isSensitive), tag, ...asPoll, ...asTalk, @@ -159,11 +176,13 @@ export async function getEmojis(names: string[]): Promise { if (names == null || names.length === 0) return []; const emojis = await Promise.all( - names.map(name => Emojis.findOneBy({ - name, - host: IsNull(), - })), + names.map((name) => + Emojis.findOneBy({ + name, + host: IsNull(), + }), + ), ); - return emojis.filter(emoji => emoji != null) as Emoji[]; + return emojis.filter((emoji) => emoji != null) as Emoji[]; } diff --git a/packages/backend/src/remote/activitypub/renderer/ordered-collection-page.ts b/packages/backend/src/remote/activitypub/renderer/ordered-collection-page.ts index c5e25f577..2275c9c94 100644 --- a/packages/backend/src/remote/activitypub/renderer/ordered-collection-page.ts +++ b/packages/backend/src/remote/activitypub/renderer/ordered-collection-page.ts @@ -7,11 +7,18 @@ * @param prev URL of prev page (optional) * @param next URL of next page (optional) */ -export default function(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) { +export default function ( + id: string, + totalItems: any, + orderedItems: any, + partOf: string, + prev?: string, + next?: string, +) { const page = { id, partOf, - type: 'OrderedCollectionPage', + type: "OrderedCollectionPage", totalItems, orderedItems, } as any; diff --git a/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts b/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts index ff9a77be3..b975399b6 100644 --- a/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts +++ b/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts @@ -6,9 +6,15 @@ * @param last URL of last page (optional) * @param orderedItems attached objects (optional) */ -export default function(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: Record[]): { +export default function ( + id: string | null, + totalItems: any, + first?: string, + last?: string, + orderedItems?: Record[], +): { id: string | null; - type: 'OrderedCollection'; + type: "OrderedCollection"; totalItems: any; first?: string; last?: string; @@ -16,7 +22,7 @@ export default function(id: string | null, totalItems: any, first?: string, last } { const page: any = { id, - type: 'OrderedCollection', + type: "OrderedCollection", totalItems, }; diff --git a/packages/backend/src/remote/activitypub/renderer/person.ts b/packages/backend/src/remote/activitypub/renderer/person.ts index 4f73d28a6..1122a3a27 100644 --- a/packages/backend/src/remote/activitypub/renderer/person.ts +++ b/packages/backend/src/remote/activitypub/renderer/person.ts @@ -1,60 +1,65 @@ -import { URL } from 'node:url'; -import * as mfm from 'mfm-js'; -import config from '@/config/index.js'; -import type { ILocalUser } from '@/models/entities/user.js'; -import { DriveFiles, UserProfiles } from '@/models/index.js'; -import { getUserKeypair } from '@/misc/keypair-store.js'; -import { toHtml } from '../../../mfm/to-html.js'; -import renderImage from './image.js'; -import renderKey from './key.js'; -import { getEmojis } from './note.js'; -import renderEmoji from './emoji.js'; -import renderHashtag from './hashtag.js'; -import type { IIdentifier } from '../models/identifier.js'; +import { URL } from "node:url"; +import * as mfm from "mfm-js"; +import config from "@/config/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { DriveFiles, UserProfiles } from "@/models/index.js"; +import { getUserKeypair } from "@/misc/keypair-store.js"; +import { toHtml } from "../../../mfm/to-html.js"; +import renderImage from "./image.js"; +import renderKey from "./key.js"; +import { getEmojis } from "./note.js"; +import renderEmoji from "./emoji.js"; +import renderHashtag from "./hashtag.js"; +import type { IIdentifier } from "../models/identifier.js"; export async function renderPerson(user: ILocalUser) { const id = `${config.url}/users/${user.id}`; const isSystem = !!user.username.match(/\./); const [avatar, banner, profile] = await Promise.all([ - user.avatarId ? DriveFiles.findOneBy({ id: user.avatarId }) : Promise.resolve(undefined), - user.bannerId ? DriveFiles.findOneBy({ id: user.bannerId }) : Promise.resolve(undefined), + user.avatarId + ? DriveFiles.findOneBy({ id: user.avatarId }) + : Promise.resolve(undefined), + user.bannerId + ? DriveFiles.findOneBy({ id: user.bannerId }) + : Promise.resolve(undefined), UserProfiles.findOneByOrFail({ userId: user.id }), ]); const attachment: { - type: 'PropertyValue', - name: string, - value: string, - identifier?: IIdentifier + type: "PropertyValue"; + name: string; + value: string; + identifier?: IIdentifier; }[] = []; if (profile.fields) { for (const field of profile.fields) { attachment.push({ - type: 'PropertyValue', + type: "PropertyValue", name: field.name, - value: (field.value != null && field.value.match(/^https?:/)) - ? `${new URL(field.value).href}` + value: field.value?.match(/^https?:/) + ? `${ + new URL(field.value).href + }` : field.value, }); } } const emojis = await getEmojis(user.emojis); - const apemojis = emojis.map(emoji => renderEmoji(emoji)); + const apemojis = emojis.map((emoji) => renderEmoji(emoji)); - const hashtagTags = (user.tags || []).map(tag => renderHashtag(tag)); + const hashtagTags = (user.tags || []).map((tag) => renderHashtag(tag)); - const tag = [ - ...apemojis, - ...hashtagTags, - ]; + const tag = [...apemojis, ...hashtagTags]; const keypair = await getUserKeypair(user.id); const person = { - type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person', + type: isSystem ? "Application" : user.isBot ? "Service" : "Person", id, inbox: `${id}/inbox`, outbox: `${id}/outbox`, @@ -66,13 +71,15 @@ export async function renderPerson(user: ILocalUser) { url: `${config.url}/@${user.username}`, preferredUsername: user.username, name: user.name, - summary: profile.description ? toHtml(mfm.parse(profile.description)) : null, + summary: profile.description + ? toHtml(mfm.parse(profile.description)) + : null, icon: avatar ? renderImage(avatar) : null, image: banner ? renderImage(banner) : null, tag, manuallyApprovesFollowers: user.isLocked, discoverable: !!user.isExplorable, - publicKey: renderKey(user, keypair, '#main-key'), + publicKey: renderKey(user, keypair, "#main-key"), isCat: user.isCat, attachment: attachment.length ? attachment : undefined, } as any; @@ -86,11 +93,11 @@ export async function renderPerson(user: ILocalUser) { } if (profile.birthday) { - person['vcard:bday'] = profile.birthday; + person["vcard:bday"] = profile.birthday; } if (profile.location) { - person['vcard:Address'] = profile.location; + person["vcard:Address"] = profile.location; } return person; diff --git a/packages/backend/src/remote/activitypub/renderer/question.ts b/packages/backend/src/remote/activitypub/renderer/question.ts index d4d1b590a..cb89aa758 100644 --- a/packages/backend/src/remote/activitypub/renderer/question.ts +++ b/packages/backend/src/remote/activitypub/renderer/question.ts @@ -1,19 +1,23 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { Poll } from '@/models/entities/poll.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import type { Poll } from "@/models/entities/poll.js"; -export default async function renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) { +export default async function renderQuestion( + user: { id: User["id"] }, + note: Note, + poll: Poll, +) { const question = { - type: 'Question', + type: "Question", id: `${config.url}/questions/${note.id}`, actor: `${config.url}/users/${user.id}`, - content: note.text || '', - [poll.multiple ? 'anyOf' : 'oneOf']: poll.choices.map((text, i) => ({ + content: note.text || "", + [poll.multiple ? "anyOf" : "oneOf"]: poll.choices.map((text, i) => ({ name: text, _misskey_votes: poll.votes[i], replies: { - type: 'Collection', + type: "Collection", totalItems: poll.votes[i], }, })), diff --git a/packages/backend/src/remote/activitypub/renderer/read.ts b/packages/backend/src/remote/activitypub/renderer/read.ts index a30e649f6..212e7e8dd 100644 --- a/packages/backend/src/remote/activitypub/renderer/read.ts +++ b/packages/backend/src/remote/activitypub/renderer/read.ts @@ -1,9 +1,12 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; -export const renderReadActivity = (user: { id: User['id'] }, message: MessagingMessage) => ({ - type: 'Read', +export const renderReadActivity = ( + user: { id: User["id"] }, + message: MessagingMessage, +) => ({ + type: "Read", actor: `${config.url}/users/${user.id}`, object: message.uri, }); diff --git a/packages/backend/src/remote/activitypub/renderer/reject.ts b/packages/backend/src/remote/activitypub/renderer/reject.ts index ab4cc1646..7ac445241 100644 --- a/packages/backend/src/remote/activitypub/renderer/reject.ts +++ b/packages/backend/src/remote/activitypub/renderer/reject.ts @@ -1,8 +1,8 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; -export default (object: any, user: { id: User['id'] }) => ({ - type: 'Reject', +export default (object: any, user: { id: User["id"] }) => ({ + type: "Reject", actor: `${config.url}/users/${user.id}`, object, }); diff --git a/packages/backend/src/remote/activitypub/renderer/remove.ts b/packages/backend/src/remote/activitypub/renderer/remove.ts index 1be3edc5d..e3b3fef85 100644 --- a/packages/backend/src/remote/activitypub/renderer/remove.ts +++ b/packages/backend/src/remote/activitypub/renderer/remove.ts @@ -1,8 +1,8 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; -export default (user: { id: User['id'] }, target: any, object: any) => ({ - type: 'Remove', +export default (user: { id: User["id"] }, target: any, object: any) => ({ + type: "Remove", actor: `${config.url}/users/${user.id}`, target, object, diff --git a/packages/backend/src/remote/activitypub/renderer/tombstone.ts b/packages/backend/src/remote/activitypub/renderer/tombstone.ts index 313ca74e9..5c4003c75 100644 --- a/packages/backend/src/remote/activitypub/renderer/tombstone.ts +++ b/packages/backend/src/remote/activitypub/renderer/tombstone.ts @@ -1,4 +1,4 @@ export default (id: string) => ({ id, - type: 'Tombstone', + type: "Tombstone", }); diff --git a/packages/backend/src/remote/activitypub/renderer/undo.ts b/packages/backend/src/remote/activitypub/renderer/undo.ts index 46631df9e..249d643b2 100644 --- a/packages/backend/src/remote/activitypub/renderer/undo.ts +++ b/packages/backend/src/remote/activitypub/renderer/undo.ts @@ -1,12 +1,16 @@ -import config from '@/config/index.js'; -import { ILocalUser, User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; +import { ILocalUser } from "@/models/entities/user.js"; -export default (object: any, user: { id: User['id'] }) => { +export default (object: any, user: { id: User["id"] }) => { if (object == null) return null; - const id = typeof object.id === 'string' && object.id.startsWith(config.url) ? `${object.id}/undo` : undefined; + const id = + typeof object.id === "string" && object.id.startsWith(config.url) + ? `${object.id}/undo` + : undefined; return { - type: 'Undo', + type: "Undo", ...(id ? { id } : {}), actor: `${config.url}/users/${user.id}`, object, diff --git a/packages/backend/src/remote/activitypub/renderer/update.ts b/packages/backend/src/remote/activitypub/renderer/update.ts index cf880f03f..765a52f06 100644 --- a/packages/backend/src/remote/activitypub/renderer/update.ts +++ b/packages/backend/src/remote/activitypub/renderer/update.ts @@ -1,12 +1,12 @@ -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; -export default (object: any, user: { id: User['id'] }) => { +export default (object: any, user: { id: User["id"] }) => { const activity = { id: `${config.url}/users/${user.id}#updates/${new Date().getTime()}`, actor: `${config.url}/users/${user.id}`, - type: 'Update', - to: [ 'https://www.w3.org/ns/activitystreams#Public' ], + type: "Update", + to: ["https://www.w3.org/ns/activitystreams#Public"], object, published: new Date().toISOString(), } as any; diff --git a/packages/backend/src/remote/activitypub/renderer/vote.ts b/packages/backend/src/remote/activitypub/renderer/vote.ts index b6eb8e095..21234a112 100644 --- a/packages/backend/src/remote/activitypub/renderer/vote.ts +++ b/packages/backend/src/remote/activitypub/renderer/vote.ts @@ -1,19 +1,25 @@ -import config from '@/config/index.js'; -import { Note } from '@/models/entities/note.js'; -import { IRemoteUser, User } from '@/models/entities/user.js'; -import { PollVote } from '@/models/entities/poll-vote.js'; -import { Poll } from '@/models/entities/poll.js'; +import config from "@/config/index.js"; +import type { Note } from "@/models/entities/note.js"; +import type { IRemoteUser, User } from "@/models/entities/user.js"; +import type { PollVote } from "@/models/entities/poll-vote.js"; +import type { Poll } from "@/models/entities/poll.js"; -export default async function renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser): Promise { +export default async function renderVote( + user: { id: User["id"] }, + vote: PollVote, + note: Note, + poll: Poll, + pollOwner: IRemoteUser, +): Promise { return { id: `${config.url}/users/${user.id}#votes/${vote.id}/activity`, actor: `${config.url}/users/${user.id}`, - type: 'Create', + type: "Create", to: [pollOwner.uri], published: new Date().toISOString(), object: { id: `${config.url}/users/${user.id}#votes/${vote.id}`, - type: 'Note', + type: "Note", attributedTo: `${config.url}/users/${user.id}`, to: [pollOwner.uri], inReplyTo: note.uri, diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts index 5cbfd8c25..ffb3e25a3 100644 --- a/packages/backend/src/remote/activitypub/request.ts +++ b/packages/backend/src/remote/activitypub/request.ts @@ -1,10 +1,10 @@ -import config from '@/config/index.js'; -import { getUserKeypair } from '@/misc/keypair-store.js'; -import { User } from '@/models/entities/user.js'; -import { getResponse } from '../../misc/fetch.js'; -import { createSignedPost, createSignedGet } from './ap-request.js'; +import config from "@/config/index.js"; +import { getUserKeypair } from "@/misc/keypair-store.js"; +import type { User } from "@/models/entities/user.js"; +import { getResponse } from "../../misc/fetch.js"; +import { createSignedPost, createSignedGet } from "./ap-request.js"; -export default async (user: { id: User['id'] }, url: string, object: any) => { +export default async (user: { id: User["id"] }, url: string, object: any) => { const body = JSON.stringify(object); const keypair = await getUserKeypair(user.id); @@ -17,7 +17,7 @@ export default async (user: { id: User['id'] }, url: string, object: any) => { url, body, additionalHeaders: { - 'User-Agent': config.userAgent, + "User-Agent": config.userAgent, }, }); @@ -34,7 +34,7 @@ export default async (user: { id: User['id'] }, url: string, object: any) => { * @param user http-signature user * @param url URL to fetch */ -export async function signedGet(url: string, user: { id: User['id'] }) { +export async function signedGet(url: string, user: { id: User["id"] }) { const keypair = await getUserKeypair(user.id); const req = createSignedGet({ @@ -44,7 +44,7 @@ export async function signedGet(url: string, user: { id: User['id'] }) { }, url, additionalHeaders: { - 'User-Agent': config.userAgent, + "User-Agent": config.userAgent, }, }); diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index 94227e4db..054792760 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -1,20 +1,28 @@ -import config from '@/config/index.js'; -import { getJson } from '@/misc/fetch.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { getInstanceActor } from '@/services/instance-actor.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { extractDbHost, isSelfHost } from '@/misc/convert-host.js'; -import { signedGet } from './request.js'; -import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js'; -import { FollowRequests, Notes, NoteReactions, Polls, Users } from '@/models/index.js'; -import { parseUri } from './db-resolver.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import { renderLike } from '@/remote/activitypub/renderer/like.js'; -import { renderPerson } from '@/remote/activitypub/renderer/person.js'; -import renderQuestion from '@/remote/activitypub/renderer/question.js'; -import renderCreate from '@/remote/activitypub/renderer/create.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import config from "@/config/index.js"; +import { getJson } from "@/misc/fetch.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { getInstanceActor } from "@/services/instance-actor.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { extractDbHost, isSelfHost } from "@/misc/convert-host.js"; +import { signedGet } from "./request.js"; +import type { IObject, ICollection, IOrderedCollection } from "./type.js"; +import { isCollectionOrOrderedCollection, getApId } from "./type.js"; +import { + FollowRequests, + Notes, + NoteReactions, + Polls, + Users, +} from "@/models/index.js"; +import { parseUri } from "./db-resolver.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import { renderLike } from "@/remote/activitypub/renderer/like.js"; +import { renderPerson } from "@/remote/activitypub/renderer/person.js"; +import renderQuestion from "@/remote/activitypub/renderer/question.js"; +import renderCreate from "@/remote/activitypub/renderer/create.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; export default class Resolver { private history: Set; @@ -30,10 +38,10 @@ export default class Resolver { return Array.from(this.history); } - public async resolveCollection(value: string | IObject): Promise { - const collection = typeof value === 'string' - ? await this.resolve(value) - : value; + public async resolveCollection( + value: string | IObject, + ): Promise { + const collection = await this.resolve(value); if (isCollectionOrOrderedCollection(collection)) { return collection; @@ -44,14 +52,20 @@ export default class Resolver { public async resolve(value: string | IObject): Promise { if (value == null) { - throw new Error('resolvee is null (or undefined)'); + throw new Error("resolvee is null (or undefined)"); } - if (typeof value !== 'string') { + if (typeof value !== "string") { + if (typeof value.id !== "undefined") { + const host = extractDbHost(getApId(value)); + if (await shouldBlockInstance(host)) { + throw new Error("instance is blocked"); + } + } return value; } - if (value.includes('#')) { + if (value.includes("#")) { // URLs with fragment parts cannot be resolved correctly because // the fragment part does not get transmitted over HTTP(S). // Avoid strange behaviour by not trying to resolve these at all. @@ -59,10 +73,10 @@ export default class Resolver { } if (this.history.has(value)) { - throw new Error('cannot resolve already resolved one'); + throw new Error("cannot resolve already resolved one"); } if (this.recursionLimit && this.history.size > this.recursionLimit) { - throw new Error('hit recursion limit'); + throw new Error("hit recursion limit"); } this.history.add(value); @@ -72,28 +86,37 @@ export default class Resolver { } const meta = await fetchMeta(); - if (meta.blockedHosts.includes(host)) { - throw new Error('Instance is blocked'); + if (await shouldBlockInstance(host, meta)) { + throw new Error("Instance is blocked"); } - if (meta.privateMode && config.host !== host && !meta.allowedHosts.includes(host)) { - throw new Error('Instance is not allowed'); + if ( + meta.privateMode && + config.host !== host && + !meta.allowedHosts.includes(host) + ) { + throw new Error("Instance is not allowed"); } if (!this.user) { this.user = await getInstanceActor(); } - const object = (this.user - ? await signedGet(value, this.user) - : await getJson(value, 'application/activity+json, application/ld+json')) as IObject; + const object = ( + this.user + ? await signedGet(value, this.user) + : await getJson(value, "application/activity+json, application/ld+json") + ) as IObject; - if (object == null || ( - Array.isArray(object['@context']) ? - !(object['@context'] as unknown[]).includes('https://www.w3.org/ns/activitystreams') : - object['@context'] !== 'https://www.w3.org/ns/activitystreams' - )) { - throw new Error('invalid response'); + if ( + object == null || + (Array.isArray(object["@context"]) + ? !(object["@context"] as unknown[]).includes( + "https://www.w3.org/ns/activitystreams", + ) + : object["@context"] !== "https://www.w3.org/ns/activitystreams") + ) { + throw new Error("invalid response"); } return object; @@ -101,39 +124,44 @@ export default class Resolver { private resolveLocal(url: string): Promise { const parsed = parseUri(url); - if (!parsed.local) throw new Error('resolveLocal: not local'); + if (!parsed.local) throw new Error("resolveLocal: not local"); switch (parsed.type) { - case 'notes': - return Notes.findOneByOrFail({ id: parsed.id }) - .then(note => { - if (parsed.rest === 'activity') { + case "notes": + return Notes.findOneByOrFail({ id: parsed.id }).then((note) => { + if (parsed.rest === "activity") { // this refers to the create activity and not the note itself return renderActivity(renderCreate(renderNote(note))); } else { return renderNote(note); } }); - case 'users': - return Users.findOneByOrFail({ id: parsed.id }) - .then(user => renderPerson(user as ILocalUser)); - case 'questions': + case "users": + return Users.findOneByOrFail({ id: parsed.id }).then((user) => + renderPerson(user as ILocalUser), + ); + case "questions": // Polls are indexed by the note they are attached to. return Promise.all([ Notes.findOneByOrFail({ id: parsed.id }), Polls.findOneByOrFail({ noteId: parsed.id }), - ]) - .then(([note, poll]) => renderQuestion({ id: note.userId }, note, poll)); - case 'likes': - return NoteReactions.findOneByOrFail({ id: parsed.id }).then(reaction => renderActivity(renderLike(reaction, { uri: null }))); - case 'follows': + ]).then(([note, poll]) => + renderQuestion({ id: note.userId }, note, poll), + ); + case "likes": + return NoteReactions.findOneByOrFail({ id: parsed.id }).then( + (reaction) => renderActivity(renderLike(reaction, { uri: null })), + ); + case "follows": // rest should be - if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI'); + if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) + throw new Error("resolveLocal: invalid follow URI"); return Promise.all( - [parsed.id, parsed.rest].map(id => Users.findOneByOrFail({ id })) - ) - .then(([follower, followee]) => renderActivity(renderFollow(follower, followee, url))); + [parsed.id, parsed.rest].map((id) => Users.findOneByOrFail({ id })), + ).then(([follower, followee]) => + renderActivity(renderFollow(follower, followee, url)), + ); default: throw new Error(`resolveLocal: type ${type} unhandled`); } diff --git a/packages/backend/src/remote/activitypub/type.ts b/packages/backend/src/remote/activitypub/type.ts index aabbd0679..b0bdb0a8b 100644 --- a/packages/backend/src/remote/activitypub/type.ts +++ b/packages/backend/src/remote/activitypub/type.ts @@ -2,7 +2,7 @@ export type obj = { [x: string]: any }; export type ApObject = IObject | string | (IObject | string)[]; export interface IObject { - '@context': string | string[] | obj | obj[]; + "@context": string | string[] | obj | obj[]; type: string | string[]; id?: string; summary?: string; @@ -31,7 +31,7 @@ export interface IObject { export function getApIds(value: ApObject | undefined): string[] { if (value == null) return []; const array = Array.isArray(value) ? value : [value]; - return array.map(x => getApId(x)); + return array.map((x) => getApId(x)); } /** @@ -46,28 +46,33 @@ export function getOneApId(value: ApObject): string { * Get ActivityStreams Object id */ export function getApId(value: string | IObject): string { - if (typeof value === 'string') return value; - if (typeof value.id === 'string') return value.id; - throw new Error('cannot detemine id'); + if (typeof value === "string") return value; + if (typeof value.id === "string") return value.id; + throw new Error("cannot detemine id"); } /** * Get ActivityStreams Object type */ export function getApType(value: IObject): string { - if (typeof value.type === 'string') return value.type; - if (Array.isArray(value.type) && typeof value.type[0] === 'string') return value.type[0]; - throw new Error('cannot detect type'); + if (typeof value.type === "string") return value.type; + if (Array.isArray(value.type) && typeof value.type[0] === "string") + return value.type[0]; + throw new Error("cannot detect type"); } -export function getOneApHrefNullable(value: ApObject | undefined): string | undefined { +export function getOneApHrefNullable( + value: ApObject | undefined, +): string | undefined { const firstOne = Array.isArray(value) ? value[0] : value; return getApHrefNullable(firstOne); } -export function getApHrefNullable(value: string | IObject | undefined): string | undefined { - if (typeof value === 'string') return value; - if (typeof value?.href === 'string') return value.href; +export function getApHrefNullable( + value: string | IObject | undefined, +): string | undefined { + if (typeof value === "string") return value; + if (typeof value?.href === "string") return value.href; return undefined; } @@ -88,35 +93,55 @@ export interface IActivity extends IObject { } export interface ICollection extends IObject { - type: 'Collection'; + type: "Collection"; totalItems: number; items: ApObject; } export interface IOrderedCollection extends IObject { - type: 'OrderedCollection'; + type: "OrderedCollection"; totalItems: number; orderedItems: ApObject; } -export const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video', 'Event']; +export const validPost = [ + "Note", + "Question", + "Article", + "Audio", + "Document", + "Image", + "Page", + "Video", + "Event", +]; export const isPost = (object: IObject): object is IPost => validPost.includes(getApType(object)); export interface IPost extends IObject { - type: 'Note' | 'Question' | 'Article' | 'Audio' | 'Document' | 'Image' | 'Page' | 'Video' | 'Event'; + type: + | "Note" + | "Question" + | "Article" + | "Audio" + | "Document" + | "Image" + | "Page" + | "Video" + | "Event"; source?: { content: string; mediaType: string; }; _misskey_quote?: string; quoteUrl?: string; + quoteUri?: string; _misskey_talk: boolean; } export interface IQuestion extends IObject { - type: 'Note' | 'Question'; + type: "Note" | "Question"; source?: { content: string; mediaType: string; @@ -130,7 +155,7 @@ export interface IQuestion extends IObject { } export const isQuestion = (object: IObject): object is IQuestion => - getApType(object) === 'Note' || getApType(object) === 'Question'; + getApType(object) === "Note" || getApType(object) === "Question"; interface IQuestionChoice { name?: string; @@ -138,21 +163,27 @@ interface IQuestionChoice { _misskey_votes?: number; } export interface ITombstone extends IObject { - type: 'Tombstone'; + type: "Tombstone"; formerType?: string; deleted?: Date; } export const isTombstone = (object: IObject): object is ITombstone => - getApType(object) === 'Tombstone'; + getApType(object) === "Tombstone"; -export const validActor = ['Person', 'Service', 'Group', 'Organization', 'Application']; +export const validActor = [ + "Person", + "Service", + "Group", + "Organization", + "Application", +]; export const isActor = (object: IObject): object is IActor => validActor.includes(getApType(object)); export interface IActor extends IObject { - type: 'Person' | 'Service' | 'Organization' | 'Group' | 'Application'; + type: "Person" | "Service" | "Organization" | "Group" | "Application"; name?: string; preferredUsername?: string; manuallyApprovesFollowers?: boolean; @@ -160,7 +191,7 @@ export interface IActor extends IObject { alsoKnownAs?: string[]; discoverable?: boolean; inbox: string; - sharedInbox?: string; // backward compatibility.. ig + sharedInbox?: string; // backward compatibility.. ig publicKey?: { id: string; publicKeyPem: string; @@ -172,21 +203,24 @@ export interface IActor extends IObject { endpoints?: { sharedInbox?: string; }; - 'vcard:bday'?: string; - 'vcard:Address'?: string; + "vcard:bday"?: string; + "vcard:Address"?: string; } export const isCollection = (object: IObject): object is ICollection => - getApType(object) === 'Collection'; + getApType(object) === "Collection"; -export const isOrderedCollection = (object: IObject): object is IOrderedCollection => - getApType(object) === 'OrderedCollection'; +export const isOrderedCollection = ( + object: IObject, +): object is IOrderedCollection => getApType(object) === "OrderedCollection"; -export const isCollectionOrOrderedCollection = (object: IObject): object is ICollection | IOrderedCollection => +export const isCollectionOrOrderedCollection = ( + object: IObject, +): object is ICollection | IOrderedCollection => isCollection(object) || isOrderedCollection(object); export interface IApPropertyValue extends IObject { - type: 'PropertyValue'; + type: "PropertyValue"; identifier: IApPropertyValue; name: string; value: string; @@ -194,110 +228,127 @@ export interface IApPropertyValue extends IObject { export const isPropertyValue = (object: IObject): object is IApPropertyValue => object && - getApType(object) === 'PropertyValue' && - typeof object.name === 'string' && - typeof (object as any).value === 'string'; + getApType(object) === "PropertyValue" && + typeof object.name === "string" && + typeof (object as any).value === "string"; export interface IApMention extends IObject { - type: 'Mention'; + type: "Mention"; href: string; } export const isMention = (object: IObject): object is IApMention => - getApType(object) === 'Mention' && - typeof object.href === 'string'; + getApType(object) === "Mention" && typeof object.href === "string"; export interface IApHashtag extends IObject { - type: 'Hashtag'; + type: "Hashtag"; name: string; } export const isHashtag = (object: IObject): object is IApHashtag => - getApType(object) === 'Hashtag' && - typeof object.name === 'string'; + getApType(object) === "Hashtag" && typeof object.name === "string"; export interface IApEmoji extends IObject { - type: 'Emoji'; + type: "Emoji"; updated: Date; } export const isEmoji = (object: IObject): object is IApEmoji => - getApType(object) === 'Emoji' && !Array.isArray(object.icon) && object.icon.url != null; + getApType(object) === "Emoji" && + !Array.isArray(object.icon) && + object.icon.url != null; export interface ICreate extends IActivity { - type: 'Create'; + type: "Create"; } export interface IDelete extends IActivity { - type: 'Delete'; + type: "Delete"; } export interface IUpdate extends IActivity { - type: 'Update'; + type: "Update"; } export interface IRead extends IActivity { - type: 'Read'; + type: "Read"; } export interface IUndo extends IActivity { - type: 'Undo'; + type: "Undo"; } export interface IFollow extends IActivity { - type: 'Follow'; + type: "Follow"; } export interface IAccept extends IActivity { - type: 'Accept'; + type: "Accept"; } export interface IReject extends IActivity { - type: 'Reject'; + type: "Reject"; } export interface IAdd extends IActivity { - type: 'Add'; + type: "Add"; } export interface IRemove extends IActivity { - type: 'Remove'; + type: "Remove"; } export interface ILike extends IActivity { - type: 'Like' | 'EmojiReaction' | 'EmojiReact'; + type: "Like" | "EmojiReaction" | "EmojiReact"; _misskey_reaction?: string; } export interface IAnnounce extends IActivity { - type: 'Announce'; + type: "Announce"; } export interface IBlock extends IActivity { - type: 'Block'; + type: "Block"; } export interface IFlag extends IActivity { - type: 'Flag'; + type: "Flag"; } export interface IMove extends IActivity { - type: 'Move'; + type: "Move"; target: IObject | string; } -export const isCreate = (object: IObject): object is ICreate => getApType(object) === 'Create'; -export const isDelete = (object: IObject): object is IDelete => getApType(object) === 'Delete'; -export const isUpdate = (object: IObject): object is IUpdate => getApType(object) === 'Update'; -export const isRead = (object: IObject): object is IRead => getApType(object) === 'Read'; -export const isUndo = (object: IObject): object is IUndo => getApType(object) === 'Undo'; -export const isFollow = (object: IObject): object is IFollow => getApType(object) === 'Follow'; -export const isAccept = (object: IObject): object is IAccept => getApType(object) === 'Accept'; -export const isReject = (object: IObject): object is IReject => getApType(object) === 'Reject'; -export const isAdd = (object: IObject): object is IAdd => getApType(object) === 'Add'; -export const isRemove = (object: IObject): object is IRemove => getApType(object) === 'Remove'; -export const isLike = (object: IObject): object is ILike => getApType(object) === 'Like' || getApType(object) === 'EmojiReaction' || getApType(object) === 'EmojiReact'; -export const isAnnounce = (object: IObject): object is IAnnounce => getApType(object) === 'Announce'; -export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block'; -export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag'; -export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move'; +export const isCreate = (object: IObject): object is ICreate => + getApType(object) === "Create"; +export const isDelete = (object: IObject): object is IDelete => + getApType(object) === "Delete"; +export const isUpdate = (object: IObject): object is IUpdate => + getApType(object) === "Update"; +export const isRead = (object: IObject): object is IRead => + getApType(object) === "Read"; +export const isUndo = (object: IObject): object is IUndo => + getApType(object) === "Undo"; +export const isFollow = (object: IObject): object is IFollow => + getApType(object) === "Follow"; +export const isAccept = (object: IObject): object is IAccept => + getApType(object) === "Accept"; +export const isReject = (object: IObject): object is IReject => + getApType(object) === "Reject"; +export const isAdd = (object: IObject): object is IAdd => + getApType(object) === "Add"; +export const isRemove = (object: IObject): object is IRemove => + getApType(object) === "Remove"; +export const isLike = (object: IObject): object is ILike => + getApType(object) === "Like" || + getApType(object) === "EmojiReaction" || + getApType(object) === "EmojiReact"; +export const isAnnounce = (object: IObject): object is IAnnounce => + getApType(object) === "Announce"; +export const isBlock = (object: IObject): object is IBlock => + getApType(object) === "Block"; +export const isFlag = (object: IObject): object is IFlag => + getApType(object) === "Flag"; +export const isMove = (object: IObject): object is IMove => + getApType(object) === "Move"; diff --git a/packages/backend/src/remote/logger.ts b/packages/backend/src/remote/logger.ts index 4921f53bd..b6bc5bf6d 100644 --- a/packages/backend/src/remote/logger.ts +++ b/packages/backend/src/remote/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger.js'; +import Logger from "@/services/logger.js"; -export const remoteLogger = new Logger('remote', 'cyan'); +export const remoteLogger = new Logger("remote", "cyan"); diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts index fe6b65472..a6c1e399a 100644 --- a/packages/backend/src/remote/resolve-user.ts +++ b/packages/backend/src/remote/resolve-user.ts @@ -1,44 +1,54 @@ -import { URL } from 'node:url'; -import chalk from 'chalk'; -import { IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import type { User, IRemoteUser } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; -import { toPuny } from '@/misc/convert-host.js'; -import webFinger from './webfinger.js'; -import { createPerson, updatePerson } from './activitypub/models/person.js'; -import { remoteLogger } from './logger.js'; +import { URL } from "node:url"; +import chalk from "chalk"; +import { IsNull } from "typeorm"; +import config from "@/config/index.js"; +import type { User, IRemoteUser } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; +import { toPuny } from "@/misc/convert-host.js"; +import webFinger from "./webfinger.js"; +import { createPerson, updatePerson } from "./activitypub/models/person.js"; +import { remoteLogger } from "./logger.js"; -const logger = remoteLogger.createSubLogger('resolve-user'); +const logger = remoteLogger.createSubLogger("resolve-user"); -export async function resolveUser(username: string, host: string | null): Promise { +export async function resolveUser( + username: string, + host: string | null, +): Promise { const usernameLower = username.toLowerCase(); if (host == null) { logger.info(`return local user: ${usernameLower}`); - return await Users.findOneBy({ usernameLower, host: IsNull() }).then(u => { - if (u == null) { - throw new Error('user not found'); - } else { - return u; - } - }); + return await Users.findOneBy({ usernameLower, host: IsNull() }).then( + (u) => { + if (u == null) { + throw new Error("user not found"); + } else { + return u; + } + }, + ); } host = toPuny(host); if (config.host === host) { logger.info(`return local user: ${usernameLower}`); - return await Users.findOneBy({ usernameLower, host: IsNull() }).then(u => { - if (u == null) { - throw new Error('user not found'); - } else { - return u; - } - }); + return await Users.findOneBy({ usernameLower, host: IsNull() }).then( + (u) => { + if (u == null) { + throw new Error("user not found"); + } else { + return u; + } + }, + ); } - const user = await Users.findOneBy({ usernameLower, host }) as IRemoteUser | null; + const user = (await Users.findOneBy({ + usernameLower, + host, + })) as IRemoteUser | null; const acctLower = `${usernameLower}@${host}`; @@ -50,7 +60,10 @@ export async function resolveUser(username: string, host: string | null): Promis } // If user information is out of date, return it by starting over from WebFilger - if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { + if ( + user.lastFetchedAt == null || + Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24 + ) { // Prevent multiple attempts to connect to unconnected instances, update before each attempt to prevent subsequent similar attempts await Users.update(user.id, { lastFetchedAt: new Date(), @@ -62,20 +75,25 @@ export async function resolveUser(username: string, host: string | null): Promis if (user.uri !== self.href) { // if uri mismatch, Fix (user@host <=> AP's Person id(IRemoteUser.uri)) mapping. logger.info(`uri missmatch: ${acctLower}`); - logger.info(`recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`); + logger.info( + `recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`, + ); // validate uri const uri = new URL(self.href); if (uri.hostname !== host) { - throw new Error('Invalid uri'); + throw new Error("Invalid uri"); } - await Users.update({ - usernameLower, - host: host, - }, { - uri: self.href, - }); + await Users.update( + { + usernameLower, + host: host, + }, + { + uri: self.href, + }, + ); } else { logger.info(`uri is fine: ${acctLower}`); } @@ -83,9 +101,9 @@ export async function resolveUser(username: string, host: string | null): Promis await updatePerson(self.href); logger.info(`return resynced remote user: ${acctLower}`); - return await Users.findOneBy({ uri: self.href }).then(u => { + return await Users.findOneBy({ uri: self.href }).then((u) => { if (u == null) { - throw new Error('user not found'); + throw new Error("user not found"); } else { return u; } @@ -98,14 +116,24 @@ export async function resolveUser(username: string, host: string | null): Promis async function resolveSelf(acctLower: string) { logger.info(`WebFinger for ${chalk.yellow(acctLower)}`); - const finger = await webFinger(acctLower).catch(e => { - logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ e.statusCode || e.message }`); - throw new Error(`Failed to WebFinger for ${acctLower}: ${ e.statusCode || e.message }`); + const finger = await webFinger(acctLower).catch((e) => { + logger.error( + `Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ + e.statusCode || e.message + }`, + ); + throw new Error( + `Failed to WebFinger for ${acctLower}: ${e.statusCode || e.message}`, + ); }); - const self = finger.links.find(link => link.rel != null && link.rel.toLowerCase() === 'self'); + const self = finger.links.find( + (link) => link.rel != null && link.rel.toLowerCase() === "self", + ); if (!self) { - logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`); - throw new Error('self link not found'); + logger.error( + `Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`, + ); + throw new Error("self link not found"); } return self; } diff --git a/packages/backend/src/remote/webfinger.ts b/packages/backend/src/remote/webfinger.ts index 337df34c2..1e929c8ff 100644 --- a/packages/backend/src/remote/webfinger.ts +++ b/packages/backend/src/remote/webfinger.ts @@ -1,6 +1,6 @@ -import { URL } from 'node:url'; -import { getJson } from '@/misc/fetch.js'; -import { query as urlQuery } from '@/prelude/url.js'; +import { URL } from "node:url"; +import { getJson } from "@/misc/fetch.js"; +import { query as urlQuery } from "@/prelude/url.js"; type ILink = { href: string; @@ -12,22 +12,29 @@ type IWebFinger = { subject: string; }; -export default async function(query: string): Promise { +export default async function (query: string): Promise { const url = genUrl(query); - return await getJson(url, 'application/jrd+json, application/json') as IWebFinger; + return (await getJson( + url, + "application/jrd+json, application/json", + )) as IWebFinger; } function genUrl(query: string) { if (query.match(/^https?:\/\//)) { const u = new URL(query); - return `${u.protocol}//${u.hostname}/.well-known/webfinger?` + urlQuery({ resource: query }); + return `${u.protocol}//${u.hostname}/.well-known/webfinger?${urlQuery({ + resource: query, + })}`; } const m = query.match(/^([^@]+)@(.*)/); if (m) { const hostname = m[2]; - return `https://${hostname}/.well-known/webfinger?` + urlQuery({ resource: `acct:${query}` }); + return `https://${hostname}/.well-known/webfinger?${urlQuery({ + resource: `acct:${query}`, + })}`; } throw new Error(`Invalid query (${query})`); diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index 782915756..29ac726ef 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -1,27 +1,27 @@ -import Router from '@koa/router'; -import json from 'koa-json-body'; -import httpSignature from '@peertube/http-signature'; +import Router from "@koa/router"; +import json from "koa-json-body"; +import httpSignature from "@peertube/http-signature"; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import renderKey from '@/remote/activitypub/renderer/key.js'; -import { renderPerson } from '@/remote/activitypub/renderer/person.js'; -import renderEmoji from '@/remote/activitypub/renderer/emoji.js'; -import Outbox, { packActivity } from './activitypub/outbox.js'; -import Followers from './activitypub/followers.js'; -import Following from './activitypub/following.js'; -import Featured from './activitypub/featured.js'; -import { inbox as processInbox } from '@/queue/index.js'; -import { isSelfHost, toPuny } from '@/misc/convert-host.js'; -import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js'; -import { ILocalUser, User } from '@/models/entities/user.js'; -import { In, IsNull, Not } from 'typeorm'; -import { renderLike } from '@/remote/activitypub/renderer/like.js'; -import { getUserKeypair } from '@/misc/keypair-store.js'; -import checkFetch from '@/remote/activitypub/check-fetch.js'; -import { getInstanceActor } from '@/services/instance-actor.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import { In, IsNull, Not } from "typeorm"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import renderKey from "@/remote/activitypub/renderer/key.js"; +import { renderPerson } from "@/remote/activitypub/renderer/person.js"; +import renderEmoji from "@/remote/activitypub/renderer/emoji.js"; +import { inbox as processInbox } from "@/queue/index.js"; +import { isSelfHost, toPuny } from "@/misc/convert-host.js"; +import { Notes, Users, Emojis, NoteReactions } from "@/models/index.js"; +import type { ILocalUser, User } from "@/models/entities/user.js"; +import { renderLike } from "@/remote/activitypub/renderer/like.js"; +import { getUserKeypair } from "@/misc/keypair-store.js"; +import { checkFetch, hasSignature } from "@/remote/activitypub/check-fetch.js"; +import { getInstanceActor } from "@/services/instance-actor.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import Featured from "./activitypub/featured.js"; +import Following from "./activitypub/following.js"; +import Followers from "./activitypub/followers.js"; +import Outbox, { packActivity } from "./activitypub/outbox.js"; // Init router const router = new Router(); @@ -32,25 +32,25 @@ function inbox(ctx: Router.RouterContext) { let signature; try { - signature = httpSignature.parseRequest(ctx.req, { 'headers': [] }); + signature = httpSignature.parseRequest(ctx.req, { headers: [] }); } catch (e) { ctx.status = 401; return; } - // @ts-ignore processInbox(ctx.request.body, signature); ctx.status = 202; } -const ACTIVITY_JSON = 'application/activity+json; charset=utf-8'; -const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8'; +const ACTIVITY_JSON = "application/activity+json; charset=utf-8"; +const LD_JSON = + 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8'; function isActivityPubReq(ctx: Router.RouterContext) { - ctx.response.vary('Accept'); - const accepted = ctx.accepts('html', ACTIVITY_JSON, LD_JSON); - return typeof accepted === 'string' && !accepted.match(/html/); + ctx.response.vary("Accept"); + const accepted = ctx.accepts("html", ACTIVITY_JSON, LD_JSON); + return typeof accepted === "string" && !accepted.match(/html/); } export function setResponseType(ctx: Router.RouterContext) { @@ -63,22 +63,22 @@ export function setResponseType(ctx: Router.RouterContext) { } // inbox -router.post('/inbox', json(), inbox); -router.post('/users/:user/inbox', json(), inbox); +router.post("/inbox", json(), inbox); +router.post("/users/:user/inbox", json(), inbox); // note -router.get('/notes/:note', async (ctx, next) => { +router.get("/notes/:note", async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } const note = await Notes.findOneBy({ id: ctx.params.note, - visibility: In(['public' as const, 'home' as const]), + visibility: In(["public" as const, "home" as const]), localOnly: false, }); @@ -88,7 +88,7 @@ router.get('/notes/:note', async (ctx, next) => { } // redirect if remote - if (note.userHost != null) { + if (note.userHost !== null) { if (note.uri == null || isSelfHost(note.userHost)) { ctx.status = 500; return; @@ -101,17 +101,17 @@ router.get('/notes/:note', async (ctx, next) => { const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }); // note activity -router.get('/notes/:note/activity', async ctx => { +router.get("/notes/:note/activity", async (ctx) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -119,7 +119,7 @@ router.get('/notes/:note/activity', async ctx => { const note = await Notes.findOneBy({ id: ctx.params.note, userHost: IsNull(), - visibility: In(['public' as const, 'home' as const]), + visibility: In(["public" as const, "home" as const]), localOnly: false, }); @@ -131,37 +131,39 @@ router.get('/notes/:note/activity', async ctx => { ctx.body = renderActivity(await packActivity(note)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }); // outbox -router.get('/users/:user/outbox', Outbox); +router.get("/users/:user/outbox", Outbox); // followers -router.get('/users/:user/followers', Followers); +router.get("/users/:user/followers", Followers); // following -router.get('/users/:user/following', Following); +router.get("/users/:user/following", Following); // featured -router.get('/users/:user/collections/featured', Featured); +router.get("/users/:user/collections/featured", Featured); // publickey -router.get('/users/:user/publickey', async ctx => { +router.get("/users/:user/publickey", async (ctx) => { const instanceActor = await getInstanceActor(); if (ctx.params.user === instanceActor.id) { - ctx.body = renderActivity(renderKey(instanceActor, await getUserKeypair(instanceActor.id))); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.body = renderActivity( + renderKey(instanceActor, await getUserKeypair(instanceActor.id)), + ); + ctx.set("Cache-Control", "public, max-age=180"); setResponseType(ctx); return; } const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -184,9 +186,9 @@ router.get('/users/:user/publickey', async ctx => { ctx.body = renderActivity(renderKey(user, keypair)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); } else { @@ -204,14 +206,14 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) { ctx.body = renderActivity(await renderPerson(user as ILocalUser)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); } -router.get('/users/:user', async (ctx, next) => { +router.get("/users/:user", async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); const instanceActor = await getInstanceActor(); @@ -221,7 +223,7 @@ router.get('/users/:user', async (ctx, next) => { } const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -237,17 +239,17 @@ router.get('/users/:user', async (ctx, next) => { await userInfo(ctx, user); }); -router.get('/@:user', async (ctx, next) => { +router.get("/@:user", async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); - if (ctx.params.user === 'instance.actor') { + if (ctx.params.user === "instance.actor") { const instanceActor = await getInstanceActor(); await userInfo(ctx, instanceActor); return; } const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -261,16 +263,16 @@ router.get('/@:user', async (ctx, next) => { await userInfo(ctx, user); }); -router.get('/actor', async (ctx, next) => { +router.get("/actor", async (ctx, next) => { const instanceActor = await getInstanceActor(); await userInfo(ctx, instanceActor); }); //#endregion // emoji -router.get('/emojis/:emoji', async ctx => { +router.get("/emojis/:emoji", async (ctx) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -288,17 +290,17 @@ router.get('/emojis/:emoji', async ctx => { ctx.body = renderActivity(await renderEmoji(emoji)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }); // like -router.get('/likes/:like', async ctx => { +router.get("/likes/:like", async (ctx) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -320,17 +322,17 @@ router.get('/likes/:like', async ctx => { ctx.body = renderActivity(await renderLike(reaction, note)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }); // follow -router.get('/follows/:follower/:followee', async ctx => { +router.get("/follows/:follower/:followee", async (ctx) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -356,9 +358,9 @@ router.get('/follows/:follower/:followee', async ctx => { ctx.body = renderActivity(renderFollow(follower, followee)); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }); diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index 87e4f8320..82bb19fa1 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -1,17 +1,17 @@ -import Router from '@koa/router'; -import config from '@/config/index.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; -import { setResponseType } from '../activitypub.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import { Users, Notes, UserNotePinings } from '@/models/index.js'; -import { IsNull } from 'typeorm'; -import checkFetch from '@/remote/activitypub/check-fetch.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { IsNull } from "typeorm"; +import config from "@/config/index.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import { Users, Notes, UserNotePinings } from "@/models/index.js"; +import { checkFetch } from "@/remote/activitypub/check-fetch.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { setResponseType } from "../activitypub.js"; +import type Router from "@koa/router"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -30,26 +30,32 @@ export default async (ctx: Router.RouterContext) => { const pinings = await UserNotePinings.find({ where: { userId: user.id }, - order: { id: 'DESC' }, + order: { id: "DESC" }, }); - const pinnedNotes = await Promise.all(pinings.map(pining => - Notes.findOneByOrFail({ id: pining.noteId }))); + const pinnedNotes = await Promise.all( + pinings.map((pining) => Notes.findOneByOrFail({ id: pining.noteId })), + ); - const renderedNotes = await Promise.all(pinnedNotes.map(note => renderNote(note))); + const renderedNotes = await Promise.all( + pinnedNotes.map((note) => renderNote(note)), + ); const rendered = renderOrderedCollection( `${config.url}/users/${userId}/collections/featured`, - renderedNotes.length, undefined, undefined, renderedNotes, + renderedNotes.length, + undefined, + undefined, + renderedNotes, ); ctx.body = renderActivity(rendered); const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } setResponseType(ctx); }; diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index 833f0e77f..146ca5192 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -1,20 +1,21 @@ -import Router from '@koa/router'; -import { FindOptionsWhere, IsNull, LessThan } from 'typeorm'; -import config from '@/config/index.js'; -import * as url from '@/prelude/url.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; -import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; -import { Users, Followings, UserProfiles } from '@/models/index.js'; -import { Following } from '@/models/entities/following.js'; -import { setResponseType } from '../activitypub.js'; -import checkFetch from '@/remote/activitypub/check-fetch.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { IsNull, LessThan } from "typeorm"; +import config from "@/config/index.js"; +import * as url from "@/prelude/url.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; +import renderOrderedCollectionPage from "@/remote/activitypub/renderer/ordered-collection-page.js"; +import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; +import { Users, Followings, UserProfiles } from "@/models/index.js"; +import type { Following } from "@/models/entities/following.js"; +import { checkFetch } from "@/remote/activitypub/check-fetch.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { setResponseType } from "../activitypub.js"; +import type { FindOptionsWhere } from "typeorm"; +import type Router from "@koa/router"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -22,12 +23,12 @@ export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; const cursor = ctx.request.query.cursor; - if (cursor != null && typeof cursor !== 'string') { + if (cursor != null && typeof cursor !== "string") { ctx.status = 400; return; } - const page = ctx.request.query.page === 'true'; + const page = ctx.request.query.page === "true"; const user = await Users.findOneBy({ id: userId, @@ -42,13 +43,13 @@ export default async (ctx: Router.RouterContext) => { //#region Check ff visibility const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.ffVisibility === "private") { ctx.status = 403; - ctx.set('Cache-Control', 'public, max-age=30'); + ctx.set("Cache-Control", "public, max-age=30"); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.ffVisibility === "followers") { ctx.status = 403; - ctx.set('Cache-Control', 'public, max-age=30'); + ctx.set("Cache-Control", "public, max-age=30"); return; } //#endregion @@ -77,32 +78,42 @@ export default async (ctx: Router.RouterContext) => { const inStock = followings.length === limit + 1; if (inStock) followings.pop(); - const renderedFollowers = await Promise.all(followings.map(following => renderFollowUser(following.followerId))); + const renderedFollowers = await Promise.all( + followings.map((following) => renderFollowUser(following.followerId)), + ); const rendered = renderOrderedCollectionPage( `${partOf}?${url.query({ - page: 'true', + page: "true", cursor, })}`, - user.followersCount, renderedFollowers, partOf, + user.followersCount, + renderedFollowers, + partOf, undefined, - inStock ? `${partOf}?${url.query({ - page: 'true', - cursor: followings[followings.length - 1].id, - })}` : undefined, + inStock + ? `${partOf}?${url.query({ + page: "true", + cursor: followings[followings.length - 1].id, + })}` + : undefined, ); ctx.body = renderActivity(rendered); setResponseType(ctx); } else { // index page - const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`); + const rendered = renderOrderedCollection( + partOf, + user.followersCount, + `${partOf}?page=true`, + ); ctx.body = renderActivity(rendered); setResponseType(ctx); } const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } }; diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index 26cee819b..eab513ce6 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -1,20 +1,21 @@ -import Router from '@koa/router'; -import { LessThan, IsNull, FindOptionsWhere } from 'typeorm'; -import config from '@/config/index.js'; -import * as url from '@/prelude/url.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; -import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; -import { Users, Followings, UserProfiles } from '@/models/index.js'; -import { Following } from '@/models/entities/following.js'; -import { setResponseType } from '../activitypub.js'; -import checkFetch from '@/remote/activitypub/check-fetch.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { LessThan, IsNull } from "typeorm"; +import config from "@/config/index.js"; +import * as url from "@/prelude/url.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; +import renderOrderedCollectionPage from "@/remote/activitypub/renderer/ordered-collection-page.js"; +import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; +import { Users, Followings, UserProfiles } from "@/models/index.js"; +import type { Following } from "@/models/entities/following.js"; +import { checkFetch } from "@/remote/activitypub/check-fetch.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { setResponseType } from "../activitypub.js"; +import type { FindOptionsWhere } from "typeorm"; +import type Router from "@koa/router"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -22,12 +23,12 @@ export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; const cursor = ctx.request.query.cursor; - if (cursor != null && typeof cursor !== 'string') { + if (cursor != null && typeof cursor !== "string") { ctx.status = 400; return; } - const page = ctx.request.query.page === 'true'; + const page = ctx.request.query.page === "true"; const user = await Users.findOneBy({ id: userId, @@ -42,13 +43,13 @@ export default async (ctx: Router.RouterContext) => { //#region Check ff visibility const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.ffVisibility === "private") { ctx.status = 403; - ctx.set('Cache-Control', 'public, max-age=30'); + ctx.set("Cache-Control", "public, max-age=30"); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.ffVisibility === "followers") { ctx.status = 403; - ctx.set('Cache-Control', 'public, max-age=30'); + ctx.set("Cache-Control", "public, max-age=30"); return; } //#endregion @@ -77,32 +78,42 @@ export default async (ctx: Router.RouterContext) => { const inStock = followings.length === limit + 1; if (inStock) followings.pop(); - const renderedFollowees = await Promise.all(followings.map(following => renderFollowUser(following.followeeId))); + const renderedFollowees = await Promise.all( + followings.map((following) => renderFollowUser(following.followeeId)), + ); const rendered = renderOrderedCollectionPage( `${partOf}?${url.query({ - page: 'true', + page: "true", cursor, })}`, - user.followingCount, renderedFollowees, partOf, + user.followingCount, + renderedFollowees, + partOf, undefined, - inStock ? `${partOf}?${url.query({ - page: 'true', - cursor: followings[followings.length - 1].id, - })}` : undefined, + inStock + ? `${partOf}?${url.query({ + page: "true", + cursor: followings[followings.length - 1].id, + })}` + : undefined, ); ctx.body = renderActivity(rendered); setResponseType(ctx); } else { // index page - const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`); + const rendered = renderOrderedCollection( + partOf, + user.followingCount, + `${partOf}?page=true`, + ); ctx.body = renderActivity(rendered); setResponseType(ctx); } const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } }; diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index 4a6b5caff..e0a380ffb 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -1,24 +1,24 @@ -import Router from '@koa/router'; -import { Brackets, IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import renderCreate from '@/remote/activitypub/renderer/create.js'; -import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; -import { countIf } from '@/prelude/array.js'; -import * as url from '@/prelude/url.js'; -import { Users, Notes } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { makePaginationQuery } from '../api/common/make-pagination-query.js'; -import { setResponseType } from '../activitypub.js'; -import checkFetch from '@/remote/activitypub/check-fetch.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Brackets, IsNull } from "typeorm"; +import config from "@/config/index.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; +import renderOrderedCollectionPage from "@/remote/activitypub/renderer/ordered-collection-page.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import renderCreate from "@/remote/activitypub/renderer/create.js"; +import renderAnnounce from "@/remote/activitypub/renderer/announce.js"; +import { countIf } from "@/prelude/array.js"; +import * as url from "@/prelude/url.js"; +import { Users, Notes } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import { checkFetch } from "@/remote/activitypub/check-fetch.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { makePaginationQuery } from "../api/common/make-pagination-query.js"; +import { setResponseType } from "../activitypub.js"; +import type Router from "@koa/router"; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); - if (verify != 200) { + if (verify !== 200) { ctx.status = verify; return; } @@ -26,20 +26,20 @@ export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; const sinceId = ctx.request.query.since_id; - if (sinceId != null && typeof sinceId !== 'string') { + if (sinceId != null && typeof sinceId !== "string") { ctx.status = 400; return; } const untilId = ctx.request.query.until_id; - if (untilId != null && typeof untilId !== 'string') { + if (untilId != null && typeof untilId !== "string") { ctx.status = 400; return; } - const page = ctx.request.query.page === 'true'; + const page = ctx.request.query.page === "true"; - if (countIf(x => x != null, [sinceId, untilId]) > 1) { + if (countIf((x) => x != null, [sinceId, untilId]) > 1) { ctx.status = 400; return; } @@ -58,41 +58,58 @@ export default async (ctx: Router.RouterContext) => { const partOf = `${config.url}/users/${userId}/outbox`; if (page) { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), sinceId, untilId) - .andWhere('note.userId = :userId', { userId: user.id }) - .andWhere(new Brackets(qb => { qb - .where('note.visibility = \'public\'') - .orWhere('note.visibility = \'home\''); - })) - .andWhere('note.localOnly = FALSE'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + sinceId, + untilId, + ) + .andWhere("note.userId = :userId", { userId: user.id }) + .andWhere( + new Brackets((qb) => { + qb.where("note.visibility = 'public'").orWhere( + "note.visibility = 'home'", + ); + }), + ) + .andWhere("note.localOnly = FALSE"); const notes = await query.take(limit).getMany(); if (sinceId) notes.reverse(); - const activities = await Promise.all(notes.map(note => packActivity(note))); + const activities = await Promise.all( + notes.map((note) => packActivity(note)), + ); const rendered = renderOrderedCollectionPage( `${partOf}?${url.query({ - page: 'true', + page: "true", since_id: sinceId, until_id: untilId, })}`, - user.notesCount, activities, partOf, - notes.length ? `${partOf}?${url.query({ - page: 'true', - since_id: notes[0].id, - })}` : undefined, - notes.length ? `${partOf}?${url.query({ - page: 'true', - until_id: notes[notes.length - 1].id, - })}` : undefined, + user.notesCount, + activities, + partOf, + notes.length + ? `${partOf}?${url.query({ + page: "true", + since_id: notes[0].id, + })}` + : undefined, + notes.length + ? `${partOf}?${url.query({ + page: "true", + until_id: notes[notes.length - 1].id, + })}` + : undefined, ); ctx.body = renderActivity(rendered); setResponseType(ctx); } else { // index page - const rendered = renderOrderedCollection(partOf, user.notesCount, + const rendered = renderOrderedCollection( + partOf, + user.notesCount, `${partOf}?page=true`, `${partOf}?page=true&since_id=000000000000000000000000`, ); @@ -102,9 +119,9 @@ export default async (ctx: Router.RouterContext) => { } const meta = await fetchMeta(); if (meta.secureMode || meta.privateMode) { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set("Cache-Control", "public, max-age=180"); } }; @@ -113,9 +130,17 @@ export default async (ctx: Router.RouterContext) => { * @param note Note */ export async function packActivity(note: Note): Promise { - if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { + if ( + note.renoteId && + note.text == null && + !note.hasPoll && + (note.fileIds == null || note.fileIds.length === 0) + ) { const renote = await Notes.findOneByOrFail({ id: note.renoteId }); - return renderAnnounce(renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note); + return renderAnnounce( + renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, + note, + ); } return renderCreate(await renderNote(note, false), note); diff --git a/packages/backend/src/server/api/2fa.ts b/packages/backend/src/server/api/2fa.ts index 96b9316e4..7318f0f43 100644 --- a/packages/backend/src/server/api/2fa.ts +++ b/packages/backend/src/server/api/2fa.ts @@ -1,12 +1,12 @@ -import * as crypto from 'node:crypto'; -import * as jsrsasign from 'jsrsasign'; -import config from '@/config/index.js'; +import * as crypto from "node:crypto"; +import * as jsrsasign from "jsrsasign"; +import config from "@/config/index.js"; const ECC_PRELUDE = Buffer.from([0x04]); const NULL_BYTE = Buffer.from([0]); const PEM_PRELUDE = Buffer.from( - '3059301306072a8648ce3d020106082a8648ce3d030107034200', - 'hex', + "3059301306072a8648ce3d020106082a8648ce3d030107034200", + "hex", ); // Android Safetynet attestations are signed with this cert: @@ -34,7 +34,7 @@ TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE-----\n`; function base64URLDecode(source: string) { - return Buffer.from(source.replace(/\-/g, '+').replace(/_/g, '/'), 'base64'); + return Buffer.from(source.replace(/\-/g, "+").replace(/_/g, "/"), "base64"); } function getCertSubject(certificate: string) { @@ -42,11 +42,11 @@ function getCertSubject(certificate: string) { subjectCert.readCertPEM(certificate); const subjectString = subjectCert.getSubjectString(); - const subjectFields = subjectString.slice(1).split('/'); + const subjectFields = subjectString.slice(1).split("/"); const fields = {} as Record; for (const field of subjectFields) { - const eqIndex = field.indexOf('='); + const eqIndex = field.indexOf("="); fields[field.substring(0, eqIndex)] = field.substring(eqIndex + 1); } @@ -77,12 +77,12 @@ function verifyCertificateChain(certificates: string[]) { return valid; } -function PEMString(pemBuffer: Buffer, type = 'CERTIFICATE') { +function PEMString(pemBuffer: Buffer, type = "CERTIFICATE") { if (pemBuffer.length === 65 && pemBuffer[0] === 0x04) { pemBuffer = Buffer.concat([PEM_PRELUDE, pemBuffer], 91); - type = 'PUBLIC KEY'; + type = "PUBLIC KEY"; } - const cert = pemBuffer.toString('base64'); + const cert = pemBuffer.toString("base64"); const keyParts = []; const max = Math.ceil(cert.length / 64); @@ -92,18 +92,13 @@ function PEMString(pemBuffer: Buffer, type = 'CERTIFICATE') { start += 64; } - return ( - `-----BEGIN ${type}-----\n` + - keyParts.join('\n') + - `\n-----END ${type}-----\n` - ); + return `-----BEGIN ${type}-----\n${keyParts.join( + "\n", + )}\n-----END ${type}-----\n`; } export function hash(data: Buffer) { - return crypto - .createHash('sha256') - .update(data) - .digest(); + return crypto.createHash("sha256").update(data).digest(); } export function verifyLogin({ @@ -114,22 +109,22 @@ export function verifyLogin({ signature, challenge, }: { - publicKey: Buffer, - authenticatorData: Buffer, - clientDataJSON: Buffer, - clientData: any, - signature: Buffer, - challenge: string + publicKey: Buffer; + authenticatorData: Buffer; + clientDataJSON: Buffer; + clientData: any; + signature: Buffer; + challenge: string; }) { - if (clientData.type !== 'webauthn.get') { - throw new Error('type is not webauthn.get'); + if (clientData.type !== "webauthn.get") { + throw new Error("type is not webauthn.get"); } - if (hash(clientData.challenge).toString('hex') !== challenge) { - throw new Error('challenge mismatch'); + if (hash(clientData.challenge).toString("hex") !== challenge) { + throw new Error("challenge mismatch"); } - if (clientData.origin !== config.scheme + '://' + config.host) { - throw new Error('origin mismatch'); + if (clientData.origin !== `${config.scheme}://${config.host}`) { + throw new Error("origin mismatch"); } const verificationData = Buffer.concat( @@ -138,7 +133,7 @@ export function verifyLogin({ ); return crypto - .createVerify('SHA256') + .createVerify("SHA256") .update(verificationData) .verify(PEMString(publicKey), signature); } @@ -149,11 +144,11 @@ export const procedures = { const negTwo = publicKey.get(-2); if (!negTwo || negTwo.length !== 32) { - throw new Error('invalid or no -2 key given'); + throw new Error("invalid or no -2 key given"); } const negThree = publicKey.get(-3); if (!negThree || negThree.length !== 32) { - throw new Error('invalid or no -3 key given'); + throw new Error("invalid or no -3 key given"); } const publicKeyU2F = Buffer.concat( @@ -167,7 +162,7 @@ export const procedures = { }; }, }, - 'android-key': { + "android-key": { verify({ attStmt, authenticatorData, @@ -176,15 +171,15 @@ export const procedures = { rpIdHash, credentialId, }: { - attStmt: any, - authenticatorData: Buffer, - clientDataHash: Buffer, + attStmt: any; + authenticatorData: Buffer; + clientDataHash: Buffer; publicKey: Map; - rpIdHash: Buffer, - credentialId: Buffer, + rpIdHash: Buffer; + credentialId: Buffer; }) { if (attStmt.alg !== -7) { - throw new Error('alg mismatch'); + throw new Error("alg mismatch"); } const verificationData = Buffer.concat([ @@ -197,11 +192,11 @@ export const procedures = { const negTwo = publicKey.get(-2); if (!negTwo || negTwo.length !== 32) { - throw new Error('invalid or no -2 key given'); + throw new Error("invalid or no -2 key given"); } const negThree = publicKey.get(-3); if (!negThree || negThree.length !== 32) { - throw new Error('invalid or no -3 key given'); + throw new Error("invalid or no -3 key given"); } const publicKeyData = Buffer.concat( @@ -210,11 +205,11 @@ export const procedures = { ); if (!attCert.equals(publicKeyData)) { - throw new Error('public key mismatch'); + throw new Error("public key mismatch"); } const isValid = crypto - .createVerify('SHA256') + .createVerify("SHA256") .update(verificationData) .verify(PEMString(attCert), attStmt.sig); @@ -227,7 +222,7 @@ export const procedures = { }, }, // what a stupid attestation - 'android-safetynet': { + "android-safetynet": { verify({ attStmt, authenticatorData, @@ -236,59 +231,59 @@ export const procedures = { rpIdHash, credentialId, }: { - attStmt: any, - authenticatorData: Buffer, - clientDataHash: Buffer, + attStmt: any; + authenticatorData: Buffer; + clientDataHash: Buffer; publicKey: Map; - rpIdHash: Buffer, - credentialId: Buffer, + rpIdHash: Buffer; + credentialId: Buffer; }) { const verificationData = hash( Buffer.concat([authenticatorData, clientDataHash]), ); - const jwsParts = attStmt.response.toString('utf-8').split('.'); + const jwsParts = attStmt.response.toString("utf-8").split("."); - const header = JSON.parse(base64URLDecode(jwsParts[0]).toString('utf-8')); + const header = JSON.parse(base64URLDecode(jwsParts[0]).toString("utf-8")); const response = JSON.parse( - base64URLDecode(jwsParts[1]).toString('utf-8'), + base64URLDecode(jwsParts[1]).toString("utf-8"), ); const signature = jwsParts[2]; - if (!verificationData.equals(Buffer.from(response.nonce, 'base64'))) { - throw new Error('invalid nonce'); + if (!verificationData.equals(Buffer.from(response.nonce, "base64"))) { + throw new Error("invalid nonce"); } const certificateChain = header.x5c .map((key: any) => PEMString(key)) .concat([GSR2]); - if (getCertSubject(certificateChain[0]).CN !== 'attest.android.com') { - throw new Error('invalid common name'); + if (getCertSubject(certificateChain[0]).CN !== "attest.android.com") { + throw new Error("invalid common name"); } if (!verifyCertificateChain(certificateChain)) { - throw new Error('Invalid certificate chain!'); + throw new Error("Invalid certificate chain!"); } const signatureBase = Buffer.from( - jwsParts[0] + '.' + jwsParts[1], - 'utf-8', + `${jwsParts[0]}.${jwsParts[1]}`, + "utf-8", ); const valid = crypto - .createVerify('sha256') + .createVerify("sha256") .update(signatureBase) .verify(certificateChain[0], base64URLDecode(signature)); const negTwo = publicKey.get(-2); if (!negTwo || negTwo.length !== 32) { - throw new Error('invalid or no -2 key given'); + throw new Error("invalid or no -2 key given"); } const negThree = publicKey.get(-3); if (!negThree || negThree.length !== 32) { - throw new Error('invalid or no -3 key given'); + throw new Error("invalid or no -3 key given"); } const publicKeyData = Buffer.concat( @@ -310,12 +305,12 @@ export const procedures = { rpIdHash, credentialId, }: { - attStmt: any, - authenticatorData: Buffer, - clientDataHash: Buffer, + attStmt: any; + authenticatorData: Buffer; + clientDataHash: Buffer; publicKey: Map; - rpIdHash: Buffer, - credentialId: Buffer, + rpIdHash: Buffer; + credentialId: Buffer; }) { const verificationData = Buffer.concat([ authenticatorData, @@ -326,18 +321,18 @@ export const procedures = { const attCert = attStmt.x5c[0]; const validSignature = crypto - .createVerify('SHA256') + .createVerify("SHA256") .update(verificationData) .verify(PEMString(attCert), attStmt.sig); const negTwo = publicKey.get(-2); if (!negTwo || negTwo.length !== 32) { - throw new Error('invalid or no -2 key given'); + throw new Error("invalid or no -2 key given"); } const negThree = publicKey.get(-3); if (!negThree || negThree.length !== 32) { - throw new Error('invalid or no -3 key given'); + throw new Error("invalid or no -3 key given"); } const publicKeyData = Buffer.concat( @@ -351,16 +346,16 @@ export const procedures = { }; } else if (attStmt.ecdaaKeyId) { // https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-ecdaa-algorithm-v2.0-id-20180227.html#ecdaa-verify-operation - throw new Error('ECDAA-Verify is not supported'); + throw new Error("ECDAA-Verify is not supported"); } else { - if (attStmt.alg !== -7) throw new Error('alg mismatch'); + if (attStmt.alg !== -7) throw new Error("alg mismatch"); - throw new Error('self attestation is not supported'); + throw new Error("self attestation is not supported"); } }, }, - 'fido-u2f': { + "fido-u2f": { verify({ attStmt, authenticatorData, @@ -369,16 +364,16 @@ export const procedures = { rpIdHash, credentialId, }: { - attStmt: any, - authenticatorData: Buffer, - clientDataHash: Buffer, - publicKey: Map, - rpIdHash: Buffer, - credentialId: Buffer + attStmt: any; + authenticatorData: Buffer; + clientDataHash: Buffer; + publicKey: Map; + rpIdHash: Buffer; + credentialId: Buffer; }) { const x5c: Buffer[] = attStmt.x5c; if (x5c.length !== 1) { - throw new Error('x5c length does not match expectation'); + throw new Error("x5c length does not match expectation"); } const attCert = x5c[0]; @@ -388,11 +383,11 @@ export const procedures = { const negTwo: Buffer = publicKey.get(-2); if (!negTwo || negTwo.length !== 32) { - throw new Error('invalid or no -2 key given'); + throw new Error("invalid or no -2 key given"); } const negThree: Buffer = publicKey.get(-3); if (!negThree || negThree.length !== 32) { - throw new Error('invalid or no -3 key given'); + throw new Error("invalid or no -3 key given"); } const publicKeyU2F = Buffer.concat( @@ -409,7 +404,7 @@ export const procedures = { ]); const validSignature = crypto - .createVerify('SHA256') + .createVerify("SHA256") .update(verificationData) .verify(PEMString(attCert), attStmt.sig); diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index 3cb94f10f..99a12fd11 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -1,97 +1,123 @@ -import Koa from 'koa'; +import type Koa from "koa"; -import { User } from '@/models/entities/user.js'; -import { UserIps } from '@/models/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { IEndpoint } from './endpoints.js'; -import authenticate, { AuthenticationError } from './authenticate.js'; -import call from './call.js'; -import { ApiError } from './error.js'; +import type { User } from "@/models/entities/user.js"; +import { UserIps } from "@/models/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import type { IEndpoint } from "./endpoints.js"; +import authenticate, { AuthenticationError } from "./authenticate.js"; +import call from "./call.js"; +import { ApiError } from "./error.js"; -const userIpHistories = new Map>(); +const userIpHistories = new Map>(); setInterval(() => { userIpHistories.clear(); }, 1000 * 60 * 60); -export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { - const body = ctx.is('multipart/form-data') - ? (ctx.request as any).body - : ctx.method === 'GET' +export default (endpoint: IEndpoint, ctx: Koa.Context) => + new Promise((res) => { + const body = ctx.is("multipart/form-data") + ? (ctx.request as any).body + : ctx.method === "GET" ? ctx.query : ctx.request.body; - const reply = (x?: any, y?: ApiError) => { - if (x == null) { - ctx.status = 204; - } else if (typeof x === 'number' && y) { - ctx.status = x; - ctx.body = { - error: { - message: y!.message, - code: y!.code, - id: y!.id, - kind: y!.kind, - ...(y!.info ? { info: y!.info } : {}), - }, - }; - } else { - // 文字列を返す場合は、JSON.stringify通さないとJSONと認識されない - ctx.body = typeof x === 'string' ? JSON.stringify(x) : x; - } - res(); - }; - - // Authentication - // for GET requests, do not even pass on the body parameter as it is considered unsafe - authenticate(ctx.headers.authorization, ctx.method === 'GET' ? null : body['i']).then(([user, app]) => { - // API invoking - call(endpoint.name, user, app, body, ctx).then((res: any) => { - if (ctx.method === 'GET' && endpoint.meta.cacheSec && !body['i'] && !user) { - ctx.set('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`); + const reply = (x?: any, y?: ApiError) => { + if (x == null) { + ctx.status = 204; + } else if (typeof x === "number" && y) { + ctx.status = x; + ctx.body = { + error: { + message: y!.message, + code: y!.code, + id: y!.id, + kind: y!.kind, + ...(y!.info ? { info: y!.info } : {}), + }, + }; + } else { + // 文字列を返す場合は、JSON.stringify通さないとJSONと認識されない + ctx.body = typeof x === "string" ? JSON.stringify(x) : x; } - reply(res); - }).catch((e: ApiError) => { - reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e); - }); + res(); + }; - // Log IP - if (user) { - fetchMeta().then(meta => { - if (!meta.enableIpLogging) return; - const ip = ctx.ip; - const ips = userIpHistories.get(user.id); - if (ips == null || !ips.has(ip)) { - if (ips == null) { - userIpHistories.set(user.id, new Set([ip])); - } else { - ips.add(ip); - } + // Authentication + // for GET requests, do not even pass on the body parameter as it is considered unsafe + authenticate( + ctx.headers.authorization, + ctx.method === "GET" ? null : body["i"], + ) + .then(([user, app]) => { + // API invoking + call(endpoint.name, user, app, body, ctx) + .then((res: any) => { + if ( + ctx.method === "GET" && + endpoint.meta.cacheSec && + !body["i"] && + !user + ) { + ctx.set( + "Cache-Control", + `public, max-age=${endpoint.meta.cacheSec}`, + ); + } + reply(res); + }) + .catch((e: ApiError) => { + reply( + e.httpStatusCode + ? e.httpStatusCode + : e.kind === "client" + ? 400 + : 500, + e, + ); + }); - try { - UserIps.createQueryBuilder().insert().values({ - createdAt: new Date(), - userId: user.id, - ip: ip, - }).orIgnore(true).execute(); - } catch { - } + // Log IP + if (user) { + fetchMeta().then((meta) => { + if (!meta.enableIpLogging) return; + const ip = ctx.ip; + const ips = userIpHistories.get(user.id); + if (ips == null || !ips.has(ip)) { + if (ips == null) { + userIpHistories.set(user.id, new Set([ip])); + } else { + ips.add(ip); + } + + try { + UserIps.createQueryBuilder() + .insert() + .values({ + createdAt: new Date(), + userId: user.id, + ip: ip, + }) + .orIgnore(true) + .execute(); + } catch {} + } + }); + } + }) + .catch((e) => { + if (e instanceof AuthenticationError) { + ctx.response.status = 403; + ctx.response.set("WWW-Authenticate", "Bearer"); + ctx.response.body = { + message: `Authentication failed: ${e.message}`, + code: "AUTHENTICATION_FAILED", + id: "b0a7f5f8-dc2f-4171-b91f-de88ad238e14", + kind: "client", + }; + res(); + } else { + reply(500, new ApiError()); } }); - } - }).catch(e => { - if (e instanceof AuthenticationError) { - ctx.response.status = 403; - ctx.response.set('WWW-Authenticate', 'Bearer'); - ctx.response.body = { - message: 'Authentication failed: ' + e.message, - code: 'AUTHENTICATION_FAILED', - id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14', - kind: 'client', - }; - res(); - } else { - reply(500, new ApiError()); - } }); -}); diff --git a/packages/backend/src/server/api/authenticate.ts b/packages/backend/src/server/api/authenticate.ts index 39be06c29..42274ad2a 100644 --- a/packages/backend/src/server/api/authenticate.ts +++ b/packages/backend/src/server/api/authenticate.ts @@ -1,35 +1,43 @@ -import isNativeToken from './common/is-native-token.js'; -import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js'; -import { Users, AccessTokens, Apps } from '@/models/index.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { Cache } from '@/misc/cache.js'; -import { App } from '@/models/entities/app.js'; -import { localUserByIdCache, localUserByNativeTokenCache } from '@/services/user-cache.js'; +import isNativeToken from "./common/is-native-token.js"; +import type { CacheableLocalUser, ILocalUser } from "@/models/entities/user.js"; +import { Users, AccessTokens, Apps } from "@/models/index.js"; +import type { AccessToken } from "@/models/entities/access-token.js"; +import { Cache } from "@/misc/cache.js"; +import type { App } from "@/models/entities/app.js"; +import { + localUserByIdCache, + localUserByNativeTokenCache, +} from "@/services/user-cache.js"; const appCache = new Cache(Infinity); export class AuthenticationError extends Error { constructor(message: string) { super(message); - this.name = 'AuthenticationError'; + this.name = "AuthenticationError"; } } -export default async (authorization: string | null | undefined, bodyToken: string | null): Promise<[CacheableLocalUser | null | undefined, AccessToken | null | undefined]> => { +export default async ( + authorization: string | null | undefined, + bodyToken: string | null, +): Promise< + [CacheableLocalUser | null | undefined, AccessToken | null | undefined] +> => { let token: string | null = null; // check if there is an authorization header set if (authorization != null) { if (bodyToken != null) { - throw new AuthenticationError('using multiple authorization schemes'); + throw new AuthenticationError("using multiple authorization schemes"); } // check if OAuth 2.0 Bearer tokens are being used // Authorization schemes are case insensitive - if (authorization.substring(0, 7).toLowerCase() === 'bearer ') { + if (authorization.substring(0, 7).toLowerCase() === "bearer ") { token = authorization.substring(7); } else { - throw new AuthenticationError('unsupported authentication scheme'); + throw new AuthenticationError("unsupported authentication scheme"); } } else if (bodyToken != null) { token = bodyToken; @@ -38,44 +46,56 @@ export default async (authorization: string | null | undefined, bodyToken: strin } if (isNativeToken(token)) { - const user = await localUserByNativeTokenCache.fetch(token, - () => Users.findOneBy({ token }) as Promise); + const user = await localUserByNativeTokenCache.fetch( + token, + () => Users.findOneBy({ token }) as Promise, + ); if (user == null) { - throw new AuthenticationError('unknown token'); + throw new AuthenticationError("unknown token"); } return [user, null]; } else { const accessToken = await AccessTokens.findOne({ - where: [{ - hash: token.toLowerCase(), // app - }, { - token: token, // miauth - }], + where: [ + { + hash: token.toLowerCase(), // app + }, + { + token: token, // miauth + }, + ], }); if (accessToken == null) { - throw new AuthenticationError('unknown token'); + throw new AuthenticationError("unknown token"); } AccessTokens.update(accessToken.id, { lastUsedAt: new Date(), }); - const user = await localUserByIdCache.fetch(accessToken.userId, - () => Users.findOneBy({ - id: accessToken.userId, - }) as Promise); + const user = await localUserByIdCache.fetch( + accessToken.userId, + () => + Users.findOneBy({ + id: accessToken.userId, + }) as Promise, + ); if (accessToken.appId) { - const app = await appCache.fetch(accessToken.appId, - () => Apps.findOneByOrFail({ id: accessToken.appId! })); + const app = await appCache.fetch(accessToken.appId, () => + Apps.findOneByOrFail({ id: accessToken.appId! }), + ); - return [user, { - id: accessToken.id, - permission: app.permission, - } as AccessToken]; + return [ + user, + { + id: accessToken.id, + permission: app.permission, + } as AccessToken, + ]; } else { return [user, accessToken]; } diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 9458d15fe..45471ed56 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -1,32 +1,43 @@ -import { performance } from 'perf_hooks'; -import Koa from 'koa'; -import { CacheableLocalUser, User } from '@/models/entities/user.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { getIpHash } from '@/misc/get-ip-hash.js'; -import { limiter } from './limiter.js'; -import endpoints, { IEndpointMeta } from './endpoints.js'; -import { ApiError } from './error.js'; -import { apiLogger } from './logger.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import { performance } from "perf_hooks"; +import type Koa from "koa"; +import type { CacheableLocalUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import type { AccessToken } from "@/models/entities/access-token.js"; +import { getIpHash } from "@/misc/get-ip-hash.js"; +import { limiter } from "./limiter.js"; +import type { IEndpointMeta } from "./endpoints.js"; +import endpoints from "./endpoints.js"; +import compatibility from "./compatibility.js"; +import { ApiError } from "./error.js"; +import { apiLogger } from "./logger.js"; +import type { AccessToken } from "@/models/entities/access-token.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; const accessDenied = { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "56f35758-7dd5-468b-8439-5d6fb8ec9b8e", }; -export default async (endpoint: string, user: CacheableLocalUser | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => { +export default async ( + endpoint: string, + user: CacheableLocalUser | null | undefined, + token: AccessToken | null | undefined, + data: any, + ctx?: Koa.Context, +) => { const isSecure = user != null && token == null; const isModerator = user != null && (user.isModerator || user.isAdmin); - const ep = endpoints.find(e => e.name === endpoint); + const ep = + endpoints.find((e) => e.name === endpoint) || + compatibility.find((e) => e.name === endpoint); if (ep == null) { throw new ApiError({ - message: 'No such endpoint.', - code: 'NO_SUCH_ENDPOINT', - id: 'f8080b67-5f9c-4eb7-8c18-7f1eeae8f709', + message: "No such endpoint.", + code: "NO_SUCH_ENDPOINT", + id: "f8080b67-5f9c-4eb7-8c18-7f1eeae8f709", httpStatusCode: 404, }); } @@ -51,11 +62,14 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi } // Rate limit - await limiter(limit as IEndpointMeta['limit'] & { key: NonNullable }, limitActor).catch(e => { + await limiter( + limit as IEndpointMeta["limit"] & { key: NonNullable }, + limitActor, + ).catch((e) => { throw new ApiError({ - message: 'Rate limit exceeded. Please try again later.', - code: 'RATE_LIMIT_EXCEEDED', - id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', + message: "Rate limit exceeded. Please try again later.", + code: "RATE_LIMIT_EXCEEDED", + id: "d5826d14-3982-4d2e-8011-b9e9f02499ef", httpStatusCode: 429, }); }); @@ -63,65 +77,80 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi if (ep.meta.requireCredential && user == null) { throw new ApiError({ - message: 'Credential required.', - code: 'CREDENTIAL_REQUIRED', - id: '1384574d-a912-4b81-8601-c7b1c4085df1', + message: "Credential required.", + code: "CREDENTIAL_REQUIRED", + id: "1384574d-a912-4b81-8601-c7b1c4085df1", httpStatusCode: 401, }); } if (ep.meta.requireCredential && user!.isSuspended) { throw new ApiError({ - message: 'Your account has been suspended.', - code: 'YOUR_ACCOUNT_SUSPENDED', - id: 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370', + message: "Your account has been suspended.", + code: "YOUR_ACCOUNT_SUSPENDED", + id: "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370", httpStatusCode: 403, }); } if (ep.meta.requireAdmin && !user!.isAdmin) { - throw new ApiError(accessDenied, { reason: 'You are not the admin.' }); + throw new ApiError(accessDenied, { reason: "You are not the admin." }); } if (ep.meta.requireModerator && !isModerator) { - throw new ApiError(accessDenied, { reason: 'You are not a moderator.' }); + throw new ApiError(accessDenied, { reason: "You are not a moderator." }); } - if (token && ep.meta.kind && !token.permission.some(p => p === ep.meta.kind)) { + if ( + token && + ep.meta.kind && + !token.permission.some((p) => p === ep.meta.kind) + ) { throw new ApiError({ - message: 'Your app does not have the necessary permissions to use this endpoint.', - code: 'PERMISSION_DENIED', - id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838', + message: + "Your app does not have the necessary permissions to use this endpoint.", + code: "PERMISSION_DENIED", + id: "1370e5b7-d4eb-4566-bb1d-7748ee6a1838", }); } // private mode const meta = await fetchMeta(); - if (meta.privateMode && ep.meta.requireCredentialPrivateMode && user == null) { + if ( + meta.privateMode && + ep.meta.requireCredentialPrivateMode && + user == null + ) { throw new ApiError({ - message: 'Credential required.', - code: 'CREDENTIAL_REQUIRED', - id: '1384574d-a912-4b81-8601-c7b1c4085df1', - httpStatusCode: 401 + message: "Credential required.", + code: "CREDENTIAL_REQUIRED", + id: "1384574d-a912-4b81-8601-c7b1c4085df1", + httpStatusCode: 401, }); } // Cast non JSON input - if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) { + if ((ep.meta.requireFile || ctx?.method === "GET") && ep.params.properties) { for (const k of Object.keys(ep.params.properties)) { const param = ep.params.properties![k]; - if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') { + if ( + ["boolean", "number", "integer"].includes(param.type ?? "") && + typeof data[k] === "string" + ) { try { data[k] = JSON.parse(data[k]); } catch (e) { - throw new ApiError({ - message: 'Invalid param.', - code: 'INVALID_PARAM', - id: '0b5f1631-7c1a-41a6-b399-cce335f34d85', - }, { - param: k, - reason: `cannot cast to ${param.type}`, - }); + throw new ApiError( + { + message: "Invalid param.", + code: "INVALID_PARAM", + id: "0b5f1631-7c1a-41a6-b399-cce335f34d85", + }, + { + param: k, + reason: `cannot cast to ${param.type}`, + }, + ); } } } @@ -129,32 +158,35 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi // API invoking const before = performance.now(); - return await ep.exec(data, user, token, ctx?.file, ctx?.ip, ctx?.headers).catch((e: Error) => { - if (e instanceof ApiError) { - throw e; - } else { - apiLogger.error(`Internal error occurred in ${ep.name}: ${e.message}`, { - ep: ep.name, - ps: data, - e: { - message: e.message, - code: e.name, - stack: e.stack, - }, - }); - throw new ApiError(null, { - e: { - message: e.message, - code: e.name, - stack: e.stack, - }, - }); - } - }).finally(() => { - const after = performance.now(); - const time = after - before; - if (time > 1000) { - apiLogger.warn(`SLOW API CALL DETECTED: ${ep.name} (${time}ms)`); - } - }); + return await ep + .exec(data, user, token, ctx?.file, ctx?.ip, ctx?.headers) + .catch((e: Error) => { + if (e instanceof ApiError) { + throw e; + } else { + apiLogger.error(`Internal error occurred in ${ep.name}: ${e.message}`, { + ep: ep.name, + ps: data, + e: { + message: e.message, + code: e.name, + stack: e.stack, + }, + }); + throw new ApiError(null, { + e: { + message: e.message, + code: e.name, + stack: e.stack, + }, + }); + } + }) + .finally(() => { + const after = performance.now(); + const time = after - before; + if (time > 1000) { + apiLogger.warn(`SLOW API CALL DETECTED: ${ep.name} (${time}ms)`); + } + }); }; diff --git a/packages/backend/src/server/api/common/generate-block-query.ts b/packages/backend/src/server/api/common/generate-block-query.ts index 60db1e731..a37b607eb 100644 --- a/packages/backend/src/server/api/common/generate-block-query.ts +++ b/packages/backend/src/server/api/common/generate-block-query.ts @@ -1,42 +1,54 @@ -import { User } from '@/models/entities/user.js'; -import { Blockings } from '@/models/index.js'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import { Blockings } from "@/models/index.js"; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; // ここでいうBlockedは被Blockedの意 -export function generateBlockedUserQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { - const blockingQuery = Blockings.createQueryBuilder('blocking') - .select('blocking.blockerId') - .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id }); +export function generateBlockedUserQuery( + q: SelectQueryBuilder, + me: { id: User["id"] }, +) { + const blockingQuery = Blockings.createQueryBuilder("blocking") + .select("blocking.blockerId") + .where("blocking.blockeeId = :blockeeId", { blockeeId: me.id }); // 投稿の作者にブロックされていない かつ // 投稿の返信先の作者にブロックされていない かつ // 投稿の引用元の作者にブロックされていない - q - .andWhere(`note.userId NOT IN (${ blockingQuery.getQuery() })`) - .andWhere(new Brackets(qb => { qb - .where(`note.replyUserId IS NULL`) - .orWhere(`note.replyUserId NOT IN (${ blockingQuery.getQuery() })`); - })) - .andWhere(new Brackets(qb => { qb - .where(`note.renoteUserId IS NULL`) - .orWhere(`note.renoteUserId NOT IN (${ blockingQuery.getQuery() })`); - })); + q.andWhere(`note.userId NOT IN (${blockingQuery.getQuery()})`) + .andWhere( + new Brackets((qb) => { + qb.where("note.replyUserId IS NULL").orWhere( + `note.replyUserId NOT IN (${blockingQuery.getQuery()})`, + ); + }), + ) + .andWhere( + new Brackets((qb) => { + qb.where("note.renoteUserId IS NULL").orWhere( + `note.renoteUserId NOT IN (${blockingQuery.getQuery()})`, + ); + }), + ); q.setParameters(blockingQuery.getParameters()); } -export function generateBlockQueryForUsers(q: SelectQueryBuilder, me: { id: User['id'] }) { - const blockingQuery = Blockings.createQueryBuilder('blocking') - .select('blocking.blockeeId') - .where('blocking.blockerId = :blockerId', { blockerId: me.id }); +export function generateBlockQueryForUsers( + q: SelectQueryBuilder, + me: { id: User["id"] }, +) { + const blockingQuery = Blockings.createQueryBuilder("blocking") + .select("blocking.blockeeId") + .where("blocking.blockerId = :blockerId", { blockerId: me.id }); - const blockedQuery = Blockings.createQueryBuilder('blocking') - .select('blocking.blockerId') - .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id }); + const blockedQuery = Blockings.createQueryBuilder("blocking") + .select("blocking.blockerId") + .where("blocking.blockeeId = :blockeeId", { blockeeId: me.id }); - q.andWhere(`user.id NOT IN (${ blockingQuery.getQuery() })`); + q.andWhere(`user.id NOT IN (${blockingQuery.getQuery()})`); q.setParameters(blockingQuery.getParameters()); - q.andWhere(`user.id NOT IN (${ blockedQuery.getQuery() })`); + q.andWhere(`user.id NOT IN (${blockedQuery.getQuery()})`); q.setParameters(blockedQuery.getParameters()); } diff --git a/packages/backend/src/server/api/common/generate-channel-query.ts b/packages/backend/src/server/api/common/generate-channel-query.ts index 333bb73b8..318062266 100644 --- a/packages/backend/src/server/api/common/generate-channel-query.ts +++ b/packages/backend/src/server/api/common/generate-channel-query.ts @@ -1,23 +1,34 @@ -import { User } from '@/models/entities/user.js'; -import { ChannelFollowings } from '@/models/index.js'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import { ChannelFollowings } from "@/models/index.js"; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; -export function generateChannelQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { +export function generateChannelQuery( + q: SelectQueryBuilder, + me?: { id: User["id"] } | null, +) { if (me == null) { - q.andWhere('note.channelId IS NULL'); + q.andWhere("note.channelId IS NULL"); } else { - q.leftJoinAndSelect('note.channel', 'channel'); + q.leftJoinAndSelect("note.channel", "channel"); - const channelFollowingQuery = ChannelFollowings.createQueryBuilder('channelFollowing') - .select('channelFollowing.followeeId') - .where('channelFollowing.followerId = :followerId', { followerId: me.id }); + const channelFollowingQuery = ChannelFollowings.createQueryBuilder( + "channelFollowing", + ) + .select("channelFollowing.followeeId") + .where("channelFollowing.followerId = :followerId", { + followerId: me.id, + }); - q.andWhere(new Brackets(qb => { qb - // チャンネルのノートではない - .where('note.channelId IS NULL') - // または自分がフォローしているチャンネルのノート - .orWhere(`note.channelId IN (${ channelFollowingQuery.getQuery() })`); - })); + q.andWhere( + new Brackets((qb) => { + qb + // チャンネルのノートではない + .where("note.channelId IS NULL") + // または自分がフォローしているチャンネルのノート + .orWhere(`note.channelId IN (${channelFollowingQuery.getQuery()})`); + }), + ); q.setParameters(channelFollowingQuery.getParameters()); } diff --git a/packages/backend/src/server/api/common/generate-muted-note-query.ts b/packages/backend/src/server/api/common/generate-muted-note-query.ts index f544e334d..86da2ea88 100644 --- a/packages/backend/src/server/api/common/generate-muted-note-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-note-query.ts @@ -1,13 +1,16 @@ -import { User } from '@/models/entities/user.js'; -import { MutedNotes } from '@/models/index.js'; -import { SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import { MutedNotes } from "@/models/index.js"; +import type { SelectQueryBuilder } from "typeorm"; -export function generateMutedNoteQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { - const mutedQuery = MutedNotes.createQueryBuilder('muted') - .select('muted.noteId') - .where('muted.userId = :userId', { userId: me.id }); +export function generateMutedNoteQuery( + q: SelectQueryBuilder, + me: { id: User["id"] }, +) { + const mutedQuery = MutedNotes.createQueryBuilder("muted") + .select("muted.noteId") + .where("muted.userId = :userId", { userId: me.id }); - q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`); + q.andWhere(`note.id NOT IN (${mutedQuery.getQuery()})`); q.setParameters(mutedQuery.getParameters()); } diff --git a/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts b/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts index 7263ea2e6..61f44f4a7 100644 --- a/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts @@ -1,17 +1,24 @@ -import { User } from '@/models/entities/user.js'; -import { NoteThreadMutings } from '@/models/index.js'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import { NoteThreadMutings } from "@/models/index.js"; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; -export function generateMutedNoteThreadQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { - const mutedQuery = NoteThreadMutings.createQueryBuilder('threadMuted') - .select('threadMuted.threadId') - .where('threadMuted.userId = :userId', { userId: me.id }); +export function generateMutedNoteThreadQuery( + q: SelectQueryBuilder, + me: { id: User["id"] }, +) { + const mutedQuery = NoteThreadMutings.createQueryBuilder("threadMuted") + .select("threadMuted.threadId") + .where("threadMuted.userId = :userId", { userId: me.id }); - q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`); - q.andWhere(new Brackets(qb => { qb - .where(`note.threadId IS NULL`) - .orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`); - })); + q.andWhere(`note.id NOT IN (${mutedQuery.getQuery()})`); + q.andWhere( + new Brackets((qb) => { + qb.where("note.threadId IS NULL").orWhere( + `note.threadId NOT IN (${mutedQuery.getQuery()})`, + ); + }), + ); q.setParameters(mutedQuery.getParameters()); } diff --git a/packages/backend/src/server/api/common/generate-muted-user-query.ts b/packages/backend/src/server/api/common/generate-muted-user-query.ts index 470ece1a6..3538fbf0a 100644 --- a/packages/backend/src/server/api/common/generate-muted-user-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-user-query.ts @@ -1,57 +1,81 @@ -import { SelectQueryBuilder, Brackets } from 'typeorm'; -import { User } from '@/models/entities/user.js'; -import { Mutings, UserProfiles } from '@/models/index.js'; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; +import type { User } from "@/models/entities/user.js"; +import { Mutings, UserProfiles } from "@/models/index.js"; -export function generateMutedUserQuery(q: SelectQueryBuilder, me: { id: User['id'] }, exclude?: User) { - const mutingQuery = Mutings.createQueryBuilder('muting') - .select('muting.muteeId') - .where('muting.muterId = :muterId', { muterId: me.id }); +export function generateMutedUserQuery( + q: SelectQueryBuilder, + me: { id: User["id"] }, + exclude?: User, +) { + const mutingQuery = Mutings.createQueryBuilder("muting") + .select("muting.muteeId") + .where("muting.muterId = :muterId", { muterId: me.id }); if (exclude) { - mutingQuery.andWhere('muting.muteeId != :excludeId', { excludeId: exclude.id }); + mutingQuery.andWhere("muting.muteeId != :excludeId", { + excludeId: exclude.id, + }); } - const mutingInstanceQuery = UserProfiles.createQueryBuilder('user_profile') - .select('user_profile.mutedInstances') - .where('user_profile.userId = :muterId', { muterId: me.id }); + const mutingInstanceQuery = UserProfiles.createQueryBuilder("user_profile") + .select("user_profile.mutedInstances") + .where("user_profile.userId = :muterId", { muterId: me.id }); // 投稿の作者をミュートしていない かつ // 投稿の返信先の作者をミュートしていない かつ // 投稿の引用元の作者をミュートしていない - q - .andWhere(`note.userId NOT IN (${ mutingQuery.getQuery() })`) - .andWhere(new Brackets(qb => { qb - .where('note.replyUserId IS NULL') - .orWhere(`note.replyUserId NOT IN (${ mutingQuery.getQuery() })`); - })) - .andWhere(new Brackets(qb => { qb - .where('note.renoteUserId IS NULL') - .orWhere(`note.renoteUserId NOT IN (${ mutingQuery.getQuery() })`); - })) + q.andWhere(`note.userId NOT IN (${mutingQuery.getQuery()})`) + .andWhere( + new Brackets((qb) => { + qb.where("note.replyUserId IS NULL").orWhere( + `note.replyUserId NOT IN (${mutingQuery.getQuery()})`, + ); + }), + ) + .andWhere( + new Brackets((qb) => { + qb.where("note.renoteUserId IS NULL").orWhere( + `note.renoteUserId NOT IN (${mutingQuery.getQuery()})`, + ); + }), + ) // mute instances - .andWhere(new Brackets(qb => { qb - .andWhere('note.userHost IS NULL') - .orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.userHost)`); - })) - .andWhere(new Brackets(qb => { qb - .where('note.replyUserHost IS NULL') - .orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.replyUserHost)`); - })) - .andWhere(new Brackets(qb => { qb - .where('note.renoteUserHost IS NULL') - .orWhere(`NOT ((${ mutingInstanceQuery.getQuery() })::jsonb ? note.renoteUserHost)`); - })); + .andWhere( + new Brackets((qb) => { + qb.andWhere("note.userHost IS NULL").orWhere( + `NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.userHost)`, + ); + }), + ) + .andWhere( + new Brackets((qb) => { + qb.where("note.replyUserHost IS NULL").orWhere( + `NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.replyUserHost)`, + ); + }), + ) + .andWhere( + new Brackets((qb) => { + qb.where("note.renoteUserHost IS NULL").orWhere( + `NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.renoteUserHost)`, + ); + }), + ); q.setParameters(mutingQuery.getParameters()); q.setParameters(mutingInstanceQuery.getParameters()); } -export function generateMutedUserQueryForUsers(q: SelectQueryBuilder, me: { id: User['id'] }) { - const mutingQuery = Mutings.createQueryBuilder('muting') - .select('muting.muteeId') - .where('muting.muterId = :muterId', { muterId: me.id }); +export function generateMutedUserQueryForUsers( + q: SelectQueryBuilder, + me: { id: User["id"] }, +) { + const mutingQuery = Mutings.createQueryBuilder("muting") + .select("muting.muteeId") + .where("muting.muterId = :muterId", { muterId: me.id }); - q.andWhere(`user.id NOT IN (${ mutingQuery.getQuery() })`); + q.andWhere(`user.id NOT IN (${mutingQuery.getQuery()})`); q.setParameters(mutingQuery.getParameters()); } diff --git a/packages/backend/src/server/api/common/generate-native-user-token.ts b/packages/backend/src/server/api/common/generate-native-user-token.ts index 5d8a4c537..5a8b41b70 100644 --- a/packages/backend/src/server/api/common/generate-native-user-token.ts +++ b/packages/backend/src/server/api/common/generate-native-user-token.ts @@ -1,3 +1,3 @@ -import { secureRndstr } from '@/misc/secure-rndstr.js'; +import { secureRndstr } from "@/misc/secure-rndstr.js"; export default () => secureRndstr(16, true); diff --git a/packages/backend/src/server/api/common/generate-replies-query.ts b/packages/backend/src/server/api/common/generate-replies-query.ts index 301782eab..140c1d74a 100644 --- a/packages/backend/src/server/api/common/generate-replies-query.ts +++ b/packages/backend/src/server/api/common/generate-replies-query.ts @@ -1,27 +1,47 @@ -import { User } from '@/models/entities/user.js'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; -export function generateRepliesQuery(q: SelectQueryBuilder, me?: Pick | null) { +export function generateRepliesQuery( + q: SelectQueryBuilder, + me?: Pick | null, +) { if (me == null) { - q.andWhere(new Brackets(qb => { qb - .where(`note.replyId IS NULL`) // 返信ではない - .orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.replyUserId = note.userId'); - })); - })); + q.andWhere( + new Brackets((qb) => { + qb.where("note.replyId IS NULL") // 返信ではない + .orWhere( + new Brackets((qb) => { + qb.where( + // 返信だけど投稿者自身への返信 + "note.replyId IS NOT NULL", + ).andWhere("note.replyUserId = note.userId"); + }), + ); + }), + ); } else if (!me.showTimelineReplies) { - q.andWhere(new Brackets(qb => { qb - .where(`note.replyId IS NULL`) // 返信ではない - .orWhere('note.replyUserId = :meId', { meId: me.id }) // 返信だけど自分のノートへの返信 - .orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.userId = :meId', { meId: me.id }); - })) - .orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.replyUserId = note.userId'); - })); - })); + q.andWhere( + new Brackets((qb) => { + qb.where("note.replyId IS NULL") // 返信ではない + .orWhere("note.replyUserId = :meId", { meId: me.id }) // 返信だけど自分のノートへの返信 + .orWhere( + new Brackets((qb) => { + qb.where( + // 返信だけど自分の行った返信 + "note.replyId IS NOT NULL", + ).andWhere("note.userId = :meId", { meId: me.id }); + }), + ) + .orWhere( + new Brackets((qb) => { + qb.where( + // 返信だけど投稿者自身への返信 + "note.replyId IS NOT NULL", + ).andWhere("note.replyUserId = note.userId"); + }), + ); + }), + ); } } diff --git a/packages/backend/src/server/api/common/generate-visibility-query.ts b/packages/backend/src/server/api/common/generate-visibility-query.ts index b50b6812f..c434df082 100644 --- a/packages/backend/src/server/api/common/generate-visibility-query.ts +++ b/packages/backend/src/server/api/common/generate-visibility-query.ts @@ -1,41 +1,60 @@ -import { User } from '@/models/entities/user.js'; -import { Followings } from '@/models/index.js'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; +import type { User } from "@/models/entities/user.js"; +import { Followings } from "@/models/index.js"; +import type { SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; -export function generateVisibilityQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { +export function generateVisibilityQuery( + q: SelectQueryBuilder, + me?: { id: User["id"] } | null, +) { // This code must always be synchronized with the checks in Notes.isVisibleForMe. if (me == null) { - q.andWhere(new Brackets(qb => { qb - .where(`note.visibility = 'public'`) - .orWhere(`note.visibility = 'home'`); - })); + q.andWhere( + new Brackets((qb) => { + qb.where(`note.visibility = 'public'`).orWhere( + `note.visibility = 'home'`, + ); + }), + ); } else { - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :meId'); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :meId"); - q.andWhere(new Brackets(qb => { qb - // 公開投稿である - .where(new Brackets(qb => { qb - .where(`note.visibility = 'public'`) - .orWhere(`note.visibility = 'home'`); - })) - // または 自分自身 - .orWhere('note.userId = :meId') - // または 自分宛て - .orWhere(':meId = ANY(note.visibleUserIds)') - .orWhere(':meId = ANY(note.mentions)') - .orWhere(new Brackets(qb => { qb - // または フォロワー宛ての投稿であり、 - .where(`note.visibility = 'followers'`) - .andWhere(new Brackets(qb => { qb - // 自分がフォロワーである - .where(`note.userId IN (${ followingQuery.getQuery() })`) - // または 自分の投稿へのリプライ - .orWhere('note.replyUserId = :meId'); - })); - })); - })); + q.andWhere( + new Brackets((qb) => { + qb + // 公開投稿である + .where( + new Brackets((qb) => { + qb.where(`note.visibility = 'public'`).orWhere( + `note.visibility = 'home'`, + ); + }), + ) + // または 自分自身 + .orWhere("note.userId = :meId") + // または 自分宛て + .orWhere(":meId = ANY(note.visibleUserIds)") + .orWhere(":meId = ANY(note.mentions)") + .orWhere( + new Brackets((qb) => { + qb + // または フォロワー宛ての投稿であり、 + .where(`note.visibility = 'followers'`) + .andWhere( + new Brackets((qb) => { + qb + // 自分がフォロワーである + .where(`note.userId IN (${followingQuery.getQuery()})`) + // または 自分の投稿へのリプライ + .orWhere("note.replyUserId = :meId"); + }), + ); + }), + ); + }), + ); q.setParameters({ meId: me.id }); } diff --git a/packages/backend/src/server/api/common/getters.ts b/packages/backend/src/server/api/common/getters.ts index c5a1e765e..fd7580775 100644 --- a/packages/backend/src/server/api/common/getters.ts +++ b/packages/backend/src/server/api/common/getters.ts @@ -1,24 +1,29 @@ -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { Notes, Users } from '@/models/index.js'; -import { generateVisibilityQuery } from './generate-visibility-query.js'; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { Notes, Users } from "@/models/index.js"; +import { generateVisibilityQuery } from "./generate-visibility-query.js"; /** * Get note for API processing, taking into account visibility. */ -export async function getNote(noteId: Note['id'], me: { id: User['id'] } | null) { - const query = Notes.createQueryBuilder('note') - .where("note.id = :id", { - id: noteId, - }); +export async function getNote( + noteId: Note["id"], + me: { id: User["id"] } | null, +) { + const query = Notes.createQueryBuilder("note").where("note.id = :id", { + id: noteId, + }); generateVisibilityQuery(query, me); const note = await query.getOne(); if (note == null) { - throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); + throw new IdentifiableError( + "9725d0ce-ba28-4dde-95a7-2cbb2c15de24", + "No such note.", + ); } return note; @@ -27,11 +32,14 @@ export async function getNote(noteId: Note['id'], me: { id: User['id'] } | null) /** * Get user for API processing */ -export async function getUser(userId: User['id']) { +export async function getUser(userId: User["id"]) { const user = await Users.findOneBy({ id: userId }); if (user == null) { - throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.'); + throw new IdentifiableError( + "15348ddd-432d-49c2-8a5a-8069753becff", + "No such user.", + ); } return user; @@ -40,11 +48,11 @@ export async function getUser(userId: User['id']) { /** * Get remote user for API processing */ -export async function getRemoteUser(userId: User['id']) { +export async function getRemoteUser(userId: User["id"]) { const user = await getUser(userId); if (!Users.isRemoteUser(user)) { - throw new Error('user is not a remote user'); + throw new Error("user is not a remote user"); } return user; @@ -53,11 +61,11 @@ export async function getRemoteUser(userId: User['id']) { /** * Get local user for API processing */ -export async function getLocalUser(userId: User['id']) { +export async function getLocalUser(userId: User["id"]) { const user = await getUser(userId); if (!Users.isLocalUser(user)) { - throw new Error('user is not a local user'); + throw new Error("user is not a local user"); } return user; diff --git a/packages/backend/src/server/api/common/inject-featured.ts b/packages/backend/src/server/api/common/inject-featured.ts index f7cdd365e..30ba3eca9 100644 --- a/packages/backend/src/server/api/common/inject-featured.ts +++ b/packages/backend/src/server/api/common/inject-featured.ts @@ -1,9 +1,9 @@ -import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note.js'; -import { User } from '@/models/entities/user.js'; -import { Notes, UserProfiles, NoteReactions } from '@/models/index.js'; -import { generateMutedUserQuery } from './generate-muted-user-query.js'; -import { generateBlockedUserQuery } from './generate-block-query.js'; +import rndstr from "rndstr"; +import type { Note } from "@/models/entities/note.js"; +import type { User } from "@/models/entities/user.js"; +import { Notes, UserProfiles, NoteReactions } from "@/models/index.js"; +import { generateMutedUserQuery } from "./generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "./generate-block-query.js"; // TODO: リアクション、Renote、返信などをしたノートは除外する @@ -18,38 +18,35 @@ export async function injectFeatured(timeline: Note[], user?: User | null) { const max = 30; const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで - const query = Notes.createQueryBuilder('note') - .addSelect('note.score') - .where('note.userHost IS NULL') - .andWhere(`note.score > 0`) - .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) + const query = Notes.createQueryBuilder("note") + .addSelect("note.score") + .where("note.userHost IS NULL") + .andWhere("note.score > 0") + .andWhere("note.createdAt > :date", { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) - .innerJoinAndSelect('note.user', 'user'); + .innerJoinAndSelect("note.user", "user"); if (user) { - query.andWhere('note.userId != :userId', { userId: user.id }); + query.andWhere("note.userId != :userId", { userId: user.id }); generateMutedUserQuery(query, user); generateBlockedUserQuery(query, user); - const reactionQuery = NoteReactions.createQueryBuilder('reaction') - .select('reaction.noteId') - .where('reaction.userId = :userId', { userId: user.id }); + const reactionQuery = NoteReactions.createQueryBuilder("reaction") + .select("reaction.noteId") + .where("reaction.userId = :userId", { userId: user.id }); - query.andWhere(`note.id NOT IN (${ reactionQuery.getQuery() })`); + query.andWhere(`note.id NOT IN (${reactionQuery.getQuery()})`); } - const notes = await query - .orderBy('note.score', 'DESC') - .take(max) - .getMany(); + const notes = await query.orderBy("note.score", "DESC").take(max).getMany(); if (notes.length === 0) return; // Pick random one const featured = notes[Math.floor(Math.random() * notes.length)]; - (featured as any)._featuredId_ = rndstr('a-z0-9', 8); + (featured as any)._featuredId_ = rndstr("a-z0-9", 8); // Inject featured timeline.splice(3, 0, featured); diff --git a/packages/backend/src/server/api/common/inject-promo.ts b/packages/backend/src/server/api/common/inject-promo.ts index b0da8118b..dcc4e5f3f 100644 --- a/packages/backend/src/server/api/common/inject-promo.ts +++ b/packages/backend/src/server/api/common/inject-promo.ts @@ -1,21 +1,23 @@ -import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note.js'; -import { User } from '@/models/entities/user.js'; -import { PromoReads, PromoNotes, Notes, Users } from '@/models/index.js'; +import rndstr from "rndstr"; +import type { Note } from "@/models/entities/note.js"; +import type { User } from "@/models/entities/user.js"; +import { PromoReads, PromoNotes, Notes, Users } from "@/models/index.js"; export async function injectPromo(timeline: Note[], user?: User | null) { if (timeline.length < 5) return; // TODO: readやexpireフィルタはクエリ側でやる - const reads = user ? await PromoReads.findBy({ - userId: user.id, - }) : []; + const reads = user + ? await PromoReads.findBy({ + userId: user.id, + }) + : []; let promos = await PromoNotes.find(); - promos = promos.filter(n => n.expiresAt.getTime() > Date.now()); - promos = promos.filter(n => !reads.map(r => r.noteId).includes(n.noteId)); + promos = promos.filter((n) => n.expiresAt.getTime() > Date.now()); + promos = promos.filter((n) => !reads.map((r) => r.noteId).includes(n.noteId)); if (promos.length === 0) return; @@ -27,7 +29,7 @@ export async function injectPromo(timeline: Note[], user?: User | null) { // Join note.user = await Users.findOneByOrFail({ id: note.userId }); - (note as any)._prId_ = rndstr('a-z0-9', 8); + (note as any)._prId_ = rndstr("a-z0-9", 8); // Inject promo timeline.splice(3, 0, note); diff --git a/packages/backend/src/server/api/common/make-pagination-query.ts b/packages/backend/src/server/api/common/make-pagination-query.ts index 51c11e5df..a2c327569 100644 --- a/packages/backend/src/server/api/common/make-pagination-query.ts +++ b/packages/backend/src/server/api/common/make-pagination-query.ts @@ -1,28 +1,42 @@ -import { SelectQueryBuilder } from 'typeorm'; +import type { SelectQueryBuilder } from "typeorm"; -export function makePaginationQuery(q: SelectQueryBuilder, sinceId?: string, untilId?: string, sinceDate?: number, untilDate?: number) { +export function makePaginationQuery( + q: SelectQueryBuilder, + sinceId?: string, + untilId?: string, + sinceDate?: number, + untilDate?: number, +) { if (sinceId && untilId) { q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId }); - q.orderBy(`${q.alias}.id`, 'DESC'); + q.orderBy(`${q.alias}.id`, "DESC"); } else if (sinceId) { q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); - q.orderBy(`${q.alias}.id`, 'ASC'); + q.orderBy(`${q.alias}.id`, "ASC"); } else if (untilId) { q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId }); - q.orderBy(`${q.alias}.id`, 'DESC'); + q.orderBy(`${q.alias}.id`, "DESC"); } else if (sinceDate && untilDate) { - q.andWhere(`${q.alias}.createdAt > :sinceDate`, { sinceDate: new Date(sinceDate) }); - q.andWhere(`${q.alias}.createdAt < :untilDate`, { untilDate: new Date(untilDate) }); - q.orderBy(`${q.alias}.createdAt`, 'DESC'); + q.andWhere(`${q.alias}.createdAt > :sinceDate`, { + sinceDate: new Date(sinceDate), + }); + q.andWhere(`${q.alias}.createdAt < :untilDate`, { + untilDate: new Date(untilDate), + }); + q.orderBy(`${q.alias}.createdAt`, "DESC"); } else if (sinceDate) { - q.andWhere(`${q.alias}.createdAt > :sinceDate`, { sinceDate: new Date(sinceDate) }); - q.orderBy(`${q.alias}.createdAt`, 'ASC'); + q.andWhere(`${q.alias}.createdAt > :sinceDate`, { + sinceDate: new Date(sinceDate), + }); + q.orderBy(`${q.alias}.createdAt`, "ASC"); } else if (untilDate) { - q.andWhere(`${q.alias}.createdAt < :untilDate`, { untilDate: new Date(untilDate) }); - q.orderBy(`${q.alias}.createdAt`, 'DESC'); + q.andWhere(`${q.alias}.createdAt < :untilDate`, { + untilDate: new Date(untilDate), + }); + q.orderBy(`${q.alias}.createdAt`, "DESC"); } else { - q.orderBy(`${q.alias}.id`, 'DESC'); + q.orderBy(`${q.alias}.id`, "DESC"); } return q; } diff --git a/packages/backend/src/server/api/common/read-messaging-message.ts b/packages/backend/src/server/api/common/read-messaging-message.ts index c4c18ffa0..fc22c843a 100644 --- a/packages/backend/src/server/api/common/read-messaging-message.ts +++ b/packages/backend/src/server/api/common/read-messaging-message.ts @@ -1,26 +1,29 @@ -import { publishMainStream, publishGroupMessagingStream } from '@/services/stream.js'; -import { publishMessagingStream } from '@/services/stream.js'; -import { publishMessagingIndexStream } from '@/services/stream.js'; -import { pushNotification } from '@/services/push-notification.js'; -import { User, IRemoteUser } from '@/models/entities/user.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { MessagingMessages, UserGroupJoinings, Users } from '@/models/index.js'; -import { In } from 'typeorm'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { toArray } from '@/prelude/array.js'; -import { renderReadActivity } from '@/remote/activitypub/renderer/read.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { deliver } from '@/queue/index.js'; -import orderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; +import { + publishMainStream, + publishGroupMessagingStream, +} from "@/services/stream.js"; +import { publishMessagingStream } from "@/services/stream.js"; +import { publishMessagingIndexStream } from "@/services/stream.js"; +import { pushNotification } from "@/services/push-notification.js"; +import type { User, IRemoteUser } from "@/models/entities/user.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { MessagingMessages, UserGroupJoinings, Users } from "@/models/index.js"; +import { In } from "typeorm"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import { toArray } from "@/prelude/array.js"; +import { renderReadActivity } from "@/remote/activitypub/renderer/read.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { deliver } from "@/queue/index.js"; +import orderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; /** * Mark messages as read */ export async function readUserMessagingMessage( - userId: User['id'], - otherpartyId: User['id'], - messageIds: MessagingMessage['id'][] + userId: User["id"], + otherpartyId: User["id"], + messageIds: MessagingMessage["id"][], ) { if (messageIds.length === 0) return; @@ -30,28 +33,34 @@ export async function readUserMessagingMessage( for (const message of messages) { if (message.recipientId !== userId) { - throw new IdentifiableError('e140a4bf-49ce-4fb6-b67c-b78dadf6b52f', 'Access denied (user).'); + throw new IdentifiableError( + "e140a4bf-49ce-4fb6-b67c-b78dadf6b52f", + "Access denied (user).", + ); } } // Update documents - await MessagingMessages.update({ - id: In(messageIds), - userId: otherpartyId, - recipientId: userId, - isRead: false, - }, { - isRead: true, - }); + await MessagingMessages.update( + { + id: In(messageIds), + userId: otherpartyId, + recipientId: userId, + isRead: false, + }, + { + isRead: true, + }, + ); // Publish event - publishMessagingStream(otherpartyId, userId, 'read', messageIds); - publishMessagingIndexStream(userId, 'read', messageIds); + publishMessagingStream(otherpartyId, userId, "read", messageIds); + publishMessagingIndexStream(userId, "read", messageIds); - if (!await Users.getHasUnreadMessagingMessage(userId)) { + if (!(await Users.getHasUnreadMessagingMessage(userId))) { // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, 'readAllMessagingMessages'); - pushNotification(userId, 'readAllMessagingMessages', undefined); + publishMainStream(userId, "readAllMessagingMessages"); + pushNotification(userId, "readAllMessagingMessages", undefined); } else { // そのユーザーとのメッセージで未読がなければイベント発行 const count = await MessagingMessages.count({ @@ -60,11 +69,13 @@ export async function readUserMessagingMessage( recipientId: userId, isRead: false, }, - take: 1 + take: 1, }); if (!count) { - pushNotification(userId, 'readAllMessagingMessagesOfARoom', { userId: otherpartyId }); + pushNotification(userId, "readAllMessagingMessagesOfARoom", { + userId: otherpartyId, + }); } } } @@ -73,9 +84,9 @@ export async function readUserMessagingMessage( * Mark messages as read */ export async function readGroupMessagingMessage( - userId: User['id'], - groupId: UserGroup['id'], - messageIds: MessagingMessage['id'][] + userId: User["id"], + groupId: UserGroup["id"], + messageIds: MessagingMessage["id"][], ) { if (messageIds.length === 0) return; @@ -86,62 +97,79 @@ export async function readGroupMessagingMessage( }); if (joining == null) { - throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).'); + throw new IdentifiableError( + "930a270c-714a-46b2-b776-ad27276dc569", + "Access denied (group).", + ); } const messages = await MessagingMessages.findBy({ id: In(messageIds), }); - const reads: MessagingMessage['id'][] = []; + const reads: MessagingMessage["id"][] = []; for (const message of messages) { if (message.userId === userId) continue; if (message.reads.includes(userId)) continue; // Update document - await MessagingMessages.createQueryBuilder().update() + await MessagingMessages.createQueryBuilder() + .update() .set({ reads: (() => `array_append("reads", '${joining.userId}')`) as any, }) - .where('id = :id', { id: message.id }) + .where("id = :id", { id: message.id }) .execute(); reads.push(message.id); } // Publish event - publishGroupMessagingStream(groupId, 'read', { + publishGroupMessagingStream(groupId, "read", { ids: reads, userId: userId, }); - publishMessagingIndexStream(userId, 'read', reads); + publishMessagingIndexStream(userId, "read", reads); - if (!await Users.getHasUnreadMessagingMessage(userId)) { + if (!(await Users.getHasUnreadMessagingMessage(userId))) { // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, 'readAllMessagingMessages'); - pushNotification(userId, 'readAllMessagingMessages', undefined); + publishMainStream(userId, "readAllMessagingMessages"); + pushNotification(userId, "readAllMessagingMessages", undefined); } else { // そのグループにおいて未読がなければイベント発行 - const unreadExist = await MessagingMessages.createQueryBuilder('message') - .where(`message.groupId = :groupId`, { groupId: groupId }) - .andWhere('message.userId != :userId', { userId: userId }) - .andWhere('NOT (:userId = ANY(message.reads))', { userId: userId }) - .andWhere('message.createdAt > :joinedAt', { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない - .getOne().then(x => x != null); + const unreadExist = await MessagingMessages.createQueryBuilder("message") + .where("message.groupId = :groupId", { groupId: groupId }) + .andWhere("message.userId != :userId", { userId: userId }) + .andWhere("NOT (:userId = ANY(message.reads))", { userId: userId }) + .andWhere("message.createdAt > :joinedAt", { + joinedAt: joining.createdAt, + }) // 自分が加入する前の会話については、未読扱いしない + .getOne() + .then((x) => x != null); if (!unreadExist) { - pushNotification(userId, 'readAllMessagingMessagesOfARoom', { groupId }); + pushNotification(userId, "readAllMessagingMessagesOfARoom", { groupId }); } } } -export async function deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) { - messages = toArray(messages).filter(x => x.uri); - const contents = messages.map(x => renderReadActivity(user, x)); +export async function deliverReadActivity( + user: { id: User["id"]; host: null }, + recipient: IRemoteUser, + messages: MessagingMessage | MessagingMessage[], +) { + messages = toArray(messages).filter((x) => x.uri); + const contents = messages.map((x) => renderReadActivity(user, x)); if (contents.length > 1) { - const collection = orderedCollection(null, contents.length, undefined, undefined, contents); + const collection = orderedCollection( + null, + contents.length, + undefined, + undefined, + contents, + ); deliver(user, renderActivity(collection), recipient.inbox); } else { for (const content of contents) { diff --git a/packages/backend/src/server/api/common/read-notification.ts b/packages/backend/src/server/api/common/read-notification.ts index b0d38a9e3..1fb1d642f 100644 --- a/packages/backend/src/server/api/common/read-notification.ts +++ b/packages/backend/src/server/api/common/read-notification.ts @@ -1,50 +1,59 @@ -import { In } from 'typeorm'; -import { publishMainStream } from '@/services/stream.js'; -import { pushNotification } from '@/services/push-notification.js'; -import { User } from '@/models/entities/user.js'; -import { Notification } from '@/models/entities/notification.js'; -import { Notifications, Users } from '@/models/index.js'; +import { In } from "typeorm"; +import { publishMainStream } from "@/services/stream.js"; +import { pushNotification } from "@/services/push-notification.js"; +import type { User } from "@/models/entities/user.js"; +import type { Notification } from "@/models/entities/notification.js"; +import { Notifications, Users } from "@/models/index.js"; export async function readNotification( - userId: User['id'], - notificationIds: Notification['id'][], + userId: User["id"], + notificationIds: Notification["id"][], ) { if (notificationIds.length === 0) return; // Update documents - const result = await Notifications.update({ - notifieeId: userId, - id: In(notificationIds), - isRead: false, - }, { - isRead: true, - }); + const result = await Notifications.update( + { + notifieeId: userId, + id: In(notificationIds), + isRead: false, + }, + { + isRead: true, + }, + ); if (result.affected === 0) return; - if (!await Users.getHasUnreadNotification(userId)) return postReadAllNotifications(userId); + if (!(await Users.getHasUnreadNotification(userId))) + return postReadAllNotifications(userId); else return postReadNotifications(userId, notificationIds); } export async function readNotificationByQuery( - userId: User['id'], + userId: User["id"], query: Record, ) { const notificationIds = await Notifications.findBy({ ...query, notifieeId: userId, isRead: false, - }).then(notifications => notifications.map(notification => notification.id)); + }).then((notifications) => + notifications.map((notification) => notification.id), + ); return readNotification(userId, notificationIds); } -function postReadAllNotifications(userId: User['id']) { - publishMainStream(userId, 'readAllNotifications'); - return pushNotification(userId, 'readAllNotifications', undefined); +function postReadAllNotifications(userId: User["id"]) { + publishMainStream(userId, "readAllNotifications"); + return pushNotification(userId, "readAllNotifications", undefined); } -function postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) { - publishMainStream(userId, 'readNotifications', notificationIds); - return pushNotification(userId, 'readNotifications', { notificationIds }); +function postReadNotifications( + userId: User["id"], + notificationIds: Notification["id"][], +) { + publishMainStream(userId, "readNotifications", notificationIds); + return pushNotification(userId, "readNotifications", { notificationIds }); } diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts index 038fd8d96..a8a435843 100644 --- a/packages/backend/src/server/api/common/signin.ts +++ b/packages/backend/src/server/api/common/signin.ts @@ -1,19 +1,19 @@ -import Koa from 'koa'; +import type Koa from "koa"; -import config from '@/config/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { Signins } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { publishMainStream } from '@/services/stream.js'; +import config from "@/config/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { Signins } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { publishMainStream } from "@/services/stream.js"; -export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { +export default function (ctx: Koa.Context, user: ILocalUser, redirect = false) { if (redirect) { //#region Cookie - ctx.cookies.set('igi', user.token!, { - path: '/', + ctx.cookies.set("igi", user.token!, { + path: "/", // SEE: https://github.com/koajs/koa/issues/974 // When using a SSL proxy it should be configured to add the "X-Forwarded-Proto: https" header - secure: config.url.startsWith('https'), + secure: config.url.startsWith("https"), httpOnly: false, }); //#endregion @@ -36,9 +36,9 @@ export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { ip: ctx.ip, headers: ctx.headers, success: true, - }).then(x => Signins.findOneByOrFail(x.identifiers[0])); + }).then((x) => Signins.findOneByOrFail(x.identifiers[0])); // Publish signin event - publishMainStream(user.id, 'signin', await Signins.pack(record)); + publishMainStream(user.id, "signin", await Signins.pack(record)); })(); } diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts index a1993cacd..7ae9e10fb 100644 --- a/packages/backend/src/server/api/common/signup.ts +++ b/packages/backend/src/server/api/common/signup.ts @@ -1,22 +1,22 @@ -import bcrypt from 'bcryptjs'; -import { generateKeyPair } from 'node:crypto'; -import generateUserToken from './generate-native-user-token.js'; -import { User } from '@/models/entities/user.js'; -import { Users, UsedUsernames } from '@/models/index.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { IsNull } from 'typeorm'; -import { genId } from '@/misc/gen-id.js'; -import { toPunyNullable } from '@/misc/convert-host.js'; -import { UserKeypair } from '@/models/entities/user-keypair.js'; -import { usersChart } from '@/services/chart/index.js'; -import { UsedUsername } from '@/models/entities/used-username.js'; -import { db } from '@/db/postgre.js'; -import config from '@/config/index.js'; +import bcrypt from "bcryptjs"; +import { generateKeyPair } from "node:crypto"; +import generateUserToken from "./generate-native-user-token.js"; +import { User } from "@/models/entities/user.js"; +import { Users, UsedUsernames } from "@/models/index.js"; +import { UserProfile } from "@/models/entities/user-profile.js"; +import { IsNull } from "typeorm"; +import { genId } from "@/misc/gen-id.js"; +import { toPunyNullable } from "@/misc/convert-host.js"; +import { UserKeypair } from "@/models/entities/user-keypair.js"; +import { usersChart } from "@/services/chart/index.js"; +import { UsedUsername } from "@/models/entities/used-username.js"; +import { db } from "@/db/postgre.js"; +import config from "@/config/index.js"; export async function signup(opts: { - username: User['username']; + username: User["username"]; password?: string | null; - passwordHash?: UserProfile['password'] | null; + passwordHash?: UserProfile["password"] | null; host?: string | null; }) { const { username, password, passwordHash, host } = opts; @@ -27,18 +27,18 @@ export async function signup(opts: { }); if (config.maxUserSignups != null && userCount > config.maxUserSignups) { - throw new Error('MAX_USERS_REACHED'); + throw new Error("MAX_USERS_REACHED"); } // Validate username if (!Users.validateLocalUsername(username)) { - throw new Error('INVALID_USERNAME'); + throw new Error("INVALID_USERNAME"); } if (password != null && passwordHash == null) { // Validate password if (!Users.validatePassword(password)) { - throw new Error('INVALID_PASSWORD'); + throw new Error("INVALID_PASSWORD"); } // Generate hash of password @@ -50,71 +50,89 @@ export async function signup(opts: { const secret = generateUserToken(); // Check username duplication - if (await Users.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) { - throw new Error('DUPLICATED_USERNAME'); + if ( + await Users.findOneBy({ + usernameLower: username.toLowerCase(), + host: IsNull(), + }) + ) { + throw new Error("DUPLICATED_USERNAME"); } // Check deleted username duplication if (await UsedUsernames.findOneBy({ username: username.toLowerCase() })) { - throw new Error('USED_USERNAME'); + throw new Error("USED_USERNAME"); } const keyPair = await new Promise((res, rej) => - generateKeyPair('rsa', { - modulusLength: 4096, - publicKeyEncoding: { - type: 'spki', - format: 'pem', - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: undefined, - passphrase: undefined, - }, - } as any, (err, publicKey, privateKey) => - err ? rej(err) : res([publicKey, privateKey]) - )); + generateKeyPair( + "rsa", + { + modulusLength: 4096, + publicKeyEncoding: { + type: "spki", + format: "pem", + }, + privateKeyEncoding: { + type: "pkcs8", + format: "pem", + cipher: undefined, + passphrase: undefined, + }, + } as any, + (err, publicKey, privateKey) => + err ? rej(err) : res([publicKey, privateKey]), + ), + ); let account!: User; // Start transaction - await db.transaction(async transactionalEntityManager => { + await db.transaction(async (transactionalEntityManager) => { const exist = await transactionalEntityManager.findOneBy(User, { usernameLower: username.toLowerCase(), host: IsNull(), }); - if (exist) throw new Error(' the username is already used'); + if (exist) throw new Error(" the username is already used"); - account = await transactionalEntityManager.save(new User({ - id: genId(), - createdAt: new Date(), - username: username, - usernameLower: username.toLowerCase(), - host: toPunyNullable(host), - token: secret, - isAdmin: (await Users.countBy({ - host: IsNull(), - })) === 0, - })); + account = await transactionalEntityManager.save( + new User({ + id: genId(), + createdAt: new Date(), + username: username, + usernameLower: username.toLowerCase(), + host: toPunyNullable(host), + token: secret, + isAdmin: + (await Users.countBy({ + host: IsNull(), + })) === 0, + }), + ); - await transactionalEntityManager.save(new UserKeypair({ - publicKey: keyPair[0], - privateKey: keyPair[1], - userId: account.id, - })); + await transactionalEntityManager.save( + new UserKeypair({ + publicKey: keyPair[0], + privateKey: keyPair[1], + userId: account.id, + }), + ); - await transactionalEntityManager.save(new UserProfile({ - userId: account.id, - autoAcceptFollowed: true, - password: hash, - })); + await transactionalEntityManager.save( + new UserProfile({ + userId: account.id, + autoAcceptFollowed: true, + password: hash, + }), + ); - await transactionalEntityManager.save(new UsedUsername({ - createdAt: new Date(), - username: username.toLowerCase(), - })); + await transactionalEntityManager.save( + new UsedUsername({ + createdAt: new Date(), + username: username.toLowerCase(), + }), + ); }); usersChart.update(account, true); diff --git a/packages/backend/src/server/api/compatibility.ts b/packages/backend/src/server/api/compatibility.ts new file mode 100644 index 000000000..7e44fa8b2 --- /dev/null +++ b/packages/backend/src/server/api/compatibility.ts @@ -0,0 +1,20 @@ +import type { IEndpoint } from "./endpoints"; + +import * as cp___instanceInfo from "./endpoints/compatibility/instance-info.js"; +import * as cp___customEmojis from "./endpoints/compatibility/custom-emojis.js"; + +const cps = [ + ["v1/instance", cp___instanceInfo], + ["v1/custom_emojis", cp___customEmojis], +]; + +const compatibility: IEndpoint[] = cps.map(([name, cp]) => { + return { + name: name, + exec: cp.default, + meta: cp.meta || {}, + params: cp.paramDef, + } as IEndpoint; +}); + +export default compatibility; diff --git a/packages/backend/src/server/api/define.ts b/packages/backend/src/server/api/define.ts index c1b56b8a8..ee0844185 100644 --- a/packages/backend/src/server/api/define.ts +++ b/packages/backend/src/server/api/define.ts @@ -1,29 +1,61 @@ -import * as fs from 'node:fs'; -import Ajv from 'ajv'; -import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js'; -import { Schema, SchemaType } from '@/misc/schema.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { IEndpointMeta } from './endpoints.js'; -import { ApiError } from './error.js'; +import * as fs from "node:fs"; +import Ajv from "ajv"; +import type { CacheableLocalUser } from "@/models/entities/user.js"; +import { ILocalUser } from "@/models/entities/user.js"; +import type { Schema, SchemaType } from "@/misc/schema.js"; +import type { AccessToken } from "@/models/entities/access-token.js"; +import type { IEndpointMeta } from "./endpoints.js"; +import { ApiError } from "./error.js"; export type Response = Record | void; // TODO: paramsの型をT['params']のスキーマ定義から推論する -type executor = - (params: SchemaType, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any, cleanup?: () => any, ip?: string | null, headers?: Record | null) => - Promise>>; +type executor = ( + params: SchemaType, + user: T["requireCredential"] extends true + ? CacheableLocalUser + : CacheableLocalUser | null, + token: AccessToken | null, + file?: any, + cleanup?: () => any, + ip?: string | null, + headers?: Record | null, +) => Promise< + T["res"] extends undefined ? Response : SchemaType> +>; const ajv = new Ajv({ useDefaults: true, }); -ajv.addFormat('misskey:id', /^[a-zA-Z0-9]+$/); +ajv.addFormat("misskey:id", /^[a-zA-Z0-9]+$/); -export default function (meta: T, paramDef: Ps, cb: executor) - : (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any, ip?: string | null, headers?: Record | null) => Promise { +export default function ( + meta: T, + paramDef: Ps, + cb: executor, +): ( + params: any, + user: T["requireCredential"] extends true + ? CacheableLocalUser + : CacheableLocalUser | null, + token: AccessToken | null, + file?: any, + ip?: string | null, + headers?: Record | null, +) => Promise { const validate = ajv.compile(paramDef); - return (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any, ip?: string | null, headers?: Record | null) => { + return ( + params: any, + user: T["requireCredential"] extends true + ? CacheableLocalUser + : CacheableLocalUser | null, + token: AccessToken | null, + file?: any, + ip?: string | null, + headers?: Record | null, + ) => { let cleanup: undefined | (() => void) = undefined; if (meta.requireFile) { @@ -31,11 +63,14 @@ export default function (meta: T, pa fs.unlink(file.path, () => {}); }; - if (file == null) return Promise.reject(new ApiError({ - message: 'File required.', - code: 'FILE_REQUIRED', - id: '4267801e-70d1-416a-b011-4ee502885d8b', - })); + if (file == null) + return Promise.reject( + new ApiError({ + message: "File required.", + code: "FILE_REQUIRED", + id: "4267801e-70d1-416a-b011-4ee502885d8b", + }), + ); } const valid = validate(params); @@ -43,17 +78,28 @@ export default function (meta: T, pa if (file) cleanup!(); const errors = validate.errors!; - const err = new ApiError({ - message: 'Invalid param.', - code: 'INVALID_PARAM', - id: '3d81ceae-475f-4600-b2a8-2bc116157532', - }, { - param: errors[0].schemaPath, - reason: errors[0].message, - }); + const err = new ApiError( + { + message: "Invalid param.", + code: "INVALID_PARAM", + id: "3d81ceae-475f-4600-b2a8-2bc116157532", + }, + { + param: errors[0].schemaPath, + reason: errors[0].message, + }, + ); return Promise.reject(err); } - return cb(params as SchemaType, user, token, file, cleanup, ip, headers); + return cb( + params as SchemaType, + user, + token, + file, + cleanup, + ip, + headers, + ); }; } diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 912998376..b6d9c3e1f 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -1,665 +1,675 @@ -import { Schema } from '@/misc/schema.js'; +import type { Schema } from "@/misc/schema.js"; -import * as ep___admin_meta from './endpoints/admin/meta.js'; -import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; -import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; -import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; -import * as ep___admin_accounts_hosted from './endpoints/admin/accounts/hosted.js'; -import * as ep___admin_ad_create from './endpoints/admin/ad/create.js'; -import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js'; -import * as ep___admin_ad_list from './endpoints/admin/ad/list.js'; -import * as ep___admin_ad_update from './endpoints/admin/ad/update.js'; -import * as ep___admin_announcements_create from './endpoints/admin/announcements/create.js'; -import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js'; -import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js'; -import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js'; -import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; -import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; -import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; -import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; -import * as ep___admin_drive_showFile from './endpoints/admin/drive/show-file.js'; -import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-aliases-bulk.js'; -import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js'; -import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js'; -import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js'; -import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js'; -import * as ep___admin_emoji_importZip from './endpoints/admin/emoji/import-zip.js'; -import * as ep___admin_emoji_listRemote from './endpoints/admin/emoji/list-remote.js'; -import * as ep___admin_emoji_list from './endpoints/admin/emoji/list.js'; -import * as ep___admin_emoji_removeAliasesBulk from './endpoints/admin/emoji/remove-aliases-bulk.js'; -import * as ep___admin_emoji_setAliasesBulk from './endpoints/admin/emoji/set-aliases-bulk.js'; -import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-category-bulk.js'; -import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js'; -import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js'; -import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; -import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js'; -import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js'; -import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; -import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; -import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js'; -import * as ep___admin_invite from './endpoints/admin/invite.js'; -import * as ep___admin_moderators_add from './endpoints/admin/moderators/add.js'; -import * as ep___admin_moderators_remove from './endpoints/admin/moderators/remove.js'; -import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; -import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; -import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; -import * as ep___admin_queue_inboxDelayed from './endpoints/admin/queue/inbox-delayed.js'; -import * as ep___admin_queue_stats from './endpoints/admin/queue/stats.js'; -import * as ep___admin_relays_add from './endpoints/admin/relays/add.js'; -import * as ep___admin_relays_list from './endpoints/admin/relays/list.js'; -import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js'; -import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js'; -import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js'; -import * as ep___admin_sendEmail from './endpoints/admin/send-email.js'; -import * as ep___admin_serverInfo from './endpoints/admin/server-info.js'; -import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js'; -import * as ep___admin_showUser from './endpoints/admin/show-user.js'; -import * as ep___admin_showUsers from './endpoints/admin/show-users.js'; -import * as ep___admin_silenceUser from './endpoints/admin/silence-user.js'; -import * as ep___admin_suspendUser from './endpoints/admin/suspend-user.js'; -import * as ep___admin_unsilenceUser from './endpoints/admin/unsilence-user.js'; -import * as ep___admin_unsuspendUser from './endpoints/admin/unsuspend-user.js'; -import * as ep___admin_updateMeta from './endpoints/admin/update-meta.js'; -import * as ep___admin_vacuum from './endpoints/admin/vacuum.js'; -import * as ep___admin_deleteAccount from './endpoints/admin/delete-account.js'; -import * as ep___admin_updateUserNote from './endpoints/admin/update-user-note.js'; -import * as ep___announcements from './endpoints/announcements.js'; -import * as ep___antennas_create from './endpoints/antennas/create.js'; -import * as ep___antennas_delete from './endpoints/antennas/delete.js'; -import * as ep___antennas_list from './endpoints/antennas/list.js'; -import * as ep___antennas_notes from './endpoints/antennas/notes.js'; -import * as ep___antennas_show from './endpoints/antennas/show.js'; -import * as ep___antennas_update from './endpoints/antennas/update.js'; -import * as ep___ap_get from './endpoints/ap/get.js'; -import * as ep___ap_show from './endpoints/ap/show.js'; -import * as ep___app_create from './endpoints/app/create.js'; -import * as ep___app_show from './endpoints/app/show.js'; -import * as ep___auth_accept from './endpoints/auth/accept.js'; -import * as ep___auth_session_generate from './endpoints/auth/session/generate.js'; -import * as ep___auth_session_show from './endpoints/auth/session/show.js'; -import * as ep___auth_session_userkey from './endpoints/auth/session/userkey.js'; -import * as ep___blocking_create from './endpoints/blocking/create.js'; -import * as ep___blocking_delete from './endpoints/blocking/delete.js'; -import * as ep___blocking_list from './endpoints/blocking/list.js'; -import * as ep___channels_create from './endpoints/channels/create.js'; -import * as ep___channels_featured from './endpoints/channels/featured.js'; -import * as ep___channels_follow from './endpoints/channels/follow.js'; -import * as ep___channels_followed from './endpoints/channels/followed.js'; -import * as ep___channels_owned from './endpoints/channels/owned.js'; -import * as ep___channels_show from './endpoints/channels/show.js'; -import * as ep___channels_timeline from './endpoints/channels/timeline.js'; -import * as ep___channels_unfollow from './endpoints/channels/unfollow.js'; -import * as ep___channels_update from './endpoints/channels/update.js'; -import * as ep___charts_activeUsers from './endpoints/charts/active-users.js'; -import * as ep___charts_apRequest from './endpoints/charts/ap-request.js'; -import * as ep___charts_drive from './endpoints/charts/drive.js'; -import * as ep___charts_federation from './endpoints/charts/federation.js'; -import * as ep___charts_hashtag from './endpoints/charts/hashtag.js'; -import * as ep___charts_instance from './endpoints/charts/instance.js'; -import * as ep___charts_notes from './endpoints/charts/notes.js'; -import * as ep___charts_user_drive from './endpoints/charts/user/drive.js'; -import * as ep___charts_user_following from './endpoints/charts/user/following.js'; -import * as ep___charts_user_notes from './endpoints/charts/user/notes.js'; -import * as ep___charts_user_reactions from './endpoints/charts/user/reactions.js'; -import * as ep___charts_users from './endpoints/charts/users.js'; -import * as ep___clips_addNote from './endpoints/clips/add-note.js'; -import * as ep___clips_removeNote from './endpoints/clips/remove-note.js'; -import * as ep___clips_create from './endpoints/clips/create.js'; -import * as ep___clips_delete from './endpoints/clips/delete.js'; -import * as ep___clips_list from './endpoints/clips/list.js'; -import * as ep___clips_notes from './endpoints/clips/notes.js'; -import * as ep___clips_show from './endpoints/clips/show.js'; -import * as ep___clips_update from './endpoints/clips/update.js'; -import * as ep___drive from './endpoints/drive.js'; -import * as ep___drive_files from './endpoints/drive/files.js'; -import * as ep___drive_files_attachedNotes from './endpoints/drive/files/attached-notes.js'; -import * as ep___drive_files_checkExistence from './endpoints/drive/files/check-existence.js'; -import * as ep___drive_files_captionImage from './endpoints/drive/files/caption-image.js'; -import * as ep___drive_files_create from './endpoints/drive/files/create.js'; -import * as ep___drive_files_delete from './endpoints/drive/files/delete.js'; -import * as ep___drive_files_findByHash from './endpoints/drive/files/find-by-hash.js'; -import * as ep___drive_files_find from './endpoints/drive/files/find.js'; -import * as ep___drive_files_show from './endpoints/drive/files/show.js'; -import * as ep___drive_files_update from './endpoints/drive/files/update.js'; -import * as ep___drive_files_uploadFromUrl from './endpoints/drive/files/upload-from-url.js'; -import * as ep___drive_folders from './endpoints/drive/folders.js'; -import * as ep___drive_folders_create from './endpoints/drive/folders/create.js'; -import * as ep___drive_folders_delete from './endpoints/drive/folders/delete.js'; -import * as ep___drive_folders_find from './endpoints/drive/folders/find.js'; -import * as ep___drive_folders_show from './endpoints/drive/folders/show.js'; -import * as ep___drive_folders_update from './endpoints/drive/folders/update.js'; -import * as ep___drive_stream from './endpoints/drive/stream.js'; -import * as ep___emailAddress_available from './endpoints/email-address/available.js'; -import * as ep___endpoint from './endpoints/endpoint.js'; -import * as ep___endpoints from './endpoints/endpoints.js'; -import * as ep___exportCustomEmojis from './endpoints/export-custom-emojis.js'; -import * as ep___federation_followers from './endpoints/federation/followers.js'; -import * as ep___federation_following from './endpoints/federation/following.js'; -import * as ep___federation_instances from './endpoints/federation/instances.js'; -import * as ep___federation_showInstance from './endpoints/federation/show-instance.js'; -import * as ep___federation_updateRemoteUser from './endpoints/federation/update-remote-user.js'; -import * as ep___federation_users from './endpoints/federation/users.js'; -import * as ep___federation_stats from './endpoints/federation/stats.js'; -import * as ep___following_create from './endpoints/following/create.js'; -import * as ep___following_delete from './endpoints/following/delete.js'; -import * as ep___following_invalidate from './endpoints/following/invalidate.js'; -import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; -import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; -import * as ep___following_requests_list from './endpoints/following/requests/list.js'; -import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; -import * as ep___gallery_featured from './endpoints/gallery/featured.js'; -import * as ep___gallery_popular from './endpoints/gallery/popular.js'; -import * as ep___gallery_posts from './endpoints/gallery/posts.js'; -import * as ep___gallery_posts_create from './endpoints/gallery/posts/create.js'; -import * as ep___gallery_posts_delete from './endpoints/gallery/posts/delete.js'; -import * as ep___gallery_posts_like from './endpoints/gallery/posts/like.js'; -import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js'; -import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js'; -import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js'; -import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js'; -import * as ep___hashtags_list from './endpoints/hashtags/list.js'; -import * as ep___hashtags_search from './endpoints/hashtags/search.js'; -import * as ep___hashtags_show from './endpoints/hashtags/show.js'; -import * as ep___hashtags_trend from './endpoints/hashtags/trend.js'; -import * as ep___hashtags_users from './endpoints/hashtags/users.js'; -import * as ep___i from './endpoints/i.js'; -import * as ep___i_2fa_done from './endpoints/i/2fa/done.js'; -import * as ep___i_2fa_keyDone from './endpoints/i/2fa/key-done.js'; -import * as ep___i_2fa_passwordLess from './endpoints/i/2fa/password-less.js'; -import * as ep___i_2fa_registerKey from './endpoints/i/2fa/register-key.js'; -import * as ep___i_2fa_register from './endpoints/i/2fa/register.js'; -import * as ep___i_2fa_removeKey from './endpoints/i/2fa/remove-key.js'; -import * as ep___i_2fa_unregister from './endpoints/i/2fa/unregister.js'; -import * as ep___i_apps from './endpoints/i/apps.js'; -import * as ep___i_authorizedApps from './endpoints/i/authorized-apps.js'; -import * as ep___i_changePassword from './endpoints/i/change-password.js'; -import * as ep___i_deleteAccount from './endpoints/i/delete-account.js'; -import * as ep___i_exportBlocking from './endpoints/i/export-blocking.js'; -import * as ep___i_exportFollowing from './endpoints/i/export-following.js'; -import * as ep___i_exportMute from './endpoints/i/export-mute.js'; -import * as ep___i_exportNotes from './endpoints/i/export-notes.js'; -import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js'; -import * as ep___i_favorites from './endpoints/i/favorites.js'; -import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js'; -import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js'; -import * as ep___i_getWordMutedNotesCount from './endpoints/i/get-word-muted-notes-count.js'; -import * as ep___i_importBlocking from './endpoints/i/import-blocking.js'; -import * as ep___i_importFollowing from './endpoints/i/import-following.js'; -import * as ep___i_importMuting from './endpoints/i/import-muting.js'; -import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js'; -import * as ep___i_notifications from './endpoints/i/notifications.js'; -import * as ep___i_pageLikes from './endpoints/i/page-likes.js'; -import * as ep___i_pages from './endpoints/i/pages.js'; -import * as ep___i_pin from './endpoints/i/pin.js'; -import * as ep___i_readAllMessagingMessages from './endpoints/i/read-all-messaging-messages.js'; -import * as ep___i_readAllUnreadNotes from './endpoints/i/read-all-unread-notes.js'; -import * as ep___i_readAnnouncement from './endpoints/i/read-announcement.js'; -import * as ep___i_regenerateToken from './endpoints/i/regenerate-token.js'; -import * as ep___i_registry_getAll from './endpoints/i/registry/get-all.js'; -import * as ep___i_registry_getDetail from './endpoints/i/registry/get-detail.js'; -import * as ep___i_registry_get from './endpoints/i/registry/get.js'; -import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js'; -import * as ep___i_registry_keys from './endpoints/i/registry/keys.js'; -import * as ep___i_registry_remove from './endpoints/i/registry/remove.js'; -import * as ep___i_registry_scopes from './endpoints/i/registry/scopes.js'; -import * as ep___i_registry_set from './endpoints/i/registry/set.js'; -import * as ep___i_revokeToken from './endpoints/i/revoke-token.js'; -import * as ep___i_signinHistory from './endpoints/i/signin-history.js'; -import * as ep___i_unpin from './endpoints/i/unpin.js'; -import * as ep___i_updateEmail from './endpoints/i/update-email.js'; -import * as ep___i_update from './endpoints/i/update.js'; -import * as ep___i_userGroupInvites from './endpoints/i/user-group-invites.js'; -import * as ep___i_webhooks_create from './endpoints/i/webhooks/create.js'; -import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js'; -import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js'; -import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js'; -import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js'; -import * as ep___messaging_history from './endpoints/messaging/history.js'; -import * as ep___messaging_messages from './endpoints/messaging/messages.js'; -import * as ep___messaging_messages_create from './endpoints/messaging/messages/create.js'; -import * as ep___messaging_messages_delete from './endpoints/messaging/messages/delete.js'; -import * as ep___messaging_messages_read from './endpoints/messaging/messages/read.js'; -import * as ep___meta from './endpoints/meta.js'; -import * as ep___miauth_genToken from './endpoints/miauth/gen-token.js'; -import * as ep___mute_create from './endpoints/mute/create.js'; -import * as ep___mute_delete from './endpoints/mute/delete.js'; -import * as ep___mute_list from './endpoints/mute/list.js'; -import * as ep___my_apps from './endpoints/my/apps.js'; -import * as ep___notes from './endpoints/notes.js'; -import * as ep___notes_children from './endpoints/notes/children.js'; -import * as ep___notes_clips from './endpoints/notes/clips.js'; -import * as ep___notes_conversation from './endpoints/notes/conversation.js'; -import * as ep___notes_create from './endpoints/notes/create.js'; -import * as ep___notes_delete from './endpoints/notes/delete.js'; -import * as ep___notes_favorites_create from './endpoints/notes/favorites/create.js'; -import * as ep___notes_favorites_delete from './endpoints/notes/favorites/delete.js'; -import * as ep___notes_featured from './endpoints/notes/featured.js'; -import * as ep___notes_globalTimeline from './endpoints/notes/global-timeline.js'; -import * as ep___notes_hybridTimeline from './endpoints/notes/hybrid-timeline.js'; -import * as ep___notes_localTimeline from './endpoints/notes/local-timeline.js'; -import * as ep___notes_recommendedTimeline from './endpoints/notes/recommended-timeline.js'; -import * as ep___notes_mentions from './endpoints/notes/mentions.js'; -import * as ep___notes_polls_recommendation from './endpoints/notes/polls/recommendation.js'; -import * as ep___notes_polls_vote from './endpoints/notes/polls/vote.js'; -import * as ep___notes_reactions from './endpoints/notes/reactions.js'; -import * as ep___notes_reactions_create from './endpoints/notes/reactions/create.js'; -import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; -import * as ep___notes_renotes from './endpoints/notes/renotes.js'; -import * as ep___notes_replies from './endpoints/notes/replies.js'; -import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; -import * as ep___notes_search from './endpoints/notes/search.js'; -import * as ep___notes_show from './endpoints/notes/show.js'; -import * as ep___notes_state from './endpoints/notes/state.js'; -import * as ep___notes_threadMuting_create from './endpoints/notes/thread-muting/create.js'; -import * as ep___notes_threadMuting_delete from './endpoints/notes/thread-muting/delete.js'; -import * as ep___notes_timeline from './endpoints/notes/timeline.js'; -import * as ep___notes_translate from './endpoints/notes/translate.js'; -import * as ep___notes_unrenote from './endpoints/notes/unrenote.js'; -import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js'; -import * as ep___notes_watching_create from './endpoints/notes/watching/create.js'; -import * as ep___notes_watching_delete from './endpoints/notes/watching/delete.js'; -import * as ep___notifications_create from './endpoints/notifications/create.js'; -import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js'; -import * as ep___notifications_read from './endpoints/notifications/read.js'; -import * as ep___pagePush from './endpoints/page-push.js'; -import * as ep___pages_create from './endpoints/pages/create.js'; -import * as ep___pages_delete from './endpoints/pages/delete.js'; -import * as ep___pages_featured from './endpoints/pages/featured.js'; -import * as ep___pages_like from './endpoints/pages/like.js'; -import * as ep___pages_show from './endpoints/pages/show.js'; -import * as ep___pages_unlike from './endpoints/pages/unlike.js'; -import * as ep___pages_update from './endpoints/pages/update.js'; -import * as ep___ping from './endpoints/ping.js'; -import * as ep___recommendedInstances from './endpoints/recommended-instances.js'; -import * as ep___pinnedUsers from './endpoints/pinned-users.js'; -import * as ep___customMOTD from './endpoints/custom-motd.js'; -import * as ep___customSplashIcons from './endpoints/custom-splash-icons.js'; -import * as ep___latestVersion from './endpoints/latest-version.js'; -import * as ep___patrons from './endpoints/patrons.js'; -import * as ep___promo_read from './endpoints/promo/read.js'; -import * as ep___requestResetPassword from './endpoints/request-reset-password.js'; -import * as ep___resetDb from './endpoints/reset-db.js'; -import * as ep___resetPassword from './endpoints/reset-password.js'; -import * as ep___serverInfo from './endpoints/server-info.js'; -import * as ep___stats from './endpoints/stats.js'; -import * as ep___sw_register from './endpoints/sw/register.js'; -import * as ep___sw_unregister from './endpoints/sw/unregister.js'; -import * as ep___test from './endpoints/test.js'; -import * as ep___username_available from './endpoints/username/available.js'; -import * as ep___users from './endpoints/users.js'; -import * as ep___users_clips from './endpoints/users/clips.js'; -import * as ep___users_followers from './endpoints/users/followers.js'; -import * as ep___users_following from './endpoints/users/following.js'; -import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js'; -import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js'; -import * as ep___users_groups_create from './endpoints/users/groups/create.js'; -import * as ep___users_groups_delete from './endpoints/users/groups/delete.js'; -import * as ep___users_groups_invitations_accept from './endpoints/users/groups/invitations/accept.js'; -import * as ep___users_groups_invitations_reject from './endpoints/users/groups/invitations/reject.js'; -import * as ep___users_groups_invite from './endpoints/users/groups/invite.js'; -import * as ep___users_groups_joined from './endpoints/users/groups/joined.js'; -import * as ep___users_groups_leave from './endpoints/users/groups/leave.js'; -import * as ep___users_groups_owned from './endpoints/users/groups/owned.js'; -import * as ep___users_groups_pull from './endpoints/users/groups/pull.js'; -import * as ep___users_groups_show from './endpoints/users/groups/show.js'; -import * as ep___users_groups_transfer from './endpoints/users/groups/transfer.js'; -import * as ep___users_groups_update from './endpoints/users/groups/update.js'; -import * as ep___users_lists_create from './endpoints/users/lists/create.js'; -import * as ep___users_lists_delete from './endpoints/users/lists/delete.js'; -import * as ep___users_lists_delete_all from './endpoints/users/lists/delete-all.js'; -import * as ep___users_lists_list from './endpoints/users/lists/list.js'; -import * as ep___users_lists_pull from './endpoints/users/lists/pull.js'; -import * as ep___users_lists_push from './endpoints/users/lists/push.js'; -import * as ep___users_lists_show from './endpoints/users/lists/show.js'; -import * as ep___users_lists_update from './endpoints/users/lists/update.js'; -import * as ep___users_notes from './endpoints/users/notes.js'; -import * as ep___users_pages from './endpoints/users/pages.js'; -import * as ep___users_reactions from './endpoints/users/reactions.js'; -import * as ep___users_recommendation from './endpoints/users/recommendation.js'; -import * as ep___users_relation from './endpoints/users/relation.js'; -import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js'; -import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js'; -import * as ep___users_search from './endpoints/users/search.js'; -import * as ep___users_show from './endpoints/users/show.js'; -import * as ep___users_stats from './endpoints/users/stats.js'; -import * as ep___fetchRss from './endpoints/fetch-rss.js'; -import * as ep___admin_driveCapOverride from './endpoints/admin/drive-capacity-override.js'; +import * as ep___admin_meta from "./endpoints/admin/meta.js"; +import * as ep___admin_abuseUserReports from "./endpoints/admin/abuse-user-reports.js"; +import * as ep___admin_accounts_create from "./endpoints/admin/accounts/create.js"; +import * as ep___admin_accounts_delete from "./endpoints/admin/accounts/delete.js"; +import * as ep___admin_accounts_hosted from "./endpoints/admin/accounts/hosted.js"; +import * as ep___admin_ad_create from "./endpoints/admin/ad/create.js"; +import * as ep___admin_ad_delete from "./endpoints/admin/ad/delete.js"; +import * as ep___admin_ad_list from "./endpoints/admin/ad/list.js"; +import * as ep___admin_ad_update from "./endpoints/admin/ad/update.js"; +import * as ep___admin_announcements_create from "./endpoints/admin/announcements/create.js"; +import * as ep___admin_announcements_delete from "./endpoints/admin/announcements/delete.js"; +import * as ep___admin_announcements_list from "./endpoints/admin/announcements/list.js"; +import * as ep___admin_announcements_update from "./endpoints/admin/announcements/update.js"; +import * as ep___admin_deleteAllFilesOfAUser from "./endpoints/admin/delete-all-files-of-a-user.js"; +import * as ep___admin_drive_cleanRemoteFiles from "./endpoints/admin/drive/clean-remote-files.js"; +import * as ep___admin_drive_cleanup from "./endpoints/admin/drive/cleanup.js"; +import * as ep___admin_drive_files from "./endpoints/admin/drive/files.js"; +import * as ep___admin_drive_showFile from "./endpoints/admin/drive/show-file.js"; +import * as ep___admin_emoji_addAliasesBulk from "./endpoints/admin/emoji/add-aliases-bulk.js"; +import * as ep___admin_emoji_add from "./endpoints/admin/emoji/add.js"; +import * as ep___admin_emoji_copy from "./endpoints/admin/emoji/copy.js"; +import * as ep___admin_emoji_deleteBulk from "./endpoints/admin/emoji/delete-bulk.js"; +import * as ep___admin_emoji_delete from "./endpoints/admin/emoji/delete.js"; +import * as ep___admin_emoji_importZip from "./endpoints/admin/emoji/import-zip.js"; +import * as ep___admin_emoji_listRemote from "./endpoints/admin/emoji/list-remote.js"; +import * as ep___admin_emoji_list from "./endpoints/admin/emoji/list.js"; +import * as ep___admin_emoji_removeAliasesBulk from "./endpoints/admin/emoji/remove-aliases-bulk.js"; +import * as ep___admin_emoji_setAliasesBulk from "./endpoints/admin/emoji/set-aliases-bulk.js"; +import * as ep___admin_emoji_setCategoryBulk from "./endpoints/admin/emoji/set-category-bulk.js"; +import * as ep___admin_emoji_update from "./endpoints/admin/emoji/update.js"; +import * as ep___admin_federation_deleteAllFiles from "./endpoints/admin/federation/delete-all-files.js"; +import * as ep___admin_federation_refreshRemoteInstanceMetadata from "./endpoints/admin/federation/refresh-remote-instance-metadata.js"; +import * as ep___admin_federation_removeAllFollowing from "./endpoints/admin/federation/remove-all-following.js"; +import * as ep___admin_federation_updateInstance from "./endpoints/admin/federation/update-instance.js"; +import * as ep___admin_getIndexStats from "./endpoints/admin/get-index-stats.js"; +import * as ep___admin_getTableStats from "./endpoints/admin/get-table-stats.js"; +import * as ep___admin_getUserIps from "./endpoints/admin/get-user-ips.js"; +import * as ep___admin_invite from "./endpoints/admin/invite.js"; +import * as ep___admin_moderators_add from "./endpoints/admin/moderators/add.js"; +import * as ep___admin_moderators_remove from "./endpoints/admin/moderators/remove.js"; +import * as ep___admin_promo_create from "./endpoints/admin/promo/create.js"; +import * as ep___admin_queue_clear from "./endpoints/admin/queue/clear.js"; +import * as ep___admin_queue_deliverDelayed from "./endpoints/admin/queue/deliver-delayed.js"; +import * as ep___admin_queue_inboxDelayed from "./endpoints/admin/queue/inbox-delayed.js"; +import * as ep___admin_queue_stats from "./endpoints/admin/queue/stats.js"; +import * as ep___admin_relays_add from "./endpoints/admin/relays/add.js"; +import * as ep___admin_relays_list from "./endpoints/admin/relays/list.js"; +import * as ep___admin_relays_remove from "./endpoints/admin/relays/remove.js"; +import * as ep___admin_resetPassword from "./endpoints/admin/reset-password.js"; +import * as ep___admin_resolveAbuseUserReport from "./endpoints/admin/resolve-abuse-user-report.js"; +import * as ep___admin_sendEmail from "./endpoints/admin/send-email.js"; +import * as ep___admin_serverInfo from "./endpoints/admin/server-info.js"; +import * as ep___admin_showModerationLogs from "./endpoints/admin/show-moderation-logs.js"; +import * as ep___admin_showUser from "./endpoints/admin/show-user.js"; +import * as ep___admin_showUsers from "./endpoints/admin/show-users.js"; +import * as ep___admin_silenceUser from "./endpoints/admin/silence-user.js"; +import * as ep___admin_suspendUser from "./endpoints/admin/suspend-user.js"; +import * as ep___admin_unsilenceUser from "./endpoints/admin/unsilence-user.js"; +import * as ep___admin_unsuspendUser from "./endpoints/admin/unsuspend-user.js"; +import * as ep___admin_updateMeta from "./endpoints/admin/update-meta.js"; +import * as ep___admin_vacuum from "./endpoints/admin/vacuum.js"; +import * as ep___admin_deleteAccount from "./endpoints/admin/delete-account.js"; +import * as ep___admin_updateUserNote from "./endpoints/admin/update-user-note.js"; +import * as ep___announcements from "./endpoints/announcements.js"; +import * as ep___antennas_create from "./endpoints/antennas/create.js"; +import * as ep___antennas_delete from "./endpoints/antennas/delete.js"; +import * as ep___antennas_list from "./endpoints/antennas/list.js"; +import * as ep___antennas_markRead from "./endpoints/antennas/markread.js"; +import * as ep___antennas_notes from "./endpoints/antennas/notes.js"; +import * as ep___antennas_show from "./endpoints/antennas/show.js"; +import * as ep___antennas_update from "./endpoints/antennas/update.js"; +import * as ep___ap_get from "./endpoints/ap/get.js"; +import * as ep___ap_show from "./endpoints/ap/show.js"; +import * as ep___app_create from "./endpoints/app/create.js"; +import * as ep___app_show from "./endpoints/app/show.js"; +import * as ep___auth_accept from "./endpoints/auth/accept.js"; +import * as ep___auth_session_generate from "./endpoints/auth/session/generate.js"; +import * as ep___auth_session_show from "./endpoints/auth/session/show.js"; +import * as ep___auth_session_userkey from "./endpoints/auth/session/userkey.js"; +import * as ep___blocking_create from "./endpoints/blocking/create.js"; +import * as ep___blocking_delete from "./endpoints/blocking/delete.js"; +import * as ep___blocking_list from "./endpoints/blocking/list.js"; +import * as ep___channels_create from "./endpoints/channels/create.js"; +import * as ep___channels_featured from "./endpoints/channels/featured.js"; +import * as ep___channels_follow from "./endpoints/channels/follow.js"; +import * as ep___channels_followed from "./endpoints/channels/followed.js"; +import * as ep___channels_owned from "./endpoints/channels/owned.js"; +import * as ep___channels_show from "./endpoints/channels/show.js"; +import * as ep___channels_timeline from "./endpoints/channels/timeline.js"; +import * as ep___channels_unfollow from "./endpoints/channels/unfollow.js"; +import * as ep___channels_update from "./endpoints/channels/update.js"; +import * as ep___charts_activeUsers from "./endpoints/charts/active-users.js"; +import * as ep___charts_apRequest from "./endpoints/charts/ap-request.js"; +import * as ep___charts_drive from "./endpoints/charts/drive.js"; +import * as ep___charts_federation from "./endpoints/charts/federation.js"; +import * as ep___charts_hashtag from "./endpoints/charts/hashtag.js"; +import * as ep___charts_instance from "./endpoints/charts/instance.js"; +import * as ep___charts_notes from "./endpoints/charts/notes.js"; +import * as ep___charts_user_drive from "./endpoints/charts/user/drive.js"; +import * as ep___charts_user_following from "./endpoints/charts/user/following.js"; +import * as ep___charts_user_notes from "./endpoints/charts/user/notes.js"; +import * as ep___charts_user_reactions from "./endpoints/charts/user/reactions.js"; +import * as ep___charts_users from "./endpoints/charts/users.js"; +import * as ep___clips_addNote from "./endpoints/clips/add-note.js"; +import * as ep___clips_removeNote from "./endpoints/clips/remove-note.js"; +import * as ep___clips_create from "./endpoints/clips/create.js"; +import * as ep___clips_delete from "./endpoints/clips/delete.js"; +import * as ep___clips_list from "./endpoints/clips/list.js"; +import * as ep___clips_notes from "./endpoints/clips/notes.js"; +import * as ep___clips_show from "./endpoints/clips/show.js"; +import * as ep___clips_update from "./endpoints/clips/update.js"; +import * as ep___drive from "./endpoints/drive.js"; +import * as ep___drive_files from "./endpoints/drive/files.js"; +import * as ep___drive_files_attachedNotes from "./endpoints/drive/files/attached-notes.js"; +import * as ep___drive_files_checkExistence from "./endpoints/drive/files/check-existence.js"; +import * as ep___drive_files_captionImage from "./endpoints/drive/files/caption-image.js"; +import * as ep___drive_files_create from "./endpoints/drive/files/create.js"; +import * as ep___drive_files_delete from "./endpoints/drive/files/delete.js"; +import * as ep___drive_files_findByHash from "./endpoints/drive/files/find-by-hash.js"; +import * as ep___drive_files_find from "./endpoints/drive/files/find.js"; +import * as ep___drive_files_show from "./endpoints/drive/files/show.js"; +import * as ep___drive_files_update from "./endpoints/drive/files/update.js"; +import * as ep___drive_files_uploadFromUrl from "./endpoints/drive/files/upload-from-url.js"; +import * as ep___drive_folders from "./endpoints/drive/folders.js"; +import * as ep___drive_folders_create from "./endpoints/drive/folders/create.js"; +import * as ep___drive_folders_delete from "./endpoints/drive/folders/delete.js"; +import * as ep___drive_folders_find from "./endpoints/drive/folders/find.js"; +import * as ep___drive_folders_show from "./endpoints/drive/folders/show.js"; +import * as ep___drive_folders_update from "./endpoints/drive/folders/update.js"; +import * as ep___drive_stream from "./endpoints/drive/stream.js"; +import * as ep___emailAddress_available from "./endpoints/email-address/available.js"; +import * as ep___endpoint from "./endpoints/endpoint.js"; +import * as ep___endpoints from "./endpoints/endpoints.js"; +import * as ep___exportCustomEmojis from "./endpoints/export-custom-emojis.js"; +import * as ep___federation_followers from "./endpoints/federation/followers.js"; +import * as ep___federation_following from "./endpoints/federation/following.js"; +import * as ep___federation_instances from "./endpoints/federation/instances.js"; +import * as ep___federation_showInstance from "./endpoints/federation/show-instance.js"; +import * as ep___federation_updateRemoteUser from "./endpoints/federation/update-remote-user.js"; +import * as ep___federation_users from "./endpoints/federation/users.js"; +import * as ep___federation_stats from "./endpoints/federation/stats.js"; +import * as ep___following_create from "./endpoints/following/create.js"; +import * as ep___following_delete from "./endpoints/following/delete.js"; +import * as ep___following_invalidate from "./endpoints/following/invalidate.js"; +import * as ep___following_requests_accept from "./endpoints/following/requests/accept.js"; +import * as ep___following_requests_cancel from "./endpoints/following/requests/cancel.js"; +import * as ep___following_requests_list from "./endpoints/following/requests/list.js"; +import * as ep___following_requests_reject from "./endpoints/following/requests/reject.js"; +import * as ep___gallery_featured from "./endpoints/gallery/featured.js"; +import * as ep___gallery_popular from "./endpoints/gallery/popular.js"; +import * as ep___gallery_posts from "./endpoints/gallery/posts.js"; +import * as ep___gallery_posts_create from "./endpoints/gallery/posts/create.js"; +import * as ep___gallery_posts_delete from "./endpoints/gallery/posts/delete.js"; +import * as ep___gallery_posts_like from "./endpoints/gallery/posts/like.js"; +import * as ep___gallery_posts_show from "./endpoints/gallery/posts/show.js"; +import * as ep___gallery_posts_unlike from "./endpoints/gallery/posts/unlike.js"; +import * as ep___gallery_posts_update from "./endpoints/gallery/posts/update.js"; +import * as ep___getOnlineUsersCount from "./endpoints/get-online-users-count.js"; +import * as ep___hashtags_list from "./endpoints/hashtags/list.js"; +import * as ep___hashtags_search from "./endpoints/hashtags/search.js"; +import * as ep___hashtags_show from "./endpoints/hashtags/show.js"; +import * as ep___hashtags_trend from "./endpoints/hashtags/trend.js"; +import * as ep___hashtags_users from "./endpoints/hashtags/users.js"; +import * as ep___i from "./endpoints/i.js"; +import * as ep___i_2fa_done from "./endpoints/i/2fa/done.js"; +import * as ep___i_2fa_keyDone from "./endpoints/i/2fa/key-done.js"; +import * as ep___i_2fa_passwordLess from "./endpoints/i/2fa/password-less.js"; +import * as ep___i_2fa_registerKey from "./endpoints/i/2fa/register-key.js"; +import * as ep___i_2fa_register from "./endpoints/i/2fa/register.js"; +import * as ep___i_2fa_removeKey from "./endpoints/i/2fa/remove-key.js"; +import * as ep___i_2fa_unregister from "./endpoints/i/2fa/unregister.js"; +import * as ep___i_apps from "./endpoints/i/apps.js"; +import * as ep___i_authorizedApps from "./endpoints/i/authorized-apps.js"; +import * as ep___i_changePassword from "./endpoints/i/change-password.js"; +import * as ep___i_deleteAccount from "./endpoints/i/delete-account.js"; +import * as ep___i_exportBlocking from "./endpoints/i/export-blocking.js"; +import * as ep___i_exportFollowing from "./endpoints/i/export-following.js"; +import * as ep___i_exportMute from "./endpoints/i/export-mute.js"; +import * as ep___i_exportNotes from "./endpoints/i/export-notes.js"; +import * as ep___i_exportUserLists from "./endpoints/i/export-user-lists.js"; +import * as ep___i_favorites from "./endpoints/i/favorites.js"; +import * as ep___i_gallery_likes from "./endpoints/i/gallery/likes.js"; +import * as ep___i_gallery_posts from "./endpoints/i/gallery/posts.js"; +import * as ep___i_getWordMutedNotesCount from "./endpoints/i/get-word-muted-notes-count.js"; +import * as ep___i_importBlocking from "./endpoints/i/import-blocking.js"; +import * as ep___i_importFollowing from "./endpoints/i/import-following.js"; +import * as ep___i_importMuting from "./endpoints/i/import-muting.js"; +import * as ep___i_importUserLists from "./endpoints/i/import-user-lists.js"; +import * as ep___i_notifications from "./endpoints/i/notifications.js"; +import * as ep___i_pageLikes from "./endpoints/i/page-likes.js"; +import * as ep___i_pages from "./endpoints/i/pages.js"; +import * as ep___i_pin from "./endpoints/i/pin.js"; +import * as ep___i_readAllMessagingMessages from "./endpoints/i/read-all-messaging-messages.js"; +import * as ep___i_readAllUnreadNotes from "./endpoints/i/read-all-unread-notes.js"; +import * as ep___i_readAnnouncement from "./endpoints/i/read-announcement.js"; +import * as ep___i_regenerateToken from "./endpoints/i/regenerate-token.js"; +import * as ep___i_registry_getAll from "./endpoints/i/registry/get-all.js"; +import * as ep___i_registry_getDetail from "./endpoints/i/registry/get-detail.js"; +import * as ep___i_registry_get from "./endpoints/i/registry/get.js"; +import * as ep___i_registry_keysWithType from "./endpoints/i/registry/keys-with-type.js"; +import * as ep___i_registry_keys from "./endpoints/i/registry/keys.js"; +import * as ep___i_registry_remove from "./endpoints/i/registry/remove.js"; +import * as ep___i_registry_scopes from "./endpoints/i/registry/scopes.js"; +import * as ep___i_registry_set from "./endpoints/i/registry/set.js"; +import * as ep___i_revokeToken from "./endpoints/i/revoke-token.js"; +import * as ep___i_signinHistory from "./endpoints/i/signin-history.js"; +import * as ep___i_unpin from "./endpoints/i/unpin.js"; +import * as ep___i_updateEmail from "./endpoints/i/update-email.js"; +import * as ep___i_update from "./endpoints/i/update.js"; +import * as ep___i_userGroupInvites from "./endpoints/i/user-group-invites.js"; +import * as ep___i_webhooks_create from "./endpoints/i/webhooks/create.js"; +import * as ep___i_webhooks_show from "./endpoints/i/webhooks/show.js"; +import * as ep___i_webhooks_list from "./endpoints/i/webhooks/list.js"; +import * as ep___i_webhooks_update from "./endpoints/i/webhooks/update.js"; +import * as ep___i_webhooks_delete from "./endpoints/i/webhooks/delete.js"; +import * as ep___messaging_history from "./endpoints/messaging/history.js"; +import * as ep___messaging_messages from "./endpoints/messaging/messages.js"; +import * as ep___messaging_messages_create from "./endpoints/messaging/messages/create.js"; +import * as ep___messaging_messages_delete from "./endpoints/messaging/messages/delete.js"; +import * as ep___messaging_messages_read from "./endpoints/messaging/messages/read.js"; +import * as ep___meta from "./endpoints/meta.js"; +import * as ep___miauth_genToken from "./endpoints/miauth/gen-token.js"; +import * as ep___mute_create from "./endpoints/mute/create.js"; +import * as ep___mute_delete from "./endpoints/mute/delete.js"; +import * as ep___mute_list from "./endpoints/mute/list.js"; +import * as ep___my_apps from "./endpoints/my/apps.js"; +import * as ep___notes from "./endpoints/notes.js"; +import * as ep___notes_children from "./endpoints/notes/children.js"; +import * as ep___notes_clips from "./endpoints/notes/clips.js"; +import * as ep___notes_conversation from "./endpoints/notes/conversation.js"; +import * as ep___notes_create from "./endpoints/notes/create.js"; +import * as ep___notes_delete from "./endpoints/notes/delete.js"; +import * as ep___notes_favorites_create from "./endpoints/notes/favorites/create.js"; +import * as ep___notes_favorites_delete from "./endpoints/notes/favorites/delete.js"; +import * as ep___notes_featured from "./endpoints/notes/featured.js"; +import * as ep___notes_globalTimeline from "./endpoints/notes/global-timeline.js"; +import * as ep___notes_hybridTimeline from "./endpoints/notes/hybrid-timeline.js"; +import * as ep___notes_localTimeline from "./endpoints/notes/local-timeline.js"; +import * as ep___notes_recommendedTimeline from "./endpoints/notes/recommended-timeline.js"; +import * as ep___notes_mentions from "./endpoints/notes/mentions.js"; +import * as ep___notes_polls_recommendation from "./endpoints/notes/polls/recommendation.js"; +import * as ep___notes_polls_vote from "./endpoints/notes/polls/vote.js"; +import * as ep___notes_reactions from "./endpoints/notes/reactions.js"; +import * as ep___notes_reactions_create from "./endpoints/notes/reactions/create.js"; +import * as ep___notes_reactions_delete from "./endpoints/notes/reactions/delete.js"; +import * as ep___notes_renotes from "./endpoints/notes/renotes.js"; +import * as ep___notes_replies from "./endpoints/notes/replies.js"; +import * as ep___notes_searchByTag from "./endpoints/notes/search-by-tag.js"; +import * as ep___notes_search from "./endpoints/notes/search.js"; +import * as ep___notes_show from "./endpoints/notes/show.js"; +import * as ep___notes_state from "./endpoints/notes/state.js"; +import * as ep___notes_threadMuting_create from "./endpoints/notes/thread-muting/create.js"; +import * as ep___notes_threadMuting_delete from "./endpoints/notes/thread-muting/delete.js"; +import * as ep___notes_timeline from "./endpoints/notes/timeline.js"; +import * as ep___notes_translate from "./endpoints/notes/translate.js"; +import * as ep___notes_unrenote from "./endpoints/notes/unrenote.js"; +import * as ep___notes_userListTimeline from "./endpoints/notes/user-list-timeline.js"; +import * as ep___notes_watching_create from "./endpoints/notes/watching/create.js"; +import * as ep___notes_watching_delete from "./endpoints/notes/watching/delete.js"; +import * as ep___notifications_create from "./endpoints/notifications/create.js"; +import * as ep___notifications_markAllAsRead from "./endpoints/notifications/mark-all-as-read.js"; +import * as ep___notifications_read from "./endpoints/notifications/read.js"; +import * as ep___pagePush from "./endpoints/page-push.js"; +import * as ep___pages_create from "./endpoints/pages/create.js"; +import * as ep___pages_delete from "./endpoints/pages/delete.js"; +import * as ep___pages_featured from "./endpoints/pages/featured.js"; +import * as ep___pages_like from "./endpoints/pages/like.js"; +import * as ep___pages_show from "./endpoints/pages/show.js"; +import * as ep___pages_unlike from "./endpoints/pages/unlike.js"; +import * as ep___pages_update from "./endpoints/pages/update.js"; +import * as ep___ping from "./endpoints/ping.js"; +import * as ep___recommendedInstances from "./endpoints/recommended-instances.js"; +import * as ep___pinnedUsers from "./endpoints/pinned-users.js"; +import * as ep___customMOTD from "./endpoints/custom-motd.js"; +import * as ep___customSplashIcons from "./endpoints/custom-splash-icons.js"; +import * as ep___latestVersion from "./endpoints/latest-version.js"; +import * as ep___patrons from "./endpoints/patrons.js"; +import * as ep___release from "./endpoints/release.js"; +import * as ep___promo_read from "./endpoints/promo/read.js"; +import * as ep___requestResetPassword from "./endpoints/request-reset-password.js"; +import * as ep___resetDb from "./endpoints/reset-db.js"; +import * as ep___resetPassword from "./endpoints/reset-password.js"; +import * as ep___serverInfo from "./endpoints/server-info.js"; +import * as ep___stats from "./endpoints/stats.js"; +import * as ep___sw_register from "./endpoints/sw/register.js"; +import * as ep___sw_unregister from "./endpoints/sw/unregister.js"; +import * as ep___test from "./endpoints/test.js"; +import * as ep___username_available from "./endpoints/username/available.js"; +import * as ep___users from "./endpoints/users.js"; +import * as ep___users_clips from "./endpoints/users/clips.js"; +import * as ep___users_followers from "./endpoints/users/followers.js"; +import * as ep___users_following from "./endpoints/users/following.js"; +import * as ep___users_gallery_posts from "./endpoints/users/gallery/posts.js"; +import * as ep___users_getFrequentlyRepliedUsers from "./endpoints/users/get-frequently-replied-users.js"; +import * as ep___users_groups_create from "./endpoints/users/groups/create.js"; +import * as ep___users_groups_delete from "./endpoints/users/groups/delete.js"; +import * as ep___users_groups_invitations_accept from "./endpoints/users/groups/invitations/accept.js"; +import * as ep___users_groups_invitations_reject from "./endpoints/users/groups/invitations/reject.js"; +import * as ep___users_groups_invite from "./endpoints/users/groups/invite.js"; +import * as ep___users_groups_joined from "./endpoints/users/groups/joined.js"; +import * as ep___users_groups_leave from "./endpoints/users/groups/leave.js"; +import * as ep___users_groups_owned from "./endpoints/users/groups/owned.js"; +import * as ep___users_groups_pull from "./endpoints/users/groups/pull.js"; +import * as ep___users_groups_show from "./endpoints/users/groups/show.js"; +import * as ep___users_groups_transfer from "./endpoints/users/groups/transfer.js"; +import * as ep___users_groups_update from "./endpoints/users/groups/update.js"; +import * as ep___users_lists_create from "./endpoints/users/lists/create.js"; +import * as ep___users_lists_delete from "./endpoints/users/lists/delete.js"; +import * as ep___users_lists_delete_all from "./endpoints/users/lists/delete-all.js"; +import * as ep___users_lists_list from "./endpoints/users/lists/list.js"; +import * as ep___users_lists_pull from "./endpoints/users/lists/pull.js"; +import * as ep___users_lists_push from "./endpoints/users/lists/push.js"; +import * as ep___users_lists_show from "./endpoints/users/lists/show.js"; +import * as ep___users_lists_update from "./endpoints/users/lists/update.js"; +import * as ep___users_notes from "./endpoints/users/notes.js"; +import * as ep___users_pages from "./endpoints/users/pages.js"; +import * as ep___users_reactions from "./endpoints/users/reactions.js"; +import * as ep___users_recommendation from "./endpoints/users/recommendation.js"; +import * as ep___users_relation from "./endpoints/users/relation.js"; +import * as ep___users_reportAbuse from "./endpoints/users/report-abuse.js"; +import * as ep___users_searchByUsernameAndHost from "./endpoints/users/search-by-username-and-host.js"; +import * as ep___users_search from "./endpoints/users/search.js"; +import * as ep___users_show from "./endpoints/users/show.js"; +import * as ep___users_stats from "./endpoints/users/stats.js"; +import * as ep___fetchRss from "./endpoints/fetch-rss.js"; +import * as ep___admin_driveCapOverride from "./endpoints/admin/drive-capacity-override.js"; //Calckey Move -import * as ep___i_move from './endpoints/i/move.js'; -import * as ep___i_known_as from './endpoints/i/known-as.js'; +import * as ep___i_move from "./endpoints/i/move.js"; +import * as ep___i_known_as from "./endpoints/i/known-as.js"; const eps = [ - ['admin/meta', ep___admin_meta], - ['admin/abuse-user-reports', ep___admin_abuseUserReports], - ['admin/accounts/create', ep___admin_accounts_create], - ['admin/accounts/delete', ep___admin_accounts_delete], - ['admin/accounts/hosted', ep___admin_accounts_hosted], - ['admin/ad/create', ep___admin_ad_create], - ['admin/ad/delete', ep___admin_ad_delete], - ['admin/ad/list', ep___admin_ad_list], - ['admin/ad/update', ep___admin_ad_update], - ['admin/announcements/create', ep___admin_announcements_create], - ['admin/announcements/delete', ep___admin_announcements_delete], - ['admin/announcements/list', ep___admin_announcements_list], - ['admin/announcements/update', ep___admin_announcements_update], - ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], - ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], - ['admin/drive/cleanup', ep___admin_drive_cleanup], - ['admin/drive/files', ep___admin_drive_files], - ['admin/drive/show-file', ep___admin_drive_showFile], - ['admin/emoji/add-aliases-bulk', ep___admin_emoji_addAliasesBulk], - ['admin/emoji/add', ep___admin_emoji_add], - ['admin/emoji/copy', ep___admin_emoji_copy], - ['admin/emoji/delete-bulk', ep___admin_emoji_deleteBulk], - ['admin/emoji/delete', ep___admin_emoji_delete], - ['admin/emoji/import-zip', ep___admin_emoji_importZip], - ['admin/emoji/list-remote', ep___admin_emoji_listRemote], - ['admin/emoji/list', ep___admin_emoji_list], - ['admin/emoji/remove-aliases-bulk', ep___admin_emoji_removeAliasesBulk], - ['admin/emoji/set-aliases-bulk', ep___admin_emoji_setAliasesBulk], - ['admin/emoji/set-category-bulk', ep___admin_emoji_setCategoryBulk], - ['admin/emoji/update', ep___admin_emoji_update], - ['admin/federation/delete-all-files', ep___admin_federation_deleteAllFiles], - ['admin/federation/refresh-remote-instance-metadata', ep___admin_federation_refreshRemoteInstanceMetadata], - ['admin/federation/remove-all-following', ep___admin_federation_removeAllFollowing], - ['admin/federation/update-instance', ep___admin_federation_updateInstance], - ['admin/get-index-stats', ep___admin_getIndexStats], - ['admin/get-table-stats', ep___admin_getTableStats], - ['admin/get-user-ips', ep___admin_getUserIps], - ['admin/invite', ep___admin_invite], - ['admin/moderators/add', ep___admin_moderators_add], - ['admin/moderators/remove', ep___admin_moderators_remove], - ['admin/promo/create', ep___admin_promo_create], - ['admin/queue/clear', ep___admin_queue_clear], - ['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed], - ['admin/queue/inbox-delayed', ep___admin_queue_inboxDelayed], - ['admin/queue/stats', ep___admin_queue_stats], - ['admin/relays/add', ep___admin_relays_add], - ['admin/relays/list', ep___admin_relays_list], - ['admin/relays/remove', ep___admin_relays_remove], - ['admin/reset-password', ep___admin_resetPassword], - ['admin/resolve-abuse-user-report', ep___admin_resolveAbuseUserReport], - ['admin/send-email', ep___admin_sendEmail], - ['admin/server-info', ep___admin_serverInfo], - ['admin/show-moderation-logs', ep___admin_showModerationLogs], - ['admin/show-user', ep___admin_showUser], - ['admin/show-users', ep___admin_showUsers], - ['admin/silence-user', ep___admin_silenceUser], - ['admin/suspend-user', ep___admin_suspendUser], - ['admin/unsilence-user', ep___admin_unsilenceUser], - ['admin/unsuspend-user', ep___admin_unsuspendUser], - ['admin/update-meta', ep___admin_updateMeta], - ['admin/vacuum', ep___admin_vacuum], - ['admin/delete-account', ep___admin_deleteAccount], - ['admin/update-user-note', ep___admin_updateUserNote], - ['announcements', ep___announcements], - ['antennas/create', ep___antennas_create], - ['antennas/delete', ep___antennas_delete], - ['antennas/list', ep___antennas_list], - ['antennas/notes', ep___antennas_notes], - ['antennas/show', ep___antennas_show], - ['antennas/update', ep___antennas_update], - ['ap/get', ep___ap_get], - ['ap/show', ep___ap_show], - ['app/create', ep___app_create], - ['app/show', ep___app_show], - ['auth/accept', ep___auth_accept], - ['auth/session/generate', ep___auth_session_generate], - ['auth/session/show', ep___auth_session_show], - ['auth/session/userkey', ep___auth_session_userkey], - ['blocking/create', ep___blocking_create], - ['blocking/delete', ep___blocking_delete], - ['blocking/list', ep___blocking_list], - ['channels/create', ep___channels_create], - ['channels/featured', ep___channels_featured], - ['channels/follow', ep___channels_follow], - ['channels/followed', ep___channels_followed], - ['channels/owned', ep___channels_owned], - ['channels/show', ep___channels_show], - ['channels/timeline', ep___channels_timeline], - ['channels/unfollow', ep___channels_unfollow], - ['channels/update', ep___channels_update], - ['charts/active-users', ep___charts_activeUsers], - ['charts/ap-request', ep___charts_apRequest], - ['charts/drive', ep___charts_drive], - ['charts/federation', ep___charts_federation], - ['charts/hashtag', ep___charts_hashtag], - ['charts/instance', ep___charts_instance], - ['charts/notes', ep___charts_notes], - ['charts/user/drive', ep___charts_user_drive], - ['charts/user/following', ep___charts_user_following], - ['charts/user/notes', ep___charts_user_notes], - ['charts/user/reactions', ep___charts_user_reactions], - ['charts/users', ep___charts_users], - ['clips/add-note', ep___clips_addNote], - ['clips/remove-note', ep___clips_removeNote], - ['clips/create', ep___clips_create], - ['clips/delete', ep___clips_delete], - ['clips/list', ep___clips_list], - ['clips/notes', ep___clips_notes], - ['clips/show', ep___clips_show], - ['clips/update', ep___clips_update], - ['drive', ep___drive], - ['drive/files', ep___drive_files], - ['drive/files/attached-notes', ep___drive_files_attachedNotes], - ['drive/files/caption-image', ep___drive_files_captionImage], - ['drive/files/check-existence', ep___drive_files_checkExistence], - ['drive/files/create', ep___drive_files_create], - ['drive/files/delete', ep___drive_files_delete], - ['drive/files/find-by-hash', ep___drive_files_findByHash], - ['drive/files/find', ep___drive_files_find], - ['drive/files/show', ep___drive_files_show], - ['drive/files/update', ep___drive_files_update], - ['drive/files/upload-from-url', ep___drive_files_uploadFromUrl], - ['drive/folders', ep___drive_folders], - ['drive/folders/create', ep___drive_folders_create], - ['drive/folders/delete', ep___drive_folders_delete], - ['drive/folders/find', ep___drive_folders_find], - ['drive/folders/show', ep___drive_folders_show], - ['drive/folders/update', ep___drive_folders_update], - ['drive/stream', ep___drive_stream], - ['email-address/available', ep___emailAddress_available], - ['endpoint', ep___endpoint], - ['endpoints', ep___endpoints], - ['export-custom-emojis', ep___exportCustomEmojis], - ['federation/followers', ep___federation_followers], - ['federation/following', ep___federation_following], - ['federation/instances', ep___federation_instances], - ['federation/show-instance', ep___federation_showInstance], - ['federation/update-remote-user', ep___federation_updateRemoteUser], - ['federation/users', ep___federation_users], - ['federation/stats', ep___federation_stats], - ['following/create', ep___following_create], - ['following/delete', ep___following_delete], - ['following/invalidate', ep___following_invalidate], - ['following/requests/accept', ep___following_requests_accept], - ['following/requests/cancel', ep___following_requests_cancel], - ['following/requests/list', ep___following_requests_list], - ['following/requests/reject', ep___following_requests_reject], - ['gallery/featured', ep___gallery_featured], - ['gallery/popular', ep___gallery_popular], - ['gallery/posts', ep___gallery_posts], - ['gallery/posts/create', ep___gallery_posts_create], - ['gallery/posts/delete', ep___gallery_posts_delete], - ['gallery/posts/like', ep___gallery_posts_like], - ['gallery/posts/show', ep___gallery_posts_show], - ['gallery/posts/unlike', ep___gallery_posts_unlike], - ['gallery/posts/update', ep___gallery_posts_update], - ['get-online-users-count', ep___getOnlineUsersCount], - ['hashtags/list', ep___hashtags_list], - ['hashtags/search', ep___hashtags_search], - ['hashtags/show', ep___hashtags_show], - ['hashtags/trend', ep___hashtags_trend], - ['hashtags/users', ep___hashtags_users], - ['i', ep___i], - ['i/known-as', ep___i_known_as], - ['i/move', ep___i_move], - ['i/2fa/done', ep___i_2fa_done], - ['i/2fa/key-done', ep___i_2fa_keyDone], - ['i/2fa/password-less', ep___i_2fa_passwordLess], - ['i/2fa/register-key', ep___i_2fa_registerKey], - ['i/2fa/register', ep___i_2fa_register], - ['i/2fa/remove-key', ep___i_2fa_removeKey], - ['i/2fa/unregister', ep___i_2fa_unregister], - ['i/apps', ep___i_apps], - ['i/authorized-apps', ep___i_authorizedApps], - ['i/change-password', ep___i_changePassword], - ['i/delete-account', ep___i_deleteAccount], - ['i/export-blocking', ep___i_exportBlocking], - ['i/export-following', ep___i_exportFollowing], - ['i/export-mute', ep___i_exportMute], - ['i/export-notes', ep___i_exportNotes], - ['i/export-user-lists', ep___i_exportUserLists], - ['i/favorites', ep___i_favorites], - ['i/gallery/likes', ep___i_gallery_likes], - ['i/gallery/posts', ep___i_gallery_posts], - ['i/get-word-muted-notes-count', ep___i_getWordMutedNotesCount], - ['i/import-blocking', ep___i_importBlocking], - ['i/import-following', ep___i_importFollowing], - ['i/import-muting', ep___i_importMuting], - ['i/import-user-lists', ep___i_importUserLists], - ['i/notifications', ep___i_notifications], - ['i/page-likes', ep___i_pageLikes], - ['i/pages', ep___i_pages], - ['i/pin', ep___i_pin], - ['i/read-all-messaging-messages', ep___i_readAllMessagingMessages], - ['i/read-all-unread-notes', ep___i_readAllUnreadNotes], - ['i/read-announcement', ep___i_readAnnouncement], - ['i/regenerate-token', ep___i_regenerateToken], - ['i/registry/get-all', ep___i_registry_getAll], - ['i/registry/get-detail', ep___i_registry_getDetail], - ['i/registry/get', ep___i_registry_get], - ['i/registry/keys-with-type', ep___i_registry_keysWithType], - ['i/registry/keys', ep___i_registry_keys], - ['i/registry/remove', ep___i_registry_remove], - ['i/registry/scopes', ep___i_registry_scopes], - ['i/registry/set', ep___i_registry_set], - ['i/revoke-token', ep___i_revokeToken], - ['i/signin-history', ep___i_signinHistory], - ['i/unpin', ep___i_unpin], - ['i/update-email', ep___i_updateEmail], - ['i/update', ep___i_update], - ['i/user-group-invites', ep___i_userGroupInvites], - ['i/webhooks/create', ep___i_webhooks_create], - ['i/webhooks/list', ep___i_webhooks_list], - ['i/webhooks/show', ep___i_webhooks_show], - ['i/webhooks/update', ep___i_webhooks_update], - ['i/webhooks/delete', ep___i_webhooks_delete], - ['messaging/history', ep___messaging_history], - ['messaging/messages', ep___messaging_messages], - ['messaging/messages/create', ep___messaging_messages_create], - ['messaging/messages/delete', ep___messaging_messages_delete], - ['messaging/messages/read', ep___messaging_messages_read], - ['meta', ep___meta], - ['miauth/gen-token', ep___miauth_genToken], - ['mute/create', ep___mute_create], - ['mute/delete', ep___mute_delete], - ['mute/list', ep___mute_list], - ['my/apps', ep___my_apps], - ['notes', ep___notes], - ['notes/children', ep___notes_children], - ['notes/clips', ep___notes_clips], - ['notes/conversation', ep___notes_conversation], - ['notes/create', ep___notes_create], - ['notes/delete', ep___notes_delete], - ['notes/favorites/create', ep___notes_favorites_create], - ['notes/favorites/delete', ep___notes_favorites_delete], - ['notes/featured', ep___notes_featured], - ['notes/global-timeline', ep___notes_globalTimeline], - ['notes/hybrid-timeline', ep___notes_hybridTimeline], - ['notes/local-timeline', ep___notes_localTimeline], - ['notes/recommended-timeline', ep___notes_recommendedTimeline], - ['notes/mentions', ep___notes_mentions], - ['notes/polls/recommendation', ep___notes_polls_recommendation], - ['notes/polls/vote', ep___notes_polls_vote], - ['notes/reactions', ep___notes_reactions], - ['notes/reactions/create', ep___notes_reactions_create], - ['notes/reactions/delete', ep___notes_reactions_delete], - ['notes/renotes', ep___notes_renotes], - ['notes/replies', ep___notes_replies], - ['notes/search-by-tag', ep___notes_searchByTag], - ['notes/search', ep___notes_search], - ['notes/show', ep___notes_show], - ['notes/state', ep___notes_state], - ['notes/thread-muting/create', ep___notes_threadMuting_create], - ['notes/thread-muting/delete', ep___notes_threadMuting_delete], - ['notes/timeline', ep___notes_timeline], - ['notes/translate', ep___notes_translate], - ['notes/unrenote', ep___notes_unrenote], - ['notes/user-list-timeline', ep___notes_userListTimeline], - ['notes/watching/create', ep___notes_watching_create], - ['notes/watching/delete', ep___notes_watching_delete], - ['notifications/create', ep___notifications_create], - ['notifications/mark-all-as-read', ep___notifications_markAllAsRead], - ['notifications/read', ep___notifications_read], - ['page-push', ep___pagePush], - ['pages/create', ep___pages_create], - ['pages/delete', ep___pages_delete], - ['pages/featured', ep___pages_featured], - ['pages/like', ep___pages_like], - ['pages/show', ep___pages_show], - ['pages/unlike', ep___pages_unlike], - ['pages/update', ep___pages_update], - ['ping', ep___ping], - ['pinned-users', ep___pinnedUsers], - ['recommended-instances', ep___recommendedInstances], - ['custom-motd', ep___customMOTD], - ['custom-splash-icons', ep___customSplashIcons], - ['latest-version', ep___latestVersion], - ['patrons', ep___patrons], - ['promo/read', ep___promo_read], - ['request-reset-password', ep___requestResetPassword], - ['reset-db', ep___resetDb], - ['reset-password', ep___resetPassword], - ['server-info', ep___serverInfo], - ['stats', ep___stats], - ['sw/register', ep___sw_register], - ['sw/unregister', ep___sw_unregister], - ['test', ep___test], - ['username/available', ep___username_available], - ['users', ep___users], - ['users/clips', ep___users_clips], - ['users/followers', ep___users_followers], - ['users/following', ep___users_following], - ['users/gallery/posts', ep___users_gallery_posts], - ['users/get-frequently-replied-users', ep___users_getFrequentlyRepliedUsers], - ['users/groups/create', ep___users_groups_create], - ['users/groups/delete', ep___users_groups_delete], - ['users/groups/invitations/accept', ep___users_groups_invitations_accept], - ['users/groups/invitations/reject', ep___users_groups_invitations_reject], - ['users/groups/invite', ep___users_groups_invite], - ['users/groups/joined', ep___users_groups_joined], - ['users/groups/leave', ep___users_groups_leave], - ['users/groups/owned', ep___users_groups_owned], - ['users/groups/pull', ep___users_groups_pull], - ['users/groups/show', ep___users_groups_show], - ['users/groups/transfer', ep___users_groups_transfer], - ['users/groups/update', ep___users_groups_update], - ['users/lists/create', ep___users_lists_create], - ['users/lists/delete', ep___users_lists_delete], - ['users/lists/delete-all', ep___users_lists_delete_all], - ['users/lists/list', ep___users_lists_list], - ['users/lists/pull', ep___users_lists_pull], - ['users/lists/push', ep___users_lists_push], - ['users/lists/show', ep___users_lists_show], - ['users/lists/update', ep___users_lists_update], - ['users/notes', ep___users_notes], - ['users/pages', ep___users_pages], - ['users/reactions', ep___users_reactions], - ['users/recommendation', ep___users_recommendation], - ['users/relation', ep___users_relation], - ['users/report-abuse', ep___users_reportAbuse], - ['users/search-by-username-and-host', ep___users_searchByUsernameAndHost], - ['users/search', ep___users_search], - ['users/show', ep___users_show], - ['users/stats', ep___users_stats], - ['admin/drive-capacity-override', ep___admin_driveCapOverride], - ['fetch-rss', ep___fetchRss], + ["admin/meta", ep___admin_meta], + ["admin/abuse-user-reports", ep___admin_abuseUserReports], + ["admin/accounts/create", ep___admin_accounts_create], + ["admin/accounts/delete", ep___admin_accounts_delete], + ["admin/accounts/hosted", ep___admin_accounts_hosted], + ["admin/ad/create", ep___admin_ad_create], + ["admin/ad/delete", ep___admin_ad_delete], + ["admin/ad/list", ep___admin_ad_list], + ["admin/ad/update", ep___admin_ad_update], + ["admin/announcements/create", ep___admin_announcements_create], + ["admin/announcements/delete", ep___admin_announcements_delete], + ["admin/announcements/list", ep___admin_announcements_list], + ["admin/announcements/update", ep___admin_announcements_update], + ["admin/delete-all-files-of-a-user", ep___admin_deleteAllFilesOfAUser], + ["admin/drive/clean-remote-files", ep___admin_drive_cleanRemoteFiles], + ["admin/drive/cleanup", ep___admin_drive_cleanup], + ["admin/drive/files", ep___admin_drive_files], + ["admin/drive/show-file", ep___admin_drive_showFile], + ["admin/emoji/add-aliases-bulk", ep___admin_emoji_addAliasesBulk], + ["admin/emoji/add", ep___admin_emoji_add], + ["admin/emoji/copy", ep___admin_emoji_copy], + ["admin/emoji/delete-bulk", ep___admin_emoji_deleteBulk], + ["admin/emoji/delete", ep___admin_emoji_delete], + ["admin/emoji/import-zip", ep___admin_emoji_importZip], + ["admin/emoji/list-remote", ep___admin_emoji_listRemote], + ["admin/emoji/list", ep___admin_emoji_list], + ["admin/emoji/remove-aliases-bulk", ep___admin_emoji_removeAliasesBulk], + ["admin/emoji/set-aliases-bulk", ep___admin_emoji_setAliasesBulk], + ["admin/emoji/set-category-bulk", ep___admin_emoji_setCategoryBulk], + ["admin/emoji/update", ep___admin_emoji_update], + ["admin/federation/delete-all-files", ep___admin_federation_deleteAllFiles], + [ + "admin/federation/refresh-remote-instance-metadata", + ep___admin_federation_refreshRemoteInstanceMetadata, + ], + [ + "admin/federation/remove-all-following", + ep___admin_federation_removeAllFollowing, + ], + ["admin/federation/update-instance", ep___admin_federation_updateInstance], + ["admin/get-index-stats", ep___admin_getIndexStats], + ["admin/get-table-stats", ep___admin_getTableStats], + ["admin/get-user-ips", ep___admin_getUserIps], + ["admin/invite", ep___admin_invite], + ["admin/moderators/add", ep___admin_moderators_add], + ["admin/moderators/remove", ep___admin_moderators_remove], + ["admin/promo/create", ep___admin_promo_create], + ["admin/queue/clear", ep___admin_queue_clear], + ["admin/queue/deliver-delayed", ep___admin_queue_deliverDelayed], + ["admin/queue/inbox-delayed", ep___admin_queue_inboxDelayed], + ["admin/queue/stats", ep___admin_queue_stats], + ["admin/relays/add", ep___admin_relays_add], + ["admin/relays/list", ep___admin_relays_list], + ["admin/relays/remove", ep___admin_relays_remove], + ["admin/reset-password", ep___admin_resetPassword], + ["admin/resolve-abuse-user-report", ep___admin_resolveAbuseUserReport], + ["admin/send-email", ep___admin_sendEmail], + ["admin/server-info", ep___admin_serverInfo], + ["admin/show-moderation-logs", ep___admin_showModerationLogs], + ["admin/show-user", ep___admin_showUser], + ["admin/show-users", ep___admin_showUsers], + ["admin/silence-user", ep___admin_silenceUser], + ["admin/suspend-user", ep___admin_suspendUser], + ["admin/unsilence-user", ep___admin_unsilenceUser], + ["admin/unsuspend-user", ep___admin_unsuspendUser], + ["admin/update-meta", ep___admin_updateMeta], + ["admin/vacuum", ep___admin_vacuum], + ["admin/delete-account", ep___admin_deleteAccount], + ["admin/update-user-note", ep___admin_updateUserNote], + ["announcements", ep___announcements], + ["antennas/create", ep___antennas_create], + ["antennas/delete", ep___antennas_delete], + ["antennas/list", ep___antennas_list], + ["antennas/mark-read", ep___antennas_markRead], + ["antennas/notes", ep___antennas_notes], + ["antennas/show", ep___antennas_show], + ["antennas/update", ep___antennas_update], + ["ap/get", ep___ap_get], + ["ap/show", ep___ap_show], + ["app/create", ep___app_create], + ["app/show", ep___app_show], + ["auth/accept", ep___auth_accept], + ["auth/session/generate", ep___auth_session_generate], + ["auth/session/show", ep___auth_session_show], + ["auth/session/userkey", ep___auth_session_userkey], + ["blocking/create", ep___blocking_create], + ["blocking/delete", ep___blocking_delete], + ["blocking/list", ep___blocking_list], + ["channels/create", ep___channels_create], + ["channels/featured", ep___channels_featured], + ["channels/follow", ep___channels_follow], + ["channels/followed", ep___channels_followed], + ["channels/owned", ep___channels_owned], + ["channels/show", ep___channels_show], + ["channels/timeline", ep___channels_timeline], + ["channels/unfollow", ep___channels_unfollow], + ["channels/update", ep___channels_update], + ["charts/active-users", ep___charts_activeUsers], + ["charts/ap-request", ep___charts_apRequest], + ["charts/drive", ep___charts_drive], + ["charts/federation", ep___charts_federation], + ["charts/hashtag", ep___charts_hashtag], + ["charts/instance", ep___charts_instance], + ["charts/notes", ep___charts_notes], + ["charts/user/drive", ep___charts_user_drive], + ["charts/user/following", ep___charts_user_following], + ["charts/user/notes", ep___charts_user_notes], + ["charts/user/reactions", ep___charts_user_reactions], + ["charts/users", ep___charts_users], + ["clips/add-note", ep___clips_addNote], + ["clips/remove-note", ep___clips_removeNote], + ["clips/create", ep___clips_create], + ["clips/delete", ep___clips_delete], + ["clips/list", ep___clips_list], + ["clips/notes", ep___clips_notes], + ["clips/show", ep___clips_show], + ["clips/update", ep___clips_update], + ["drive", ep___drive], + ["drive/files", ep___drive_files], + ["drive/files/attached-notes", ep___drive_files_attachedNotes], + ["drive/files/caption-image", ep___drive_files_captionImage], + ["drive/files/check-existence", ep___drive_files_checkExistence], + ["drive/files/create", ep___drive_files_create], + ["drive/files/delete", ep___drive_files_delete], + ["drive/files/find-by-hash", ep___drive_files_findByHash], + ["drive/files/find", ep___drive_files_find], + ["drive/files/show", ep___drive_files_show], + ["drive/files/update", ep___drive_files_update], + ["drive/files/upload-from-url", ep___drive_files_uploadFromUrl], + ["drive/folders", ep___drive_folders], + ["drive/folders/create", ep___drive_folders_create], + ["drive/folders/delete", ep___drive_folders_delete], + ["drive/folders/find", ep___drive_folders_find], + ["drive/folders/show", ep___drive_folders_show], + ["drive/folders/update", ep___drive_folders_update], + ["drive/stream", ep___drive_stream], + ["email-address/available", ep___emailAddress_available], + ["endpoint", ep___endpoint], + ["endpoints", ep___endpoints], + ["export-custom-emojis", ep___exportCustomEmojis], + ["federation/followers", ep___federation_followers], + ["federation/following", ep___federation_following], + ["federation/instances", ep___federation_instances], + ["federation/show-instance", ep___federation_showInstance], + ["federation/update-remote-user", ep___federation_updateRemoteUser], + ["federation/users", ep___federation_users], + ["federation/stats", ep___federation_stats], + ["following/create", ep___following_create], + ["following/delete", ep___following_delete], + ["following/invalidate", ep___following_invalidate], + ["following/requests/accept", ep___following_requests_accept], + ["following/requests/cancel", ep___following_requests_cancel], + ["following/requests/list", ep___following_requests_list], + ["following/requests/reject", ep___following_requests_reject], + ["gallery/featured", ep___gallery_featured], + ["gallery/popular", ep___gallery_popular], + ["gallery/posts", ep___gallery_posts], + ["gallery/posts/create", ep___gallery_posts_create], + ["gallery/posts/delete", ep___gallery_posts_delete], + ["gallery/posts/like", ep___gallery_posts_like], + ["gallery/posts/show", ep___gallery_posts_show], + ["gallery/posts/unlike", ep___gallery_posts_unlike], + ["gallery/posts/update", ep___gallery_posts_update], + ["get-online-users-count", ep___getOnlineUsersCount], + ["hashtags/list", ep___hashtags_list], + ["hashtags/search", ep___hashtags_search], + ["hashtags/show", ep___hashtags_show], + ["hashtags/trend", ep___hashtags_trend], + ["hashtags/users", ep___hashtags_users], + ["i", ep___i], + ["i/known-as", ep___i_known_as], + ["i/move", ep___i_move], + ["i/2fa/done", ep___i_2fa_done], + ["i/2fa/key-done", ep___i_2fa_keyDone], + ["i/2fa/password-less", ep___i_2fa_passwordLess], + ["i/2fa/register-key", ep___i_2fa_registerKey], + ["i/2fa/register", ep___i_2fa_register], + ["i/2fa/remove-key", ep___i_2fa_removeKey], + ["i/2fa/unregister", ep___i_2fa_unregister], + ["i/apps", ep___i_apps], + ["i/authorized-apps", ep___i_authorizedApps], + ["i/change-password", ep___i_changePassword], + ["i/delete-account", ep___i_deleteAccount], + ["i/export-blocking", ep___i_exportBlocking], + ["i/export-following", ep___i_exportFollowing], + ["i/export-mute", ep___i_exportMute], + ["i/export-notes", ep___i_exportNotes], + ["i/export-user-lists", ep___i_exportUserLists], + ["i/favorites", ep___i_favorites], + ["i/gallery/likes", ep___i_gallery_likes], + ["i/gallery/posts", ep___i_gallery_posts], + ["i/get-word-muted-notes-count", ep___i_getWordMutedNotesCount], + ["i/import-blocking", ep___i_importBlocking], + ["i/import-following", ep___i_importFollowing], + ["i/import-muting", ep___i_importMuting], + ["i/import-user-lists", ep___i_importUserLists], + ["i/notifications", ep___i_notifications], + ["i/page-likes", ep___i_pageLikes], + ["i/pages", ep___i_pages], + ["i/pin", ep___i_pin], + ["i/read-all-messaging-messages", ep___i_readAllMessagingMessages], + ["i/read-all-unread-notes", ep___i_readAllUnreadNotes], + ["i/read-announcement", ep___i_readAnnouncement], + ["i/regenerate-token", ep___i_regenerateToken], + ["i/registry/get-all", ep___i_registry_getAll], + ["i/registry/get-detail", ep___i_registry_getDetail], + ["i/registry/get", ep___i_registry_get], + ["i/registry/keys-with-type", ep___i_registry_keysWithType], + ["i/registry/keys", ep___i_registry_keys], + ["i/registry/remove", ep___i_registry_remove], + ["i/registry/scopes", ep___i_registry_scopes], + ["i/registry/set", ep___i_registry_set], + ["i/revoke-token", ep___i_revokeToken], + ["i/signin-history", ep___i_signinHistory], + ["i/unpin", ep___i_unpin], + ["i/update-email", ep___i_updateEmail], + ["i/update", ep___i_update], + ["i/user-group-invites", ep___i_userGroupInvites], + ["i/webhooks/create", ep___i_webhooks_create], + ["i/webhooks/list", ep___i_webhooks_list], + ["i/webhooks/show", ep___i_webhooks_show], + ["i/webhooks/update", ep___i_webhooks_update], + ["i/webhooks/delete", ep___i_webhooks_delete], + ["messaging/history", ep___messaging_history], + ["messaging/messages", ep___messaging_messages], + ["messaging/messages/create", ep___messaging_messages_create], + ["messaging/messages/delete", ep___messaging_messages_delete], + ["messaging/messages/read", ep___messaging_messages_read], + ["meta", ep___meta], + ["miauth/gen-token", ep___miauth_genToken], + ["mute/create", ep___mute_create], + ["mute/delete", ep___mute_delete], + ["mute/list", ep___mute_list], + ["my/apps", ep___my_apps], + ["notes", ep___notes], + ["notes/children", ep___notes_children], + ["notes/clips", ep___notes_clips], + ["notes/conversation", ep___notes_conversation], + ["notes/create", ep___notes_create], + ["notes/delete", ep___notes_delete], + ["notes/favorites/create", ep___notes_favorites_create], + ["notes/favorites/delete", ep___notes_favorites_delete], + ["notes/featured", ep___notes_featured], + ["notes/global-timeline", ep___notes_globalTimeline], + ["notes/hybrid-timeline", ep___notes_hybridTimeline], + ["notes/local-timeline", ep___notes_localTimeline], + ["notes/recommended-timeline", ep___notes_recommendedTimeline], + ["notes/mentions", ep___notes_mentions], + ["notes/polls/recommendation", ep___notes_polls_recommendation], + ["notes/polls/vote", ep___notes_polls_vote], + ["notes/reactions", ep___notes_reactions], + ["notes/reactions/create", ep___notes_reactions_create], + ["notes/reactions/delete", ep___notes_reactions_delete], + ["notes/renotes", ep___notes_renotes], + ["notes/replies", ep___notes_replies], + ["notes/search-by-tag", ep___notes_searchByTag], + ["notes/search", ep___notes_search], + ["notes/show", ep___notes_show], + ["notes/state", ep___notes_state], + ["notes/thread-muting/create", ep___notes_threadMuting_create], + ["notes/thread-muting/delete", ep___notes_threadMuting_delete], + ["notes/timeline", ep___notes_timeline], + ["notes/translate", ep___notes_translate], + ["notes/unrenote", ep___notes_unrenote], + ["notes/user-list-timeline", ep___notes_userListTimeline], + ["notes/watching/create", ep___notes_watching_create], + ["notes/watching/delete", ep___notes_watching_delete], + ["notifications/create", ep___notifications_create], + ["notifications/mark-all-as-read", ep___notifications_markAllAsRead], + ["notifications/read", ep___notifications_read], + ["page-push", ep___pagePush], + ["pages/create", ep___pages_create], + ["pages/delete", ep___pages_delete], + ["pages/featured", ep___pages_featured], + ["pages/like", ep___pages_like], + ["pages/show", ep___pages_show], + ["pages/unlike", ep___pages_unlike], + ["pages/update", ep___pages_update], + ["ping", ep___ping], + ["pinned-users", ep___pinnedUsers], + ["recommended-instances", ep___recommendedInstances], + ["custom-motd", ep___customMOTD], + ["custom-splash-icons", ep___customSplashIcons], + ["latest-version", ep___latestVersion], + ["patrons", ep___patrons], + ["release", ep___release], + ["promo/read", ep___promo_read], + ["request-reset-password", ep___requestResetPassword], + ["reset-db", ep___resetDb], + ["reset-password", ep___resetPassword], + ["server-info", ep___serverInfo], + ["stats", ep___stats], + ["sw/register", ep___sw_register], + ["sw/unregister", ep___sw_unregister], + ["test", ep___test], + ["username/available", ep___username_available], + ["users", ep___users], + ["users/clips", ep___users_clips], + ["users/followers", ep___users_followers], + ["users/following", ep___users_following], + ["users/gallery/posts", ep___users_gallery_posts], + ["users/get-frequently-replied-users", ep___users_getFrequentlyRepliedUsers], + ["users/groups/create", ep___users_groups_create], + ["users/groups/delete", ep___users_groups_delete], + ["users/groups/invitations/accept", ep___users_groups_invitations_accept], + ["users/groups/invitations/reject", ep___users_groups_invitations_reject], + ["users/groups/invite", ep___users_groups_invite], + ["users/groups/joined", ep___users_groups_joined], + ["users/groups/leave", ep___users_groups_leave], + ["users/groups/owned", ep___users_groups_owned], + ["users/groups/pull", ep___users_groups_pull], + ["users/groups/show", ep___users_groups_show], + ["users/groups/transfer", ep___users_groups_transfer], + ["users/groups/update", ep___users_groups_update], + ["users/lists/create", ep___users_lists_create], + ["users/lists/delete", ep___users_lists_delete], + ["users/lists/delete-all", ep___users_lists_delete_all], + ["users/lists/list", ep___users_lists_list], + ["users/lists/pull", ep___users_lists_pull], + ["users/lists/push", ep___users_lists_push], + ["users/lists/show", ep___users_lists_show], + ["users/lists/update", ep___users_lists_update], + ["users/notes", ep___users_notes], + ["users/pages", ep___users_pages], + ["users/reactions", ep___users_reactions], + ["users/recommendation", ep___users_recommendation], + ["users/relation", ep___users_relation], + ["users/report-abuse", ep___users_reportAbuse], + ["users/search-by-username-and-host", ep___users_searchByUsernameAndHost], + ["users/search", ep___users_search], + ["users/show", ep___users_show], + ["users/stats", ep___users_stats], + ["admin/drive-capacity-override", ep___admin_driveCapOverride], + ["fetch-rss", ep___fetchRss], ]; export interface IEndpointMeta { - readonly stability?: 'deprecated' | 'experimental' | 'stable'; + readonly stability?: "deprecated" | "experimental" | "stable"; readonly tags?: ReadonlyArray; @@ -694,7 +704,6 @@ export interface IEndpointMeta { * 省略した場合はリミテーションは無いものとして解釈されます。 */ readonly limit?: { - /** * 複数のエンドポイントでリミットを共有したい場合に指定するキー */ diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index 333746f42..486143140 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -1,69 +1,81 @@ -import define from '../../define.js'; -import { AbuseUserReports } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { AbuseUserReports } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - nullable: false, optional: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + nullable: false, + optional: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - nullable: false, optional: false, - format: 'date-time', + type: "string", + nullable: false, + optional: false, + format: "date-time", }, comment: { - type: 'string', - nullable: false, optional: false, + type: "string", + nullable: false, + optional: false, }, resolved: { - type: 'boolean', - nullable: false, optional: false, + type: "boolean", + nullable: false, + optional: false, example: false, }, reporterId: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, targetUserId: { - type: 'string', - nullable: false, optional: false, - format: 'id', + type: "string", + nullable: false, + optional: false, + format: "id", }, assigneeId: { - type: 'string', - nullable: true, optional: false, - format: 'id', + type: "string", + nullable: true, + optional: false, + format: "id", }, reporter: { - type: 'object', - nullable: false, optional: false, - ref: 'User', + type: "object", + nullable: false, + optional: false, + ref: "User", }, targetUser: { - type: 'object', - nullable: false, optional: false, - ref: 'User', + type: "object", + nullable: false, + optional: false, + ref: "User", }, assignee: { - type: 'object', - nullable: true, optional: true, - ref: 'User', + type: "object", + nullable: true, + optional: true, + ref: "User", }, }, }, @@ -71,36 +83,59 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - state: { type: 'string', nullable: true, default: null }, - reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "combined" }, - targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "combined" }, - forwarded: { type: 'boolean', default: false }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + state: { type: "string", nullable: true, default: null }, + reporterOrigin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "combined", + }, + targetUserOrigin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "combined", + }, + forwarded: { type: "boolean", default: false }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const query = makePaginationQuery(AbuseUserReports.createQueryBuilder('report'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + AbuseUserReports.createQueryBuilder("report"), + ps.sinceId, + ps.untilId, + ); switch (ps.state) { - case 'resolved': query.andWhere('report.resolved = TRUE'); break; - case 'unresolved': query.andWhere('report.resolved = FALSE'); break; + case "resolved": + query.andWhere("report.resolved = TRUE"); + break; + case "unresolved": + query.andWhere("report.resolved = FALSE"); + break; } switch (ps.reporterOrigin) { - case 'local': query.andWhere('report.reporterHost IS NULL'); break; - case 'remote': query.andWhere('report.reporterHost IS NOT NULL'); break; + case "local": + query.andWhere("report.reporterHost IS NULL"); + break; + case "remote": + query.andWhere("report.reporterHost IS NOT NULL"); + break; } switch (ps.targetUserOrigin) { - case 'local': query.andWhere('report.targetUserHost IS NULL'); break; - case 'remote': query.andWhere('report.targetUserHost IS NOT NULL'); break; + case "local": + query.andWhere("report.targetUserHost IS NULL"); + break; + case "remote": + query.andWhere("report.targetUserHost IS NOT NULL"); + break; } const reports = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index 5f8921999..11ef2273c 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -1,40 +1,42 @@ -import define from '../../../define.js'; -import { Users } from '@/models/index.js'; -import { signup } from '../../../common/signup.js'; -import { IsNull } from 'typeorm'; +import define from "../../../define.js"; +import { Users } from "@/models/index.js"; +import { signup } from "../../../common/signup.js"; +import { IsNull } from "typeorm"; export const meta = { - tags: ['admin'], + tags: ["admin"], res: { - type: 'object', - optional: false, nullable: false, - ref: 'User', + type: "object", + optional: false, + nullable: false, + ref: "User", properties: { token: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { username: Users.localUsernameSchema, password: Users.passwordSchema, }, - required: ['username', 'password'], + required: ["username", "password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, _me) => { const me = _me ? await Users.findOneByOrFail({ id: _me.id }) : null; - const noUsers = (await Users.countBy({ - host: IsNull(), - })) === 0; - if (!noUsers && !me?.isAdmin) throw new Error('access denied'); + const noUsers = + (await Users.countBy({ + host: IsNull(), + })) === 0; + if (!(noUsers || me?.isAdmin)) throw new Error("access denied"); const { account, secret } = await signup({ username: ps.username, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 629d70058..3f7243ab5 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -1,43 +1,42 @@ -import define from '../../../define.js'; -import { Users } from '@/models/index.js'; -import { doPostSuspend } from '@/services/suspend-user.js'; -import { publishUserEvent } from '@/services/stream.js'; -import { createDeleteAccountJob } from '@/queue/index.js'; +import define from "../../../define.js"; +import { Users } from "@/models/index.js"; +import { doPostSuspend } from "@/services/suspend-user.js"; +import { publishUserEvent } from "@/services/stream.js"; +import { createDeleteAccountJob } from "@/queue/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (user.isAdmin) { - throw new Error('cannot suspend admin'); + throw new Error("cannot suspend admin"); } if (user.isModerator) { - throw new Error('cannot suspend moderator'); + throw new Error("cannot suspend moderator"); } if (Users.isLocalUser(user)) { // 物理削除する前にDelete activityを送信する - await doPostSuspend(user).catch(e => {}); + await doPostSuspend(user).catch((e) => {}); createDeleteAccountJob(user, { soft: false, @@ -54,6 +53,6 @@ export default define(meta, paramDef, async (ps, me) => { if (Users.isLocalUser(user)) { // Terminate streaming - publishUserEvent(user.id, 'terminate', {}); + publishUserEvent(user.id, "terminate", {}); } }); diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts index 07cd984b0..15ad1f9a1 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts @@ -1,100 +1,104 @@ -import config from '@/config/index.js'; -import { Meta } from '@/models/entities/meta.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { db } from '@/db/postgre.js'; -import define from '../../../define.js'; +import config from "@/config/index.js"; +import { Meta } from "@/models/entities/meta.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { db } from "@/db/postgre.js"; +import define from "../../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const hostedConfig = config.isManagedHosting; - const hosted = (hostedConfig != null && hostedConfig === true); + const hosted = hostedConfig != null && hostedConfig === true; if (hosted) { const set = {} as Partial; if (config.deepl.managed != null && config.deepl.managed === true) { - if (typeof config.deepl.authKey === 'boolean') { + if (typeof config.deepl.authKey === "boolean") { set.deeplAuthKey = config.deepl.authKey; } - if (typeof config.deepl.isPro === 'boolean') { + if (typeof config.deepl.isPro === "boolean") { set.deeplIsPro = config.deepl.isPro; } } if (config.email.managed != null && config.email.managed === true) { set.enableEmail = true; - if (typeof config.email.address === 'string') { + if (typeof config.email.address === "string") { set.email = config.email.address; } - if (typeof config.email.host === 'string') { + if (typeof config.email.host === "string") { set.smtpHost = config.email.host; } - if (typeof config.email.port === 'number') { + if (typeof config.email.port === "number") { set.smtpPort = config.email.port; } - if (typeof config.email.user === 'string') { + if (typeof config.email.user === "string") { set.smtpUser = config.email.user; } - if (typeof config.email.pass === 'string') { + if (typeof config.email.pass === "string") { set.smtpPass = config.email.pass; } - if (typeof config.email.useImplicitSslTls === 'boolean') { + if (typeof config.email.useImplicitSslTls === "boolean") { set.smtpSecure = config.email.useImplicitSslTls; } } - if (config.objectStorage.managed != null && config.objectStorage.managed === true) { + if ( + config.objectStorage.managed != null && + config.objectStorage.managed === true + ) { set.useObjectStorage = true; - if (typeof config.objectStorage.baseUrl === 'string') { + if (typeof config.objectStorage.baseUrl === "string") { set.objectStorageBaseUrl = config.objectStorage.baseUrl; } - if (typeof config.objectStorage.bucket === 'string') { + if (typeof config.objectStorage.bucket === "string") { set.objectStorageBucket = config.objectStorage.bucket; } - if (typeof config.objectStorage.prefix === 'string') { + if (typeof config.objectStorage.prefix === "string") { set.objectStoragePrefix = config.objectStorage.prefix; } - if (typeof config.objectStorage.endpoint === 'string') { + if (typeof config.objectStorage.endpoint === "string") { set.objectStorageEndpoint = config.objectStorage.endpoint; } - if (typeof config.objectStorage.region === 'string') { + if (typeof config.objectStorage.region === "string") { set.objectStorageRegion = config.objectStorage.region; } - if (typeof config.objectStorage.accessKey === 'string') { + if (typeof config.objectStorage.accessKey === "string") { set.objectStorageAccessKey = config.objectStorage.accessKey; } - if (typeof config.objectStorage.secretKey === 'string') { + if (typeof config.objectStorage.secretKey === "string") { set.objectStorageSecretKey = config.objectStorage.secretKey; } - if (typeof config.objectStorage.useSsl === 'boolean') { + if (typeof config.objectStorage.useSsl === "boolean") { set.objectStorageUseSSL = config.objectStorage.useSsl; } - if (typeof config.objectStorage.connnectOverProxy === 'boolean') { + if (typeof config.objectStorage.connnectOverProxy === "boolean") { set.objectStorageUseProxy = config.objectStorage.connnectOverProxy; } - if (typeof config.objectStorage.setPublicReadOnUpload === 'boolean') { - set.objectStorageSetPublicRead = config.objectStorage.setPublicReadOnUpload; + if (typeof config.objectStorage.setPublicReadOnUpload === "boolean") { + set.objectStorageSetPublicRead = + config.objectStorage.setPublicReadOnUpload; } - if (typeof config.objectStorage.s3ForcePathStyle === 'boolean') { - set.objectStorageS3ForcePathStyle = config.objectStorage.s3ForcePathStyle; + if (typeof config.objectStorage.s3ForcePathStyle === "boolean") { + set.objectStorageS3ForcePathStyle = + config.objectStorage.s3ForcePathStyle; } } if (config.summalyProxyUrl !== undefined) { set.summalyProxy = config.summalyProxyUrl; } - await db.transaction(async transactionalEntityManager => { + await db.transaction(async (transactionalEntityManager) => { const metas = await transactionalEntityManager.find(Meta, { order: { - id: 'DESC', + id: "DESC", }, }); @@ -106,7 +110,7 @@ export default define(meta, paramDef, async (ps, me) => { await transactionalEntityManager.save(Meta, set); } }); - insertModerationLog(me, 'updateMeta'); + insertModerationLog(me, "updateMeta"); } return hosted; }); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index ab2c50b50..db39f3eb2 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -1,29 +1,36 @@ -import define from '../../../define.js'; -import { Ads } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import define from "../../../define.js"; +import { Ads } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - url: { type: 'string', minLength: 1 }, - memo: { type: 'string' }, - place: { type: 'string' }, - priority: { type: 'string' }, - ratio: { type: 'integer' }, - expiresAt: { type: 'integer' }, - imageUrl: { type: 'string', minLength: 1 }, + url: { type: "string", minLength: 1 }, + memo: { type: "string" }, + place: { type: "string" }, + priority: { type: "string" }, + ratio: { type: "integer" }, + expiresAt: { type: "integer" }, + imageUrl: { type: "string", minLength: 1 }, }, - required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'imageUrl'], + required: [ + "url", + "memo", + "place", + "priority", + "ratio", + "expiresAt", + "imageUrl", + ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { await Ads.insert({ id: genId(), diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index 0ead2be00..ee6d314de 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -1,31 +1,30 @@ -import define from '../../../define.js'; -import { Ads } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { Ads } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchAd: { - message: 'No such ad.', - code: 'NO_SUCH_AD', - id: 'ccac9863-3a03-416e-b899-8a64041118b1', + message: "No such ad.", + code: "NO_SUCH_AD", + id: "ccac9863-3a03-416e-b899-8a64041118b1", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, + id: { type: "string", format: "misskey:id" }, }, - required: ['id'], + required: ["id"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const ad = await Ads.findOneBy({ id: ps.id }); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 74f154f27..65944d31e 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -1,28 +1,30 @@ -import define from '../../../define.js'; -import { Ads } from '@/models/index.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import define from "../../../define.js"; +import { Ads } from "@/models/index.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const query = makePaginationQuery(Ads.createQueryBuilder('ad'), ps.sinceId, ps.untilId) - .andWhere('ad.expiresAt > :now', { now: new Date() }); + const query = makePaginationQuery( + Ads.createQueryBuilder("ad"), + ps.sinceId, + ps.untilId, + ).andWhere("ad.expiresAt > :now", { now: new Date() }); const ads = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index 650f8670e..2c7038731 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -1,38 +1,46 @@ -import define from '../../../define.js'; -import { Ads } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { Ads } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchAd: { - message: 'No such ad.', - code: 'NO_SUCH_AD', - id: 'b7aa1727-1354-47bc-a182-3a9c3973d300', + message: "No such ad.", + code: "NO_SUCH_AD", + id: "b7aa1727-1354-47bc-a182-3a9c3973d300", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, - memo: { type: 'string' }, - url: { type: 'string', minLength: 1 }, - imageUrl: { type: 'string', minLength: 1 }, - place: { type: 'string' }, - priority: { type: 'string' }, - ratio: { type: 'integer' }, - expiresAt: { type: 'integer' }, + id: { type: "string", format: "misskey:id" }, + memo: { type: "string" }, + url: { type: "string", minLength: 1 }, + imageUrl: { type: "string", minLength: 1 }, + place: { type: "string" }, + priority: { type: "string" }, + ratio: { type: "integer" }, + expiresAt: { type: "integer" }, }, - required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt'], + required: [ + "id", + "memo", + "url", + "imageUrl", + "place", + "priority", + "ratio", + "expiresAt", + ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const ad = await Ads.findOneBy({ id: ps.id }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 33076b6d3..a532b6677 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -1,60 +1,66 @@ -import define from '../../../define.js'; -import { Announcements } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import define from "../../../define.js"; +import { Announcements } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, updatedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, title: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, text: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, imageUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - title: { type: 'string', minLength: 1 }, - text: { type: 'string', minLength: 1 }, - imageUrl: { type: 'string', nullable: true, minLength: 1 }, + title: { type: "string", minLength: 1 }, + text: { type: "string", minLength: 1 }, + imageUrl: { type: "string", nullable: true, minLength: 1 }, }, - required: ['title', 'text', 'imageUrl'], + required: ["title", "text", "imageUrl"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const announcement = await Announcements.insert({ id: genId(), @@ -63,7 +69,10 @@ export default define(meta, paramDef, async (ps) => { title: ps.title, text: ps.text, imageUrl: ps.imageUrl, - }).then(x => Announcements.findOneByOrFail(x.identifiers[0])); + }).then((x) => Announcements.findOneByOrFail(x.identifiers[0])); - return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); + return Object.assign({}, announcement, { + createdAt: announcement.createdAt.toISOString(), + updatedAt: null, + }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index c17765f4f..5665b94a7 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -1,31 +1,30 @@ -import define from '../../../define.js'; -import { Announcements } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { Announcements } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchAnnouncement: { - message: 'No such announcement.', - code: 'NO_SUCH_ANNOUNCEMENT', - id: 'ecad8040-a276-4e85-bda9-015a708d291e', + message: "No such announcement.", + code: "NO_SUCH_ANNOUNCEMENT", + id: "ecad8040-a276-4e85-bda9-015a708d291e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, + id: { type: "string", format: "misskey:id" }, }, - required: ['id'], + required: ["id"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const announcement = await Announcements.findOneBy({ id: ps.id }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 7a5758d75..fc5b02070 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -1,52 +1,61 @@ -import { Announcements, AnnouncementReads } from '@/models/index.js'; -import { Announcement } from '@/models/entities/announcement.js'; -import define from '../../../define.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import { Announcements, AnnouncementReads } from "@/models/index.js"; +import type { Announcement } from "@/models/entities/announcement.js"; +import define from "../../../define.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, updatedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, text: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, title: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, imageUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, reads: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, @@ -54,30 +63,36 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + Announcements.createQueryBuilder("announcement"), + ps.sinceId, + ps.untilId, + ); const announcements = await query.take(ps.limit).getMany(); const reads = new Map(); for (const announcement of announcements) { - reads.set(announcement, await AnnouncementReads.countBy({ - announcementId: announcement.id, - })); + reads.set( + announcement, + await AnnouncementReads.countBy({ + announcementId: announcement.id, + }), + ); } - return announcements.map(announcement => ({ + return announcements.map((announcement) => ({ id: announcement.id, createdAt: announcement.createdAt.toISOString(), updatedAt: announcement.updatedAt?.toISOString() ?? null, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index 61ce106d8..35e64f281 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -1,34 +1,33 @@ -import define from '../../../define.js'; -import { Announcements } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { Announcements } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchAnnouncement: { - message: 'No such announcement.', - code: 'NO_SUCH_ANNOUNCEMENT', - id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc', + message: "No such announcement.", + code: "NO_SUCH_ANNOUNCEMENT", + id: "d3aae5a7-6372-4cb4-b61c-f511ffc2d7cc", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, - title: { type: 'string', minLength: 1 }, - text: { type: 'string', minLength: 1 }, - imageUrl: { type: 'string', nullable: true, minLength: 1 }, + id: { type: "string", format: "misskey:id" }, + title: { type: "string", minLength: 1 }, + text: { type: "string", minLength: 1 }, + imageUrl: { type: "string", nullable: true, minLength: 1 }, }, - required: ['id', 'title', 'text', 'imageUrl'], + required: ["id", "title", "text", "imageUrl"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const announcement = await Announcements.findOneBy({ id: ps.id }); diff --git a/packages/backend/src/server/api/endpoints/admin/delete-account.ts b/packages/backend/src/server/api/endpoints/admin/delete-account.ts index 2d7ef2f23..9fd196888 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-account.ts @@ -1,26 +1,24 @@ -import { Users } from '@/models/index.js'; -import { deleteAccount } from '@/services/delete-account.js'; -import define from '../../define.js'; +import { Users } from "@/models/index.js"; +import { deleteAccount } from "@/services/delete-account.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, - res: { - }, + res: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await Users.findOneByOrFail({ id: ps.userId }); if (user.isDeleted) { diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index dc1976624..796900811 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -1,23 +1,22 @@ -import define from '../../define.js'; -import { deleteFile } from '@/services/drive/delete-file.js'; -import { DriveFiles } from '@/models/index.js'; +import define from "../../define.js"; +import { deleteFile } from "@/services/drive/delete-file.js"; +import { DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.findBy({ userId: ps.userId, diff --git a/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts index a4b29770e..1f6ac5f27 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts @@ -1,34 +1,33 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { User } from "@/models/entities/user.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - overrideMb: { type: 'number', nullable: true }, + userId: { type: "string", format: "misskey:id" }, + overrideMb: { type: "number", nullable: true }, }, - required: ['userId', 'overrideMb'], + required: ["userId", "overrideMb"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (!Users.isLocalUser(user)) { - throw new Error('user is not local user'); - } + throw new Error("user is not local user"); + } /*if (user.isAdmin) { throw new Error('cannot suspend admin'); @@ -41,7 +40,7 @@ export default define(meta, paramDef, async (ps, me) => { driveCapacityOverrideMb: ps.overrideMb, }); - insertModerationLog(me, 'change-drive-capacity-override', { + insertModerationLog(me, "change-drive-capacity-override", { targetId: user.id, }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts index bab149532..1b0c1260b 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts @@ -1,20 +1,19 @@ -import define from '../../../define.js'; -import { createCleanRemoteFilesJob } from '@/queue/index.js'; +import define from "../../../define.js"; +import { createCleanRemoteFilesJob } from "@/queue/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { createCleanRemoteFilesJob(); }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index 3db942e6c..04208f600 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -1,22 +1,21 @@ -import { IsNull } from 'typeorm'; -import define from '../../../define.js'; -import { deleteFile } from '@/services/drive/delete-file.js'; -import { DriveFiles } from '@/models/index.js'; +import { IsNull } from "typeorm"; +import define from "../../../define.js"; +import { deleteFile } from "@/services/drive/delete-file.js"; +import { DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.findBy({ userId: IsNull(), diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index ba32aac43..5cb0aecd8 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -1,70 +1,89 @@ -import { DriveFiles } from '@/models/index.js'; -import define from '../../../define.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import { DriveFiles } from "@/models/index.js"; +import define from "../../../define.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: false, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id', nullable: true }, - type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) }, - origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id", nullable: true }, + type: { + type: "string", + nullable: true, + pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1), + }, + origin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "local", + }, hostname: { - type: 'string', + type: "string", nullable: true, default: null, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + DriveFiles.createQueryBuilder("file"), + ps.sinceId, + ps.untilId, + ); if (ps.userId) { - query.andWhere('file.userId = :userId', { userId: ps.userId }); + query.andWhere("file.userId = :userId", { userId: ps.userId }); } else { - if (ps.origin === 'local') { - query.andWhere('file.userHost IS NULL'); - } else if (ps.origin === 'remote') { - query.andWhere('file.userHost IS NOT NULL'); + if (ps.origin === "local") { + query.andWhere("file.userHost IS NULL"); + } else if (ps.origin === "remote") { + query.andWhere("file.userHost IS NOT NULL"); } if (ps.hostname) { - query.andWhere('file.userHost = :hostname', { hostname: ps.hostname }); + query.andWhere("file.userHost = :hostname", { hostname: ps.hostname }); } } if (ps.type) { - if (ps.type.endsWith('/*')) { - query.andWhere('file.type like :type', { type: ps.type.replace('/*', '/') + '%' }); + if (ps.type.endsWith("/*")) { + query.andWhere("file.type like :type", { + type: `${ps.type.replace("/*", "/")}%`, + }); } else { - query.andWhere('file.type = :type', { type: ps.type }); + query.andWhere("file.type = :type", { type: ps.type }); } } const files = await query.take(ps.limit).getMany(); - return await DriveFiles.packMany(files, { detail: true, withUser: true, self: true }); + return await DriveFiles.packMany(files, { + detail: true, + withUser: true, + self: true, + }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index e9117a23c..d65ec09fc 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -1,192 +1,224 @@ -import { DriveFiles } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { DriveFiles } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'caf3ca38-c6e5-472e-a30c-b05377dcc240', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "caf3ca38-c6e5-472e-a30c-b05377dcc240", }, }, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, userId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, userHost: { - type: 'string', - optional: false, nullable: true, - description: 'The local host is represented with `null`.', + type: "string", + optional: false, + nullable: true, + description: "The local host is represented with `null`.", }, md5: { - type: 'string', - optional: false, nullable: false, - format: 'md5', - example: '15eca7fba0480996e2245f5185bf39f2', + type: "string", + optional: false, + nullable: false, + format: "md5", + example: "15eca7fba0480996e2245f5185bf39f2", }, name: { - type: 'string', - optional: false, nullable: false, - example: 'lenna.jpg', + type: "string", + optional: false, + nullable: false, + example: "lenna.jpg", }, type: { - type: 'string', - optional: false, nullable: false, - example: 'image/jpeg', + type: "string", + optional: false, + nullable: false, + example: "image/jpeg", }, size: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, example: 51469, }, comment: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, blurhash: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, properties: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { width: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, example: 1280, }, height: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, example: 720, }, avgColor: { - type: 'string', - optional: true, nullable: false, - example: 'rgb(40,65,87)', + type: "string", + optional: true, + nullable: false, + example: "rgb(40,65,87)", }, }, }, storedInternal: { - type: 'boolean', - optional: false, nullable: true, + type: "boolean", + optional: false, + nullable: true, example: true, }, url: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, thumbnailUrl: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, webpublicUrl: { - type: 'string', - optional: false, nullable: true, - format: 'url', + type: "string", + optional: false, + nullable: true, + format: "url", }, accessKey: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, thumbnailAccessKey: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, webpublicAccessKey: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, uri: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, src: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, folderId: { - type: 'string', - optional: false, nullable: true, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: true, + format: "id", + example: "xxxxxxxxxx", }, isSensitive: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isLink: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", anyOf: [ { properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], }, { properties: { - url: { type: 'string' }, + url: { type: "string" }, }, - required: ['url'], + required: ["url"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const file = ps.fileId ? await DriveFiles.findOneBy({ id: ps.fileId }) : await DriveFiles.findOne({ - where: [{ - url: ps.url, - }, { - thumbnailUrl: ps.url, - }, { - webpublicUrl: ps.url, - }], - }); + const file = ps.fileId + ? await DriveFiles.findOneBy({ id: ps.fileId }) + : await DriveFiles.findOne({ + where: [ + { + url: ps.url, + }, + { + thumbnailUrl: ps.url, + }, + { + webpublicUrl: ps.url, + }, + ], + }); if (file == null) { throw new ApiError(meta.errors.noSuchFile); } if (!me.isAdmin) { - delete file.requestIp; - delete file.requestHeaders; + file.requestIp = undefined; + file.requestHeaders = undefined; } return file; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index 232fbbd57..1ea457adf 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -1,30 +1,36 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { In } from 'typeorm'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { In } from "typeorm"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - ids: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, - aliases: { type: 'array', items: { - type: 'string', - } }, + ids: { + type: "array", + items: { + type: "string", + format: "misskey:id", + }, + }, + aliases: { + type: "array", + items: { + type: "string", + }, + }, }, - required: ['ids', 'aliases'], + required: ["ids", "aliases"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const emojis = await Emojis.findBy({ id: In(ps.ids), @@ -37,5 +43,5 @@ export default define(meta, paramDef, async (ps) => { }); } - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 67349c24e..601d754a0 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -1,42 +1,43 @@ -import define from '../../../define.js'; -import { Emojis, DriveFiles } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { ApiError } from '../../../error.js'; -import rndstr from 'rndstr'; -import { publishBroadcastStream } from '@/services/stream.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis, DriveFiles } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { ApiError } from "../../../error.js"; +import rndstr from "rndstr"; +import { publishBroadcastStream } from "@/services/stream.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchFile: { - message: 'No such file.', - code: 'MO_SUCH_FILE', - id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf', + message: "No such file.", + code: "MO_SUCH_FILE", + id: "fc46b5a4-6b92-4c33-ac66-b806659bb5cf", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); - const name = file.name.split('.')[0].match(/^[a-z0-9_]+$/) ? file.name.split('.')[0] : `_${rndstr('a-z0-9', 8)}_`; + const name = file.name.split(".")[0].match(/^[a-z0-9_]+$/) + ? file.name.split(".")[0] + : `_${rndstr("a-z0-9", 8)}_`; const emoji = await Emojis.insert({ id: genId(), @@ -48,15 +49,15 @@ export default define(meta, paramDef, async (ps, me) => { originalUrl: file.url, publicUrl: file.webpublicUrl ?? file.url, type: file.webpublicType ?? file.type, - }).then(x => Emojis.findOneByOrFail(x.identifiers[0])); + }).then((x) => Emojis.findOneByOrFail(x.identifiers[0])); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); - publishBroadcastStream('emojiAdded', { + publishBroadcastStream("emojiAdded", { emoji: await Emojis.pack(emoji.id), }); - insertModerationLog(me, 'addEmoji', { + insertModerationLog(me, "addEmoji", { emojiId: emoji.id, }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 7010ade0d..4a7f2bc61 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -1,48 +1,49 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { ApiError } from '../../../error.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; -import { publishBroadcastStream } from '@/services/stream.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { ApiError } from "../../../error.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import { publishBroadcastStream } from "@/services/stream.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchEmoji: { - message: 'No such emoji.', - code: 'NO_SUCH_EMOJI', - id: 'e2785b66-dca3-4087-9cac-b93c541cc425', + message: "No such emoji.", + code: "NO_SUCH_EMOJI", + id: "e2785b66-dca3-4087-9cac-b93c541cc425", }, }, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - emojiId: { type: 'string', format: 'misskey:id' }, + emojiId: { type: "string", format: "misskey:id" }, }, - required: ['emojiId'], + required: ["emojiId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const emoji = await Emojis.findOneBy({ id: ps.emojiId }); @@ -54,7 +55,11 @@ export default define(meta, paramDef, async (ps, me) => { try { // Create file - driveFile = await uploadFromUrl({ url: emoji.originalUrl, user: null, force: true }); + driveFile = await uploadFromUrl({ + url: emoji.originalUrl, + user: null, + force: true, + }); } catch (e) { throw new ApiError(); } @@ -68,11 +73,11 @@ export default define(meta, paramDef, async (ps, me) => { originalUrl: driveFile.url, publicUrl: driveFile.webpublicUrl ?? driveFile.url, type: driveFile.webpublicType ?? driveFile.type, - }).then(x => Emojis.findOneByOrFail(x.identifiers[0])); + }).then((x) => Emojis.findOneByOrFail(x.identifiers[0])); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); - publishBroadcastStream('emojiAdded', { + publishBroadcastStream("emojiAdded", { emoji: await Emojis.pack(copied.id), }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index 93a6c4e4e..585af231f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -1,28 +1,31 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { In } from 'typeorm'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { In } from "typeorm"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - ids: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, + ids: { + type: "array", + items: { + type: "string", + format: "misskey:id", + }, + }, }, - required: ['ids'], + required: ["ids"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const emojis = await Emojis.findBy({ id: In(ps.ids), @@ -30,10 +33,10 @@ export default define(meta, paramDef, async (ps, me) => { for (const emoji of emojis) { await Emojis.delete(emoji.id); - - await db.queryResultCache!.remove(['meta_emojis']); - - insertModerationLog(me, 'deleteEmoji', { + + await db.queryResultCache!.remove(["meta_emojis"]); + + insertModerationLog(me, "deleteEmoji", { emoji: emoji, }); } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index 67dbf28d8..761c7c377 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -1,33 +1,32 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchEmoji: { - message: 'No such emoji.', - code: 'NO_SUCH_EMOJI', - id: 'be83669b-773a-44b7-b1f8-e5e5170ac3c2', + message: "No such emoji.", + code: "NO_SUCH_EMOJI", + id: "be83669b-773a-44b7-b1f8-e5e5170ac3c2", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, + id: { type: "string", format: "misskey:id" }, }, - required: ['id'], + required: ["id"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const emoji = await Emojis.findOneBy({ id: ps.id }); @@ -35,9 +34,9 @@ export default define(meta, paramDef, async (ps, me) => { await Emojis.delete(emoji.id); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); - insertModerationLog(me, 'deleteEmoji', { + insertModerationLog(me, "deleteEmoji", { emoji: emoji, }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts index 3f03dc2da..6f49d6d18 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts @@ -1,6 +1,6 @@ -import define from '../../../define.js'; -import { createImportCustomEmojisJob } from '@/queue/index.js'; -import ms from 'ms'; +import define from "../../../define.js"; +import { createImportCustomEmojisJob } from "@/queue/index.js"; +import ms from "ms"; export const meta = { secure: true, @@ -9,14 +9,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createImportCustomEmojisJob(user, ps.fileId); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index d16689a28..63f60bc99 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -1,50 +1,59 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, aliases: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, category: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, host: { - type: 'string', - optional: false, nullable: true, - description: 'The local host is represented with `null`.', + type: "string", + optional: false, + nullable: true, + description: "The local host is represented with `null`.", }, url: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, @@ -52,40 +61,40 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - query: { type: 'string', nullable: true, default: null }, + query: { type: "string", nullable: true, default: null }, host: { - type: 'string', + type: "string", nullable: true, default: null, - description: 'Use `null` to represent the local host.', + description: "Use `null` to represent the local host.", }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId); + const q = makePaginationQuery( + Emojis.createQueryBuilder("emoji"), + ps.sinceId, + ps.untilId, + ); if (ps.host == null) { - q.andWhere(`emoji.host IS NOT NULL`); + q.andWhere("emoji.host IS NOT NULL"); } else { - q.andWhere(`emoji.host = :host`, { host: toPuny(ps.host) }); + q.andWhere("emoji.host = :host", { host: toPuny(ps.host) }); } if (ps.query) { - q.andWhere('emoji.name like :query', { query: '%' + ps.query + '%' }); + q.andWhere("emoji.name like :query", { query: `%${ps.query}%` }); } - const emojis = await q - .orderBy('emoji.id', 'DESC') - .take(ps.limit) - .getMany(); + const emojis = await q.orderBy("emoji.id", "DESC").take(ps.limit).getMany(); return Emojis.packMany(emojis); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 6192978fa..bc4f1d29f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -1,50 +1,59 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; -import { Emoji } from '@/models/entities/emoji.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; +import type { Emoji } from "@/models/entities/emoji.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, aliases: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, category: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, host: { - type: 'null', + type: "null", optional: false, - description: 'The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files.', + description: + "The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files.", }, url: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, @@ -52,20 +61,22 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - query: { type: 'string', nullable: true, default: null }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + query: { type: "string", nullable: true, default: null }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId) - .andWhere(`emoji.host IS NULL`); + const q = makePaginationQuery( + Emojis.createQueryBuilder("emoji"), + ps.sinceId, + ps.untilId, + ).andWhere("emoji.host IS NULL"); let emojis: Emoji[]; @@ -75,10 +86,12 @@ export default define(meta, paramDef, async (ps) => { emojis = await q.getMany(); - emojis = emojis.filter(emoji => - emoji.name.includes(ps.query!) || - emoji.aliases.some(a => a.includes(ps.query!)) || - emoji.category?.includes(ps.query!)); + emojis = emojis.filter( + (emoji) => + emoji.name.includes(ps.query!) || + emoji.aliases.some((a) => a.includes(ps.query!)) || + emoji.category?.includes(ps.query!), + ); emojis.splice(ps.limit + 1); } else { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index a4da40fff..4e57fa3dd 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -1,30 +1,36 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { In } from 'typeorm'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { In } from "typeorm"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - ids: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, - aliases: { type: 'array', items: { - type: 'string', - } }, + ids: { + type: "array", + items: { + type: "string", + format: "misskey:id", + }, + }, + aliases: { + type: "array", + items: { + type: "string", + }, + }, }, - required: ['ids', 'aliases'], + required: ["ids", "aliases"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const emojis = await Emojis.findBy({ id: In(ps.ids), @@ -33,9 +39,9 @@ export default define(meta, paramDef, async (ps) => { for (const emoji of emojis) { await Emojis.update(emoji.id, { updatedAt: new Date(), - aliases: emoji.aliases.filter(x => !ps.aliases.includes(x)), + aliases: emoji.aliases.filter((x) => !ps.aliases.includes(x)), }); } - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index ae3b190f4..1197f6077 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -1,37 +1,46 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { In } from 'typeorm'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { In } from "typeorm"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - ids: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, - aliases: { type: 'array', items: { - type: 'string', - } }, + ids: { + type: "array", + items: { + type: "string", + format: "misskey:id", + }, + }, + aliases: { + type: "array", + items: { + type: "string", + }, + }, }, - required: ['ids', 'aliases'], + required: ["ids", "aliases"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - await Emojis.update({ - id: In(ps.ids), - }, { - updatedAt: new Date(), - aliases: ps.aliases, - }); + await Emojis.update( + { + id: In(ps.ids), + }, + { + updatedAt: new Date(), + aliases: ps.aliases, + }, + ); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index cff58d617..17881a445 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -1,39 +1,45 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { In } from 'typeorm'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { In } from "typeorm"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - ids: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, + ids: { + type: "array", + items: { + type: "string", + format: "misskey:id", + }, + }, category: { - type: 'string', + type: "string", nullable: true, - description: 'Use `null` to reset the category.', + description: "Use `null` to reset the category.", }, }, - required: ['ids'], + required: ["ids"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - await Emojis.update({ - id: In(ps.ids), - }, { - updatedAt: new Date(), - category: ps.category, - }); + await Emojis.update( + { + id: In(ps.ids), + }, + { + updatedAt: new Date(), + category: ps.category, + }, + ); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index 5b547b3b7..3f7f6639f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -1,41 +1,43 @@ -import define from '../../../define.js'; -import { Emojis } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; -import { db } from '@/db/postgre.js'; +import define from "../../../define.js"; +import { Emojis } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchEmoji: { - message: 'No such emoji.', - code: 'NO_SUCH_EMOJI', - id: '684dec9d-a8c2-4364-9aa8-456c49cb1dc8', + message: "No such emoji.", + code: "NO_SUCH_EMOJI", + id: "684dec9d-a8c2-4364-9aa8-456c49cb1dc8", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - id: { type: 'string', format: 'misskey:id' }, - name: { type: 'string' }, + id: { type: "string", format: "misskey:id" }, + name: { type: "string" }, category: { - type: 'string', + type: "string", nullable: true, - description: 'Use `null` to reset the category.', + description: "Use `null` to reset the category.", + }, + aliases: { + type: "array", + items: { + type: "string", + }, }, - aliases: { type: 'array', items: { - type: 'string', - } }, }, - required: ['id', 'name', 'aliases'], + required: ["id", "name", "aliases"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const emoji = await Emojis.findOneBy({ id: ps.id }); @@ -48,5 +50,5 @@ export default define(meta, paramDef, async (ps) => { aliases: ps.aliases, }); - await db.queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(["meta_emojis"]); }); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index da5420147..534f226c2 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -1,23 +1,22 @@ -import define from '../../../define.js'; -import { deleteFile } from '@/services/drive/delete-file.js'; -import { DriveFiles } from '@/models/index.js'; +import define from "../../../define.js"; +import { deleteFile } from "@/services/drive/delete-file.js"; +import { DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, + host: { type: "string" }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.findBy({ userHost: ps.host, diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index cb2be5ab3..9c7165593 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -1,29 +1,28 @@ -import define from '../../../define.js'; -import { Instances } from '@/models/index.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; +import define from "../../../define.js"; +import { Instances } from "@/models/index.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, + host: { type: "string" }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); if (instance == null) { - throw new Error('instance not found'); + throw new Error("instance not found"); } fetchInstanceMetadata(instance, true); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index b7ee27db6..a1ccf11af 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -1,32 +1,35 @@ -import define from '../../../define.js'; -import deleteFollowing from '@/services/following/delete.js'; -import { Followings, Users } from '@/models/index.js'; +import define from "../../../define.js"; +import deleteFollowing from "@/services/following/delete.js"; +import { Followings, Users } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, + host: { type: "string" }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const followings = await Followings.findBy({ followerHost: ps.host, }); - const pairs = await Promise.all(followings.map(f => Promise.all([ - Users.findOneByOrFail({ id: f.followerId }), - Users.findOneByOrFail({ id: f.followeeId }), - ]))); + const pairs = await Promise.all( + followings.map((f) => + Promise.all([ + Users.findOneByOrFail({ id: f.followerId }), + Users.findOneByOrFail({ id: f.followeeId }), + ]), + ), + ); for (const pair of pairs) { deleteFollowing(pair[0], pair[1]); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 278131fb3..016989b54 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -1,32 +1,34 @@ -import define from '../../../define.js'; -import { Instances } from '@/models/index.js'; -import { toPuny } from '@/misc/convert-host.js'; +import define from "../../../define.js"; +import { Instances } from "@/models/index.js"; +import { toPuny } from "@/misc/convert-host.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, - isSuspended: { type: 'boolean' }, + host: { type: "string" }, + isSuspended: { type: "boolean" }, }, - required: ['host', 'isSuspended'], + required: ["host", "isSuspended"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); if (instance == null) { - throw new Error('instance not found'); + throw new Error("instance not found"); } - Instances.update({ host: toPuny(ps.host) }, { - isSuspended: ps.isSuspended, - }); + Instances.update( + { host: toPuny(ps.host) }, + { + isSuspended: ps.isSuspended, + }, + ); }); diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index dd16473f3..f39a369ec 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -1,23 +1,22 @@ -import define from '../../define.js'; -import { db } from '@/db/postgre.js'; +import define from "../../define.js"; +import { db } from "@/db/postgre.js"; export const meta = { requireCredential: true, requireModerator: true, - tags: ['admin'], + tags: ["admin"], } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { - const stats = await db.query(`SELECT * FROM pg_indexes;`).then(recs => { - const res = [] as { tablename: string; indexname: string; }[]; + const stats = await db.query("SELECT * FROM pg_indexes;").then((recs) => { + const res = [] as { tablename: string; indexname: string }[]; for (const rec of recs) { res.push(rec); } diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index aca2540fd..25d07f327 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -1,15 +1,16 @@ -import { db } from '@/db/postgre.js'; -import define from '../../define.js'; +import { db } from "@/db/postgre.js"; +import define from "../../define.js"; export const meta = { requireCredential: true, requireModerator: true, - tags: ['admin'], + tags: ["admin"], res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, example: { migrations: { count: 66, @@ -20,22 +21,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { - const sizes = await - db.query(` + const sizes = await db + .query(` SELECT relname AS "table", reltuples as "count", pg_total_relation_size(C.oid) AS "size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND C.relkind <> 'i' AND nspname !~ '^pg_toast';`) - .then(recs => { - const res = {} as Record; + .then((recs) => { + const res = {} as Record; for (const rec of recs) { res[rec.table] = { count: parseInt(rec.count, 10), diff --git a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts index e8b9cb3b0..da76ae624 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts @@ -1,30 +1,29 @@ -import { UserIps } from '@/models/index.js'; -import define from '../../define.js'; +import { UserIps } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const ips = await UserIps.find({ where: { userId: ps.userId }, - order: { createdAt: 'DESC' }, + order: { createdAt: "DESC" }, take: 30, }); - return ips.map(x => ({ + return ips.map((x) => ({ ip: x.ip, createdAt: x.createdAt.toISOString(), })); diff --git a/packages/backend/src/server/api/endpoints/admin/invite.ts b/packages/backend/src/server/api/endpoints/admin/invite.ts index 7e950cf87..b8bdb38b4 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite.ts @@ -1,22 +1,24 @@ -import rndstr from 'rndstr'; -import define from '../../define.js'; -import { RegistrationTickets } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import rndstr from "rndstr"; +import define from "../../define.js"; +import { RegistrationTickets } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { code: { - type: 'string', - optional: false, nullable: false, - example: '2ERUA5VR', + type: "string", + optional: false, + nullable: false, + example: "2ERUA5VR", maxLength: 8, minLength: 8, }, @@ -25,16 +27,15 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const code = rndstr({ length: 8, - chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns) + chars: "2-9A-HJ-NP-Z", // [0-9A-Z] w/o [01IO] (32 patterns) }); await RegistrationTickets.insert({ diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 71a217d93..1808de118 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -1,385 +1,470 @@ -import config from '@/config/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import define from '../../define.js'; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { MAX_NOTE_TEXT_LENGTH } from "@/const.js"; +import define from "../../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: true, requireAdmin: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { driveCapacityPerLocalUserMb: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, driveCapacityPerRemoteUserMb: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, cacheRemoteFiles: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, emailRequiredForSignup: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableHcaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hcaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, enableRecaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, recaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, swPublickey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, mascotImageUrl: { - type: 'string', - optional: false, nullable: false, - default: '/assets/ai.png', + type: "string", + optional: false, + nullable: false, + default: "/assets/ai.png", }, bannerUrl: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, errorImageUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://xn--931a.moe/aiart/yubitun.png', + type: "string", + optional: false, + nullable: false, + default: "https://xn--931a.moe/aiart/yubitun.png", }, iconUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, maxNoteTextLength: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, emojis: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, aliases: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, category: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, host: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, url: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, }, }, }, ads: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { place: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, url: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, imageUrl: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, }, }, }, enableEmail: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableTwitterIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableGithubIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableDiscordIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableServiceWorker: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, translatorAvailable: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, proxyAccountName: { - type: 'string', - optional: false, nullable: true, - }, - userStarForReactionFallback: { - type: 'boolean', - optional: true, nullable: false, + type: "string", + optional: false, + nullable: true, }, recommendedInstances: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, pinnedUsers: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, customMOTD: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, customSplashIcons: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, hiddenTags: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, blockedHosts: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, allowedHosts: { - type: 'array', - optional: true, nullable: false, + type: "array", + optional: true, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, privateMode: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, secureMode: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hcaptchaSecretKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, recaptchaSecretKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, sensitiveMediaDetection: { - type: 'string', - optional: true, nullable: false, + type: "string", + optional: true, + nullable: false, }, sensitiveMediaDetectionSensitivity: { - type: 'string', - optional: true, nullable: false, + type: "string", + optional: true, + nullable: false, }, setSensitiveFlagAutomatically: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, enableSensitiveMediaDetectionForVideos: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, proxyAccountId: { - type: 'string', - optional: true, nullable: true, - format: 'id', + type: "string", + optional: true, + nullable: true, + format: "id", }, twitterConsumerKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, twitterConsumerSecret: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, githubClientId: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, githubClientSecret: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, discordClientId: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, discordClientSecret: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, summaryProxy: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, email: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, smtpSecure: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, smtpHost: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, smtpPort: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, smtpUser: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, smtpPass: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, swPrivateKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, useObjectStorage: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, objectStorageBaseUrl: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStorageBucket: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStoragePrefix: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStorageEndpoint: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStorageRegion: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStoragePort: { - type: 'number', - optional: true, nullable: true, + type: "number", + optional: true, + nullable: true, }, objectStorageAccessKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStorageSecretKey: { - type: 'string', - optional: true, nullable: true, + type: "string", + optional: true, + nullable: true, }, objectStorageUseSSL: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, objectStorageUseProxy: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, objectStorageSetPublicRead: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, enableIpLogging: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, enableActiveEmailValidation: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, + }, + defaultReaction: { + type: "string", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', - properties: { - }, + type: "object", + properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const instance = await fetchMeta(true); @@ -425,7 +510,7 @@ export default define(meta, paramDef, async (ps, me) => { pinnedPages: instance.pinnedPages, pinnedClipId: instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, - useStarForReactionFallback: instance.useStarForReactionFallback, + defaultReaction: instance.defaultReaction, recommendedInstances: instance.recommendedInstances, pinnedUsers: instance.pinnedUsers, customMOTD: instance.customMOTD, @@ -438,9 +523,11 @@ export default define(meta, paramDef, async (ps, me) => { hcaptchaSecretKey: instance.hcaptchaSecretKey, recaptchaSecretKey: instance.recaptchaSecretKey, sensitiveMediaDetection: instance.sensitiveMediaDetection, - sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, + sensitiveMediaDetectionSensitivity: + instance.sensitiveMediaDetectionSensitivity, setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, - enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, + enableSensitiveMediaDetectionForVideos: + instance.enableSensitiveMediaDetectionForVideos, proxyAccountId: instance.proxyAccountId, twitterConsumerKey: instance.twitterConsumerKey, twitterConsumerSecret: instance.twitterConsumerSecret, diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts index 7b209c2d9..478f2661b 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts @@ -1,37 +1,39 @@ -import define from '../../../define.js'; -import { Users } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../../define.js"; +import { Users } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (user.isAdmin) { - throw new Error('cannot mark as moderator if admin user'); + throw new Error("cannot mark as moderator if admin user"); } await Users.update(user.id, { isModerator: true, }); - publishInternalEvent('userChangeModeratorState', { id: user.id, isModerator: true }); + publishInternalEvent("userChangeModeratorState", { + id: user.id, + isModerator: true, + }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts index a01e9f3c6..a43cc0cbe 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts @@ -1,33 +1,35 @@ -import define from '../../../define.js'; -import { Users } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../../define.js"; +import { Users } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } await Users.update(user.id, { isModerator: false, }); - publishInternalEvent('userChangeModeratorState', { id: user.id, isModerator: false }); + publishInternalEvent("userChangeModeratorState", { + id: user.id, + isModerator: false, + }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index b5142fcf0..a6d1f3519 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -1,42 +1,42 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getNote } from '../../../common/getters.js'; -import { PromoNotes } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getNote } from "../../../common/getters.js"; +import { PromoNotes } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'ee449fbe-af2a-453b-9cae-cf2fe7c895fc', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "ee449fbe-af2a-453b-9cae-cf2fe7c895fc", }, alreadyPromoted: { - message: 'The note has already promoted.', - code: 'ALREADY_PROMOTED', - id: 'ae427aa2-7a41-484f-a18c-2c1104051604', + message: "The note has already promoted.", + code: "ALREADY_PROMOTED", + id: "ae427aa2-7a41-484f-a18c-2c1104051604", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - expiresAt: { type: 'integer' }, + noteId: { type: "string", format: "misskey:id" }, + expiresAt: { type: "integer" }, }, - required: ['noteId', 'expiresAt'], + required: ["noteId", "expiresAt"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts index 8f015c280..9b828bb24 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts @@ -1,23 +1,22 @@ -import define from '../../../define.js'; -import { destroy } from '@/queue/index.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import define from "../../../define.js"; +import { destroy } from "@/queue/index.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { destroy(); - insertModerationLog(me, 'clearQueue'); + insertModerationLog(me, "clearQueue"); }); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 70f7d77de..15fdfb025 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -1,53 +1,51 @@ -import { deliverQueue } from '@/queue/queues.js'; -import { URL } from 'node:url'; -import define from '../../../define.js'; +import { deliverQueue } from "@/queue/queues.js"; +import { URL } from "node:url"; +import define from "../../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { anyOf: [ { - type: 'string', + type: "string", }, { - type: 'number', + type: "number", }, ], }, }, - example: [[ - 'example.com', - 12, - ]], + example: [["example.com", 12]], }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const jobs = await deliverQueue.getJobs(['delayed']); + const jobs = await deliverQueue.getJobs(["delayed"]); const res = [] as [string, number][]; for (const job of jobs) { const host = new URL(job.data.to).host; - if (res.find(x => x[0] === host)) { - res.find(x => x[0] === host)![1]++; + if (res.find((x) => x[0] === host)) { + res.find((x) => x[0] === host)![1]++; } else { res.push([host, 1]); } diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index 2235ce8f9..1890bd434 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -1,53 +1,51 @@ -import { URL } from 'node:url'; -import define from '../../../define.js'; -import { inboxQueue } from '@/queue/queues.js'; +import { URL } from "node:url"; +import define from "../../../define.js"; +import { inboxQueue } from "@/queue/queues.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { anyOf: [ { - type: 'string', + type: "string", }, { - type: 'number', + type: "number", }, ], }, }, - example: [[ - 'example.com', - 12, - ]], + example: [["example.com", 12]], }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const jobs = await inboxQueue.getJobs(['delayed']); + const jobs = await inboxQueue.getJobs(["delayed"]); const res = [] as [string, number][]; for (const job of jobs) { const host = new URL(job.data.signature.keyId).host; - if (res.find(x => x[0] === host)) { - res.find(x => x[0] === host)![1]++; + if (res.find((x) => x[0] === host)) { + res.find((x) => x[0] === host)![1]++; } else { res.push([host, 1]); } diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index 988b5a5e3..ecd67d893 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -1,43 +1,52 @@ -import { deliverQueue, inboxQueue, dbQueue, objectStorageQueue } from '@/queue/queues.js'; -import define from '../../../define.js'; +import { + deliverQueue, + inboxQueue, + dbQueue, + objectStorageQueue, +} from "@/queue/queues.js"; +import define from "../../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { deliver: { - optional: false, nullable: false, - ref: 'QueueCount', + optional: false, + nullable: false, + ref: "QueueCount", }, inbox: { - optional: false, nullable: false, - ref: 'QueueCount', + optional: false, + nullable: false, + ref: "QueueCount", }, db: { - optional: false, nullable: false, - ref: 'QueueCount', + optional: false, + nullable: false, + ref: "QueueCount", }, objectStorage: { - optional: false, nullable: false, - ref: 'QueueCount', + optional: false, + nullable: false, + ref: "QueueCount", }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const deliverJobCounts = await deliverQueue.getJobCounts(); const inboxJobCounts = await inboxQueue.getJobCounts(); diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index 4384e20f0..bb56216a7 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -1,63 +1,62 @@ -import { URL } from 'node:url'; -import define from '../../../define.js'; -import { addRelay } from '@/services/relay.js'; -import { ApiError } from '../../../error.js'; +import { URL } from "node:url"; +import define from "../../../define.js"; +import { addRelay } from "@/services/relay.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, errors: { invalidUrl: { - message: 'Invalid URL', - code: 'INVALID_URL', - id: 'fb8c92d3-d4e5-44e7-b3d4-800d5cef8b2c', + message: "Invalid URL", + code: "INVALID_URL", + id: "fb8c92d3-d4e5-44e7-b3d4-800d5cef8b2c", }, }, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, inbox: { - description: 'URL of the inbox, must be a https scheme URL', - type: 'string', - optional: false, nullable: false, - format: 'url', + description: "URL of the inbox, must be a https scheme URL", + type: "string", + optional: false, + nullable: false, + format: "url", }, status: { - type: 'string', - optional: false, nullable: false, - default: 'requesting', - enum: [ - 'requesting', - 'accepted', - 'rejected', - ], + type: "string", + optional: false, + nullable: false, + default: "requesting", + enum: ["requesting", "accepted", "rejected"], }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - inbox: { type: 'string' }, + inbox: { type: "string" }, }, - required: ['inbox'], + required: ["inbox"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { try { - if (new URL(ps.inbox).protocol !== 'https:') throw new Error('https only'); + if (new URL(ps.inbox).protocol !== "https:") throw new Error("https only"); } catch { throw new ApiError(meta.errors.invalidUrl); } diff --git a/packages/backend/src/server/api/endpoints/admin/relays/list.ts b/packages/backend/src/server/api/endpoints/admin/relays/list.ts index 89ec651e6..4c294ba9b 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/list.ts @@ -1,38 +1,39 @@ -import define from '../../../define.js'; -import { listRelay } from '@/services/relay.js'; +import define from "../../../define.js"; +import { listRelay } from "@/services/relay.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, inbox: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, status: { - type: 'string', - optional: false, nullable: false, - default: 'requesting', - enum: [ - 'requesting', - 'accepted', - 'rejected', - ], + type: "string", + optional: false, + nullable: false, + default: "requesting", + enum: ["requesting", "accepted", "rejected"], }, }, }, @@ -40,12 +41,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { return await listRelay(); }); diff --git a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts index b59cf72c5..1b3d90628 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts @@ -1,22 +1,21 @@ -import define from '../../../define.js'; -import { removeRelay } from '@/services/relay.js'; +import define from "../../../define.js"; +import { removeRelay } from "@/services/relay.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - inbox: { type: 'string' }, + inbox: { type: "string" }, }, - required: ['inbox'], + required: ["inbox"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { return await removeRelay(ps.inbox); }); diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index be4c2dcee..dd3f258f7 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -1,21 +1,23 @@ -import define from '../../define.js'; -import bcrypt from 'bcryptjs'; -import rndstr from 'rndstr'; -import { Users, UserProfiles } from '@/models/index.js'; +import define from "../../define.js"; +import bcrypt from "bcryptjs"; +import rndstr from "rndstr"; +import { Users, UserProfiles } from "@/models/index.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { password: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, minLength: 8, maxLength: 8, }, @@ -24,35 +26,37 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (user.isAdmin) { - throw new Error('cannot reset password of admin'); + throw new Error("cannot reset password of admin"); } - const passwd = rndstr('a-zA-Z0-9', 8); + const passwd = rndstr("a-zA-Z0-9", 8); // Generate hash of password const hash = bcrypt.hashSync(passwd); - await UserProfiles.update({ - userId: user.id, - }, { - password: hash, - }); + await UserProfiles.update( + { + userId: user.id, + }, + { + password: hash, + }, + ); return { password: passwd, diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index 3edae4a85..c876a2198 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -1,39 +1,42 @@ -import define from '../../define.js'; -import { AbuseUserReports, Users } from '@/models/index.js'; -import { getInstanceActor } from '@/services/instance-actor.js'; -import { deliver } from '@/queue/index.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { renderFlag } from '@/remote/activitypub/renderer/flag.js'; +import define from "../../define.js"; +import { AbuseUserReports, Users } from "@/models/index.js"; +import { getInstanceActor } from "@/services/instance-actor.js"; +import { deliver } from "@/queue/index.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { renderFlag } from "@/remote/activitypub/renderer/flag.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - reportId: { type: 'string', format: 'misskey:id' }, - forward: { type: 'boolean', default: false }, + reportId: { type: "string", format: "misskey:id" }, + forward: { type: "boolean", default: false }, }, - required: ['reportId'], + required: ["reportId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const report = await AbuseUserReports.findOneByOrFail({ id: ps.reportId }); if (report == null) { - throw new Error('report not found'); + throw new Error("report not found"); } if (ps.forward && report.targetUserHost != null) { const actor = await getInstanceActor(); const targetUser = await Users.findOneByOrFail({ id: report.targetUserId }); - deliver(actor, renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); + deliver( + actor, + renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)), + targetUser.inbox, + ); } await AbuseUserReports.update(report.id, { diff --git a/packages/backend/src/server/api/endpoints/admin/send-email.ts b/packages/backend/src/server/api/endpoints/admin/send-email.ts index bbdd66e4c..1676f6890 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-email.ts @@ -1,24 +1,23 @@ -import define from '../../define.js'; -import { sendEmail } from '@/services/send-email.js'; +import define from "../../define.js"; +import { sendEmail } from "@/services/send-email.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - to: { type: 'string' }, - subject: { type: 'string' }, - text: { type: 'string' }, + to: { type: "string" }, + subject: { type: "string" }, + text: { type: "string" }, }, - required: ['to', 'subject', 'text'], + required: ["to", "subject", "text"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { await sendEmail(ps.to, ps.subject, ps.text, ps.text); }); diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index 85c6fb82e..8998032cc 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -1,85 +1,100 @@ -import * as os from 'node:os'; -import si from 'systeminformation'; -import define from '../../define.js'; -import { redisClient } from '../../../../db/redis.js'; -import { db } from '@/db/postgre.js'; +import * as os from "node:os"; +import si from "systeminformation"; +import define from "../../define.js"; +import { redisClient } from "../../../../db/redis.js"; +import { db } from "@/db/postgre.js"; export const meta = { requireCredential: true, requireModerator: true, - tags: ['admin', 'meta'], + tags: ["admin", "meta"], res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { machine: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, os: { - type: 'string', - optional: false, nullable: false, - example: 'linux', + type: "string", + optional: false, + nullable: false, + example: "linux", }, node: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, psql: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, cpu: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { model: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, cores: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, mem: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { total: { - type: 'number', - optional: false, nullable: false, - format: 'bytes', + type: "number", + optional: false, + nullable: false, + format: "bytes", }, }, }, fs: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { total: { - type: 'number', - optional: false, nullable: false, - format: 'bytes', + type: "number", + optional: false, + nullable: false, + format: "bytes", }, used: { - type: 'number', - optional: false, nullable: false, - format: 'bytes', + type: "number", + optional: false, + nullable: false, + format: "bytes", }, }, }, net: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { interface: { - type: 'string', - optional: false, nullable: false, - example: 'eth0', + type: "string", + optional: false, + nullable: false, + example: "eth0", }, }, }, @@ -88,26 +103,27 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const memStats = await si.mem(); const fsStats = await si.fsSize(); const netInterface = await si.networkInterfaceDefault(); - const redisServerInfo = await redisClient.info('Server'); - const m = redisServerInfo.match(new RegExp('^redis_version:(.*)', 'm')); + const redisServerInfo = await redisClient.info("Server"); + const m = redisServerInfo.match(new RegExp("^redis_version:(.*)", "m")); const redis_version = m?.[1]; return { machine: os.hostname(), os: os.platform(), node: process.version, - psql: await db.query('SHOW server_version').then(x => x[0].server_version), + psql: await db + .query("SHOW server_version") + .then((x) => x[0].server_version), redis: redis_version, cpu: { model: os.cpus()[0].model, diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts index 3545536aa..df7e8979c 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -1,47 +1,55 @@ -import define from '../../define.js'; -import { ModerationLogs } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { ModerationLogs } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, type: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, info: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, }, userId: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, user: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, }, @@ -49,18 +57,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + ModerationLogs.createQueryBuilder("report"), + ps.sinceId, + ps.untilId, + ); const reports = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 0d866b311..e91f07f83 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -1,27 +1,27 @@ -import { Signins, UserProfiles, Users } from '@/models/index.js'; -import define from '../../define.js'; +import { Signins, UserProfiles, Users } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'object', - nullable: false, optional: false, + type: "object", + nullable: false, + optional: false, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const [user, profile] = await Promise.all([ Users.findOneBy({ id: ps.userId }), @@ -29,12 +29,12 @@ export default define(meta, paramDef, async (ps, me) => { ]); if (user == null || profile == null) { - throw new Error('user not found'); + throw new Error("user not found"); } const _me = await Users.findOneByOrFail({ id: me.id }); - if ((_me.isModerator && !_me.isAdmin) && user.isAdmin) { - throw new Error('cannot show info of admin'); + if (_me.isModerator && !_me.isAdmin && user.isAdmin) { + throw new Error("cannot show info of admin"); } if (!_me.isAdmin) { @@ -45,9 +45,11 @@ export default define(meta, paramDef, async (ps, me) => { }; } - const maskedKeys = ['accessToken', 'accessTokenSecret', 'refreshToken']; - Object.keys(profile.integrations).forEach(integration => { - maskedKeys.forEach(key => profile.integrations[integration][key] = ''); + const maskedKeys = ["accessToken", "accessTokenSecret", "refreshToken"]; + Object.keys(profile.integrations).forEach((integration) => { + maskedKeys.forEach( + (key) => (profile.integrations[integration][key] = ""), + ); }); const signins = await Signins.findBy({ userId: user.id }); diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 8e09e72d5..868df9dc9 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,77 +1,143 @@ -import { Users } from '@/models/index.js'; -import define from '../../define.js'; +import { Users } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, res: { - type: 'array', - nullable: false, optional: false, + type: "array", + nullable: false, + optional: false, items: { - type: 'object', - nullable: false, optional: false, - ref: 'UserDetailed', + type: "object", + nullable: false, + optional: false, + ref: "UserDetailed", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, - sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, - state: { type: 'string', enum: ['all', 'alive', 'available', 'admin', 'moderator', 'adminOrModerator', 'silenced', 'suspended'], default: 'all' }, - origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' }, - username: { type: 'string', nullable: true, default: null }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, + sort: { + type: "string", + enum: [ + "+follower", + "-follower", + "+createdAt", + "-createdAt", + "+updatedAt", + "-updatedAt", + ], + }, + state: { + type: "string", + enum: [ + "all", + "alive", + "available", + "admin", + "moderator", + "adminOrModerator", + "silenced", + "suspended", + ], + default: "all", + }, + origin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "combined", + }, + username: { type: "string", nullable: true, default: null }, hostname: { - type: 'string', + type: "string", nullable: true, default: null, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Users.createQueryBuilder('user'); + const query = Users.createQueryBuilder("user"); switch (ps.state) { - case 'available': query.where('user.isSuspended = FALSE'); break; - case 'admin': query.where('user.isAdmin = TRUE'); break; - case 'moderator': query.where('user.isModerator = TRUE'); break; - case 'adminOrModerator': query.where('user.isAdmin = TRUE OR user.isModerator = TRUE'); break; - case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break; - case 'silenced': query.where('user.isSilenced = TRUE'); break; - case 'suspended': query.where('user.isSuspended = TRUE'); break; + case "available": + query.where("user.isSuspended = FALSE"); + break; + case "admin": + query.where("user.isAdmin = TRUE"); + break; + case "moderator": + query.where("user.isModerator = TRUE"); + break; + case "adminOrModerator": + query.where("user.isAdmin = TRUE OR user.isModerator = TRUE"); + break; + case "alive": + query.where("user.updatedAt > :date", { + date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5), + }); + break; + case "silenced": + query.where("user.isSilenced = TRUE"); + break; + case "suspended": + query.where("user.isSuspended = TRUE"); + break; } switch (ps.origin) { - case 'local': query.andWhere('user.host IS NULL'); break; - case 'remote': query.andWhere('user.host IS NOT NULL'); break; + case "local": + query.andWhere("user.host IS NULL"); + break; + case "remote": + query.andWhere("user.host IS NOT NULL"); + break; } if (ps.username) { - query.andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }); + query.andWhere("user.usernameLower like :username", { + username: `${ps.username.toLowerCase()}%`, + }); } if (ps.hostname) { - query.andWhere('user.host = :hostname', { hostname: ps.hostname.toLowerCase() }); + query.andWhere("user.host = :hostname", { + hostname: ps.hostname.toLowerCase(), + }); } switch (ps.sort) { - case '+follower': query.orderBy('user.followersCount', 'DESC'); break; - case '-follower': query.orderBy('user.followersCount', 'ASC'); break; - case '+createdAt': query.orderBy('user.createdAt', 'DESC'); break; - case '-createdAt': query.orderBy('user.createdAt', 'ASC'); break; - case '+updatedAt': query.orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); break; - case '-updatedAt': query.orderBy('user.updatedAt', 'ASC', 'NULLS FIRST'); break; - default: query.orderBy('user.id', 'ASC'); break; + case "+follower": + query.orderBy("user.followersCount", "DESC"); + break; + case "-follower": + query.orderBy("user.followersCount", "ASC"); + break; + case "+createdAt": + query.orderBy("user.createdAt", "DESC"); + break; + case "-createdAt": + query.orderBy("user.createdAt", "ASC"); + break; + case "+updatedAt": + query.orderBy("user.updatedAt", "DESC", "NULLS LAST"); + break; + case "-updatedAt": + query.orderBy("user.updatedAt", "ASC", "NULLS FIRST"); + break; + default: + query.orderBy("user.id", "ASC"); + break; } query.take(ps.limit); diff --git a/packages/backend/src/server/api/endpoints/admin/silence-user.ts b/packages/backend/src/server/api/endpoints/admin/silence-user.ts index 17b9f3b5a..a61823297 100644 --- a/packages/backend/src/server/api/endpoints/admin/silence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/silence-user.ts @@ -1,42 +1,44 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (user.isAdmin) { - throw new Error('cannot silence admin'); + throw new Error("cannot silence admin"); } await Users.update(user.id, { isSilenced: true, }); - publishInternalEvent('userChangeSilencedState', { id: user.id, isSilenced: true }); + publishInternalEvent("userChangeSilencedState", { + id: user.id, + isSilenced: true, + }); - insertModerationLog(me, 'silence', { + insertModerationLog(me, "silence", { targetId: user.id, }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index f03bf592a..984bc0789 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -1,59 +1,58 @@ -import define from '../../define.js'; -import deleteFollowing from '@/services/following/delete.js'; -import { Users, Followings, Notifications } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { doPostSuspend } from '@/services/suspend-user.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import deleteFollowing from "@/services/following/delete.js"; +import { Users, Followings, Notifications } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { doPostSuspend } from "@/services/suspend-user.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } if (user.isAdmin) { - throw new Error('cannot suspend admin'); + throw new Error("cannot suspend admin"); } if (user.isModerator) { - throw new Error('cannot suspend moderator'); + throw new Error("cannot suspend moderator"); } await Users.update(user.id, { isSuspended: true, }); - insertModerationLog(me, 'suspend', { + insertModerationLog(me, "suspend", { targetId: user.id, }); // Terminate streaming if (Users.isLocalUser(user)) { - publishUserEvent(user.id, 'terminate', {}); + publishUserEvent(user.id, "terminate", {}); } (async () => { - await doPostSuspend(user).catch(e => {}); - await unFollowAll(user).catch(e => {}); - await readAllNotify(user).catch(e => {}); + await doPostSuspend(user).catch((e) => {}); + await unFollowAll(user).catch((e) => {}); + await readAllNotify(user).catch((e) => {}); })(); }); @@ -76,10 +75,13 @@ async function unFollowAll(follower: User) { } async function readAllNotify(notifier: User) { - await Notifications.update({ - notifierId: notifier.id, - isRead: false, - }, { - isRead: true, - }); + await Notifications.update( + { + notifierId: notifier.id, + isRead: false, + }, + { + isRead: true, + }, + ); } diff --git a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts index a4b373f5c..6a01b8e8d 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts @@ -1,38 +1,40 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } await Users.update(user.id, { isSilenced: false, }); - publishInternalEvent('userChangeSilencedState', { id: user.id, isSilenced: false }); + publishInternalEvent("userChangeSilencedState", { + id: user.id, + isSilenced: false, + }); - insertModerationLog(me, 'unsilence', { + insertModerationLog(me, "unsilence", { targetId: user.id, }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 5cf26251b..e51d5851c 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -1,36 +1,35 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { doPostUnsuspend } from '@/services/unsuspend-user.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { doPostUnsuspend } from "@/services/unsuspend-user.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } await Users.update(user.id, { isSuspended: false, }); - insertModerationLog(me, 'unsuspend', { + insertModerationLog(me, "unsuspend", { targetId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 61a1338f2..28aac4a4d 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -1,148 +1,191 @@ -import { Meta } from '@/models/entities/meta.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; -import { db } from '@/db/postgre.js'; -import define from '../../define.js'; +import { Meta } from "@/models/entities/meta.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { DB_MAX_NOTE_TEXT_LENGTH } from "@/misc/hard-limits.js"; +import { db } from "@/db/postgre.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireAdmin: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - disableRegistration: { type: 'boolean', nullable: true }, - disableLocalTimeline: { type: 'boolean', nullable: true }, - disableRecommendedTimeline: { type: 'boolean', nullable: true }, - disableGlobalTimeline: { type: 'boolean', nullable: true }, - useStarForReactionFallback: { type: 'boolean', nullable: true }, - recommendedInstances: { type: 'array', nullable: true, items: { - type: 'string', - } }, - pinnedUsers: { type: 'array', nullable: true, items: { - type: 'string', - } }, - customMOTD: { type: 'array', nullable: true, items: { - type: 'string', - } }, - customSplashIcons: { type: 'array', nullable: true, items: { - type: 'string', - } }, - hiddenTags: { type: 'array', nullable: true, items: { - type: 'string', - } }, - blockedHosts: { type: 'array', nullable: true, items: { - type: 'string', - } }, - allowedHosts: { type: 'array', nullable: true, items: { - type: 'string', - } }, - secureMode: { type: 'boolean', nullable: true }, - privateMode: { type: 'boolean', nullable: true }, - themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' }, - mascotImageUrl: { type: 'string', nullable: true }, - bannerUrl: { type: 'string', nullable: true }, - logoImageUrl: { type: 'string', nullable: true }, - errorImageUrl: { type: 'string', nullable: true }, - iconUrl: { type: 'string', nullable: true }, - backgroundImageUrl: { type: 'string', nullable: true }, - name: { type: 'string', nullable: true }, - description: { type: 'string', nullable: true }, - defaultLightTheme: { type: 'string', nullable: true }, - defaultDarkTheme: { type: 'string', nullable: true }, - localDriveCapacityMb: { type: 'integer' }, - remoteDriveCapacityMb: { type: 'integer' }, - cacheRemoteFiles: { type: 'boolean' }, - emailRequiredForSignup: { type: 'boolean' }, - enableHcaptcha: { type: 'boolean' }, - hcaptchaSiteKey: { type: 'string', nullable: true }, - hcaptchaSecretKey: { type: 'string', nullable: true }, - enableRecaptcha: { type: 'boolean' }, - recaptchaSiteKey: { type: 'string', nullable: true }, - recaptchaSecretKey: { type: 'string', nullable: true }, - sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] }, - sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] }, - setSensitiveFlagAutomatically: { type: 'boolean' }, - enableSensitiveMediaDetectionForVideos: { type: 'boolean' }, - proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true }, - maintainerName: { type: 'string', nullable: true }, - maintainerEmail: { type: 'string', nullable: true }, - pinnedPages: { type: 'array', items: { - type: 'string', - } }, - pinnedClipId: { type: 'string', format: 'misskey:id', nullable: true }, - langs: { type: 'array', items: { - type: 'string', - } }, - summalyProxy: { type: 'string', nullable: true }, - deeplAuthKey: { type: 'string', nullable: true }, - deeplIsPro: { type: 'boolean' }, - enableTwitterIntegration: { type: 'boolean' }, - twitterConsumerKey: { type: 'string', nullable: true }, - twitterConsumerSecret: { type: 'string', nullable: true }, - enableGithubIntegration: { type: 'boolean' }, - githubClientId: { type: 'string', nullable: true }, - githubClientSecret: { type: 'string', nullable: true }, - enableDiscordIntegration: { type: 'boolean' }, - discordClientId: { type: 'string', nullable: true }, - discordClientSecret: { type: 'string', nullable: true }, - enableEmail: { type: 'boolean' }, - email: { type: 'string', nullable: true }, - smtpSecure: { type: 'boolean' }, - smtpHost: { type: 'string', nullable: true }, - smtpPort: { type: 'integer', nullable: true }, - smtpUser: { type: 'string', nullable: true }, - smtpPass: { type: 'string', nullable: true }, - enableServiceWorker: { type: 'boolean' }, - swPublicKey: { type: 'string', nullable: true }, - swPrivateKey: { type: 'string', nullable: true }, - tosUrl: { type: 'string', nullable: true }, - repositoryUrl: { type: 'string' }, - feedbackUrl: { type: 'string' }, - useObjectStorage: { type: 'boolean' }, - objectStorageBaseUrl: { type: 'string', nullable: true }, - objectStorageBucket: { type: 'string', nullable: true }, - objectStoragePrefix: { type: 'string', nullable: true }, - objectStorageEndpoint: { type: 'string', nullable: true }, - objectStorageRegion: { type: 'string', nullable: true }, - objectStoragePort: { type: 'integer', nullable: true }, - objectStorageAccessKey: { type: 'string', nullable: true }, - objectStorageSecretKey: { type: 'string', nullable: true }, - objectStorageUseSSL: { type: 'boolean' }, - objectStorageUseProxy: { type: 'boolean' }, - objectStorageSetPublicRead: { type: 'boolean' }, - objectStorageS3ForcePathStyle: { type: 'boolean' }, - enableIpLogging: { type: 'boolean' }, - enableActiveEmailValidation: { type: 'boolean' }, + disableRegistration: { type: "boolean", nullable: true }, + disableLocalTimeline: { type: "boolean", nullable: true }, + disableRecommendedTimeline: { type: "boolean", nullable: true }, + disableGlobalTimeline: { type: "boolean", nullable: true }, + defaultReaction: { type: "string", nullable: true }, + recommendedInstances: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + pinnedUsers: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + customMOTD: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + customSplashIcons: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + hiddenTags: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + blockedHosts: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + allowedHosts: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, + secureMode: { type: "boolean", nullable: true }, + privateMode: { type: "boolean", nullable: true }, + themeColor: { + type: "string", + nullable: true, + pattern: "^#[0-9a-fA-F]{6}$", + }, + mascotImageUrl: { type: "string", nullable: true }, + bannerUrl: { type: "string", nullable: true }, + logoImageUrl: { type: "string", nullable: true }, + errorImageUrl: { type: "string", nullable: true }, + iconUrl: { type: "string", nullable: true }, + backgroundImageUrl: { type: "string", nullable: true }, + name: { type: "string", nullable: true }, + description: { type: "string", nullable: true }, + defaultLightTheme: { type: "string", nullable: true }, + defaultDarkTheme: { type: "string", nullable: true }, + localDriveCapacityMb: { type: "integer" }, + remoteDriveCapacityMb: { type: "integer" }, + cacheRemoteFiles: { type: "boolean" }, + emailRequiredForSignup: { type: "boolean" }, + enableHcaptcha: { type: "boolean" }, + hcaptchaSiteKey: { type: "string", nullable: true }, + hcaptchaSecretKey: { type: "string", nullable: true }, + enableRecaptcha: { type: "boolean" }, + recaptchaSiteKey: { type: "string", nullable: true }, + recaptchaSecretKey: { type: "string", nullable: true }, + sensitiveMediaDetection: { + type: "string", + enum: ["none", "all", "local", "remote"], + }, + sensitiveMediaDetectionSensitivity: { + type: "string", + enum: ["medium", "low", "high", "veryLow", "veryHigh"], + }, + setSensitiveFlagAutomatically: { type: "boolean" }, + enableSensitiveMediaDetectionForVideos: { type: "boolean" }, + proxyAccountId: { type: "string", format: "misskey:id", nullable: true }, + maintainerName: { type: "string", nullable: true }, + maintainerEmail: { type: "string", nullable: true }, + pinnedPages: { + type: "array", + items: { + type: "string", + }, + }, + pinnedClipId: { type: "string", format: "misskey:id", nullable: true }, + langs: { + type: "array", + items: { + type: "string", + }, + }, + summalyProxy: { type: "string", nullable: true }, + deeplAuthKey: { type: "string", nullable: true }, + deeplIsPro: { type: "boolean" }, + enableTwitterIntegration: { type: "boolean" }, + twitterConsumerKey: { type: "string", nullable: true }, + twitterConsumerSecret: { type: "string", nullable: true }, + enableGithubIntegration: { type: "boolean" }, + githubClientId: { type: "string", nullable: true }, + githubClientSecret: { type: "string", nullable: true }, + enableDiscordIntegration: { type: "boolean" }, + discordClientId: { type: "string", nullable: true }, + discordClientSecret: { type: "string", nullable: true }, + enableEmail: { type: "boolean" }, + email: { type: "string", nullable: true }, + smtpSecure: { type: "boolean" }, + smtpHost: { type: "string", nullable: true }, + smtpPort: { type: "integer", nullable: true }, + smtpUser: { type: "string", nullable: true }, + smtpPass: { type: "string", nullable: true }, + enableServiceWorker: { type: "boolean" }, + swPublicKey: { type: "string", nullable: true }, + swPrivateKey: { type: "string", nullable: true }, + tosUrl: { type: "string", nullable: true }, + repositoryUrl: { type: "string" }, + feedbackUrl: { type: "string" }, + useObjectStorage: { type: "boolean" }, + objectStorageBaseUrl: { type: "string", nullable: true }, + objectStorageBucket: { type: "string", nullable: true }, + objectStoragePrefix: { type: "string", nullable: true }, + objectStorageEndpoint: { type: "string", nullable: true }, + objectStorageRegion: { type: "string", nullable: true }, + objectStoragePort: { type: "integer", nullable: true }, + objectStorageAccessKey: { type: "string", nullable: true }, + objectStorageSecretKey: { type: "string", nullable: true }, + objectStorageUseSSL: { type: "boolean" }, + objectStorageUseProxy: { type: "boolean" }, + objectStorageSetPublicRead: { type: "boolean" }, + objectStorageS3ForcePathStyle: { type: "boolean" }, + enableIpLogging: { type: "boolean" }, + enableActiveEmailValidation: { type: "boolean" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const set = {} as Partial; - if (typeof ps.disableRegistration === 'boolean') { + if (typeof ps.disableRegistration === "boolean") { set.disableRegistration = ps.disableRegistration; } - if (typeof ps.disableLocalTimeline === 'boolean') { + if (typeof ps.disableLocalTimeline === "boolean") { set.disableLocalTimeline = ps.disableLocalTimeline; } - if (typeof ps.disableRecommendedTimeline === 'boolean') { + if (typeof ps.disableRecommendedTimeline === "boolean") { set.disableRecommendedTimeline = ps.disableRecommendedTimeline; } - if (typeof ps.disableGlobalTimeline === 'boolean') { + if (typeof ps.disableGlobalTimeline === "boolean") { set.disableGlobalTimeline = ps.disableGlobalTimeline; } - if (typeof ps.useStarForReactionFallback === 'boolean') { - set.useStarForReactionFallback = ps.useStarForReactionFallback; + if (typeof ps.defaultReaction === "string") { + set.defaultReaction = ps.defaultReaction; } if (Array.isArray(ps.pinnedUsers)) { @@ -177,11 +220,11 @@ export default define(meta, paramDef, async (ps, me) => { set.allowedHosts = ps.allowedHosts.filter(Boolean); } - if (typeof ps.privateMode === 'boolean') { + if (typeof ps.privateMode === "boolean") { set.privateMode = ps.privateMode; } - if (typeof ps.secureMode === 'boolean') { + if (typeof ps.secureMode === "boolean") { set.secureMode = ps.secureMode; } @@ -270,7 +313,8 @@ export default define(meta, paramDef, async (ps, me) => { } if (ps.sensitiveMediaDetectionSensitivity !== undefined) { - set.sensitiveMediaDetectionSensitivity = ps.sensitiveMediaDetectionSensitivity; + set.sensitiveMediaDetectionSensitivity = + ps.sensitiveMediaDetectionSensitivity; } if (ps.setSensitiveFlagAutomatically !== undefined) { @@ -278,7 +322,8 @@ export default define(meta, paramDef, async (ps, me) => { } if (ps.enableSensitiveMediaDetectionForVideos !== undefined) { - set.enableSensitiveMediaDetectionForVideos = ps.enableSensitiveMediaDetectionForVideos; + set.enableSensitiveMediaDetectionForVideos = + ps.enableSensitiveMediaDetectionForVideos; } if (ps.proxyAccountId !== undefined) { @@ -454,7 +499,7 @@ export default define(meta, paramDef, async (ps, me) => { } if (ps.deeplAuthKey !== undefined) { - if (ps.deeplAuthKey === '') { + if (ps.deeplAuthKey === "") { set.deeplAuthKey = null; } else { set.deeplAuthKey = ps.deeplAuthKey; @@ -473,10 +518,10 @@ export default define(meta, paramDef, async (ps, me) => { set.enableActiveEmailValidation = ps.enableActiveEmailValidation; } - await db.transaction(async transactionalEntityManager => { + await db.transaction(async (transactionalEntityManager) => { const metas = await transactionalEntityManager.find(Meta, { order: { - id: 'DESC', + id: "DESC", }, }); @@ -489,5 +534,5 @@ export default define(meta, paramDef, async (ps, me) => { } }); - insertModerationLog(me, 'updateMeta'); + insertModerationLog(me, "updateMeta"); }); diff --git a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts index fa21ab783..04870d1c1 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts @@ -1,31 +1,33 @@ -import { UserProfiles, Users } from '@/models/index.js'; -import define from '../../define.js'; +import { UserProfiles, Users } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - text: { type: 'string' }, + userId: { type: "string", format: "misskey:id" }, + text: { type: "string" }, }, - required: ['userId', 'text'], + required: ["userId", "text"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { - throw new Error('user not found'); + throw new Error("user not found"); } - await UserProfiles.update({ userId: user.id }, { - moderationNote: ps.text, - }); + await UserProfiles.update( + { userId: user.id }, + { + moderationNote: ps.text, + }, + ); }); diff --git a/packages/backend/src/server/api/endpoints/admin/vacuum.ts b/packages/backend/src/server/api/endpoints/admin/vacuum.ts index 0546acfac..559b310e4 100644 --- a/packages/backend/src/server/api/endpoints/admin/vacuum.ts +++ b/packages/backend/src/server/api/endpoints/admin/vacuum.ts @@ -1,36 +1,35 @@ -import define from '../../define.js'; -import { insertModerationLog } from '@/services/insert-moderation-log.js'; -import { db } from '@/db/postgre.js'; +import define from "../../define.js"; +import { insertModerationLog } from "@/services/insert-moderation-log.js"; +import { db } from "@/db/postgre.js"; export const meta = { - tags: ['admin'], + tags: ["admin"], requireCredential: true, requireModerator: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - full: { type: 'boolean' }, - analyze: { type: 'boolean' }, + full: { type: "boolean" }, + analyze: { type: "boolean" }, }, - required: ['full', 'analyze'], + required: ["full", "analyze"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const params: string[] = []; if (ps.full) { - params.push('FULL'); + params.push("FULL"); } if (ps.analyze) { - params.push('ANALYZE'); + params.push("ANALYZE"); } - db.query('VACUUM ' + params.join(' ')); + db.query(`VACUUM ${params.join(" ")}`); - insertModerationLog(me, 'vacuum', ps); + insertModerationLog(me, "vacuum", ps); }); diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index 189de042b..00634cc42 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -1,51 +1,60 @@ -import { Announcements, AnnouncementReads } from '@/models/index.js'; -import define from '../define.js'; -import { makePaginationQuery } from '../common/make-pagination-query.js'; +import { Announcements, AnnouncementReads } from "@/models/index.js"; +import define from "../define.js"; +import { makePaginationQuery } from "../common/make-pagination-query.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', + type: "string", + optional: false, + nullable: false, + format: "id", + example: "xxxxxxxxxx", }, createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', + type: "string", + optional: false, + nullable: false, + format: "date-time", }, updatedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', + type: "string", + optional: false, + nullable: true, + format: "date-time", }, text: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, title: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, imageUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, isRead: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, }, }, }, @@ -53,33 +62,40 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - withUnreads: { type: 'boolean', default: false }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + withUnreads: { type: "boolean", default: false }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + Announcements.createQueryBuilder("announcement"), + ps.sinceId, + ps.untilId, + ); const announcements = await query.take(ps.limit).getMany(); if (user) { - const reads = (await AnnouncementReads.findBy({ - userId: user.id, - })).map(x => x.announcementId); + const reads = ( + await AnnouncementReads.findBy({ + userId: user.id, + }) + ).map((x) => x.announcementId); for (const announcement of announcements) { (announcement as any).isRead = reads.includes(announcement.id); } } - return (ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements).map((a) => ({ + return ( + ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements + ).map((a) => ({ ...a, createdAt: a.createdAt.toISOString(), updatedAt: a.updatedAt?.toISOString() ?? null, diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index ae85c44cf..171fc2c64 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -1,72 +1,93 @@ -import define from '../../define.js'; -import { genId } from '@/misc/gen-id.js'; -import { Antennas, UserLists, UserGroupJoinings } from '@/models/index.js'; -import { ApiError } from '../../error.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { genId } from "@/misc/gen-id.js"; +import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js"; +import { ApiError } from "../../error.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['antennas'], + tags: ["antennas"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchUserList: { - message: 'No such user list.', - code: 'NO_SUCH_USER_LIST', - id: '95063e93-a283-4b8b-9aa5-bcdb8df69a7f', + message: "No such user list.", + code: "NO_SUCH_USER_LIST", + id: "95063e93-a283-4b8b-9aa5-bcdb8df69a7f", }, noSuchUserGroup: { - message: 'No such user group.', - code: 'NO_SUCH_USER_GROUP', - id: 'aa3c0b9a-8cae-47c0-92ac-202ce5906682', + message: "No such user group.", + code: "NO_SUCH_USER_GROUP", + id: "aa3c0b9a-8cae-47c0-92ac-202ce5906682", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Antenna', + type: "object", + optional: false, + nullable: false, + ref: "Antenna", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 100 }, - src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] }, - userListId: { type: 'string', format: 'misskey:id', nullable: true }, - userGroupId: { type: 'string', format: 'misskey:id', nullable: true }, - keywords: { type: 'array', items: { - type: 'array', items: { - type: 'string', + name: { type: "string", minLength: 1, maxLength: 100 }, + src: { type: "string", enum: ["home", "all", "users", "list", "group"] }, + userListId: { type: "string", format: "misskey:id", nullable: true }, + userGroupId: { type: "string", format: "misskey:id", nullable: true }, + keywords: { + type: "array", + items: { + type: "array", + items: { + type: "string", + }, }, - } }, - excludeKeywords: { type: 'array', items: { - type: 'array', items: { - type: 'string', + }, + excludeKeywords: { + type: "array", + items: { + type: "array", + items: { + type: "string", + }, }, - } }, - users: { type: 'array', items: { - type: 'string', - } }, - caseSensitive: { type: 'boolean' }, - withReplies: { type: 'boolean' }, - withFile: { type: 'boolean' }, - notify: { type: 'boolean' }, + }, + users: { + type: "array", + items: { + type: "string", + }, + }, + caseSensitive: { type: "boolean" }, + withReplies: { type: "boolean" }, + withFile: { type: "boolean" }, + notify: { type: "boolean" }, }, - required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'], + required: [ + "name", + "src", + "keywords", + "excludeKeywords", + "users", + "caseSensitive", + "withReplies", + "withFile", + "notify", + ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if(user.movedToUri != null) throw new ApiError(meta.errors.noSuchUserGroup); + if (user.movedToUri != null) throw new ApiError(meta.errors.noSuchUserGroup); let userList; let userGroupJoining; - if (ps.src === 'list' && ps.userListId) { + if (ps.src === "list" && ps.userListId) { userList = await UserLists.findOneBy({ id: ps.userListId, userId: user.id, @@ -75,7 +96,7 @@ export default define(meta, paramDef, async (ps, user) => { if (userList == null) { throw new ApiError(meta.errors.noSuchUserList); } - } else if (ps.src === 'group' && ps.userGroupId) { + } else if (ps.src === "group" && ps.userGroupId) { userGroupJoining = await UserGroupJoinings.findOneBy({ userGroupId: ps.userGroupId, userId: user.id, @@ -101,9 +122,9 @@ export default define(meta, paramDef, async (ps, user) => { withReplies: ps.withReplies, withFile: ps.withFile, notify: ps.notify, - }).then(x => Antennas.findOneByOrFail(x.identifiers[0])); + }).then((x) => Antennas.findOneByOrFail(x.identifiers[0])); - publishInternalEvent('antennaCreated', antenna); + publishInternalEvent("antennaCreated", antenna); return await Antennas.pack(antenna); }); diff --git a/packages/backend/src/server/api/endpoints/antennas/delete.ts b/packages/backend/src/server/api/endpoints/antennas/delete.ts index ced34ba31..a6cf79011 100644 --- a/packages/backend/src/server/api/endpoints/antennas/delete.ts +++ b/packages/backend/src/server/api/endpoints/antennas/delete.ts @@ -1,33 +1,32 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Antennas } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Antennas } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['antennas'], + tags: ["antennas"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchAntenna: { - message: 'No such antenna.', - code: 'NO_SUCH_ANTENNA', - id: 'b34dcf9d-348f-44bb-99d0-6c9314cfe2df', + message: "No such antenna.", + code: "NO_SUCH_ANTENNA", + id: "b34dcf9d-348f-44bb-99d0-6c9314cfe2df", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - antennaId: { type: 'string', format: 'misskey:id' }, + antennaId: { type: "string", format: "misskey:id" }, }, - required: ['antennaId'], + required: ["antennaId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const antenna = await Antennas.findOneBy({ id: ps.antennaId, @@ -40,5 +39,5 @@ export default define(meta, paramDef, async (ps, user) => { await Antennas.delete(antenna.id); - publishInternalEvent('antennaDeleted', antenna); + publishInternalEvent("antennaDeleted", antenna); }); diff --git a/packages/backend/src/server/api/endpoints/antennas/list.ts b/packages/backend/src/server/api/endpoints/antennas/list.ts index c519b452e..929b761d4 100644 --- a/packages/backend/src/server/api/endpoints/antennas/list.ts +++ b/packages/backend/src/server/api/endpoints/antennas/list.ts @@ -1,35 +1,36 @@ -import define from '../../define.js'; -import { Antennas } from '@/models/index.js'; +import define from "../../define.js"; +import { Antennas } from "@/models/index.js"; export const meta = { - tags: ['antennas', 'account'], + tags: ["antennas", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Antenna', + type: "object", + optional: false, + nullable: false, + ref: "Antenna", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const antennas = await Antennas.findBy({ userId: me.id, }); - return await Promise.all(antennas.map(x => Antennas.pack(x))); + return await Promise.all(antennas.map((x) => Antennas.pack(x))); }); diff --git a/packages/backend/src/server/api/endpoints/antennas/markread.ts b/packages/backend/src/server/api/endpoints/antennas/markread.ts new file mode 100644 index 000000000..e29e13bbb --- /dev/null +++ b/packages/backend/src/server/api/endpoints/antennas/markread.ts @@ -0,0 +1,43 @@ +import define from "../../define.js"; +import { Antennas, AntennaNotes } from "@/models/index.js"; +import { FindOptionsWhere } from "typeorm"; +import { AntennaNote } from "@/models/entities/antenna-note.js"; + +export const meta = { + tags: ["antennas", "account"], + + requireCredential: true, + + kind: "write:account", +} as const; + +export const paramDef = { + type: "object", + properties: { + antennaId: { type: "string", format: "misskey:id" }, + }, + required: ["antennaId"], +} as const; + +export default define(meta, paramDef, async (ps, me) => { + const antenna = await Antennas.findOneBy({ + userId: me.id, + id: ps.antennaId, + }); + + if (!antenna) { + return null; + } + + await AntennaNotes.update( + { + antennaId: antenna.id, + read: false, + }, + { + read: true, + }, + ); + + return true; +}); diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 8aac55b4a..d011c5fb8 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -1,52 +1,53 @@ -import define from '../../define.js'; -import readNote from '@/services/note/read.js'; -import { Antennas, Notes, AntennaNotes } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { ApiError } from '../../error.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import define from "../../define.js"; +import readNote from "@/services/note/read.js"; +import { Antennas, Notes, AntennaNotes } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { ApiError } from "../../error.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['antennas', 'account', 'notes'], + tags: ["antennas", "account", "notes"], requireCredential: true, - kind: 'read:account', + kind: "read:account", errors: { noSuchAntenna: { - message: 'No such antenna.', - code: 'NO_SUCH_ANTENNA', - id: '850926e0-fd3b-49b6-b69a-b28a5dbd82fe', + message: "No such antenna.", + code: "NO_SUCH_ANTENNA", + id: "850926e0-fd3b-49b6-b69a-b28a5dbd82fe", }, }, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - antennaId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + antennaId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, - required: ['antennaId'], + required: ["antennaId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const antenna = await Antennas.findOneBy({ id: ps.antennaId, @@ -57,29 +58,36 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchAntenna); } - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .innerJoin(AntennaNotes.metadata.targetName, 'antennaNote', 'antennaNote.noteId = note.id') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .andWhere('antennaNote.antennaId = :antennaId', { antennaId: antenna.id }); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .innerJoin( + AntennaNotes.metadata.targetName, + "antennaNote", + "antennaNote.noteId = note.id", + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") + .andWhere("antennaNote.antennaId = :antennaId", { antennaId: antenna.id }); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); generateBlockedUserQuery(query, user); - const notes = await query - .take(ps.limit) - .getMany(); + const notes = await query.take(ps.limit).getMany(); if (notes.length > 0) { readNote(user.id, notes); diff --git a/packages/backend/src/server/api/endpoints/antennas/show.ts b/packages/backend/src/server/api/endpoints/antennas/show.ts index dd693789c..350d73921 100644 --- a/packages/backend/src/server/api/endpoints/antennas/show.ts +++ b/packages/backend/src/server/api/endpoints/antennas/show.ts @@ -1,38 +1,38 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Antennas } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Antennas } from "@/models/index.js"; export const meta = { - tags: ['antennas', 'account'], + tags: ["antennas", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", errors: { noSuchAntenna: { - message: 'No such antenna.', - code: 'NO_SUCH_ANTENNA', - id: 'c06569fb-b025-4f23-b22d-1fcd20d2816b', + message: "No such antenna.", + code: "NO_SUCH_ANTENNA", + id: "c06569fb-b025-4f23-b22d-1fcd20d2816b", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Antenna', + type: "object", + optional: false, + nullable: false, + ref: "Antenna", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - antennaId: { type: 'string', format: 'misskey:id' }, + antennaId: { type: "string", format: "misskey:id" }, }, - required: ['antennaId'], + required: ["antennaId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the antenna const antenna = await Antennas.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts index edfedc175..6c48cd369 100644 --- a/packages/backend/src/server/api/endpoints/antennas/update.ts +++ b/packages/backend/src/server/api/endpoints/antennas/update.ts @@ -1,72 +1,94 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Antennas, UserLists, UserGroupJoinings } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['antennas'], + tags: ["antennas"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchAntenna: { - message: 'No such antenna.', - code: 'NO_SUCH_ANTENNA', - id: '10c673ac-8852-48eb-aa1f-f5b67f069290', + message: "No such antenna.", + code: "NO_SUCH_ANTENNA", + id: "10c673ac-8852-48eb-aa1f-f5b67f069290", }, noSuchUserList: { - message: 'No such user list.', - code: 'NO_SUCH_USER_LIST', - id: '1c6b35c9-943e-48c2-81e4-2844989407f7', + message: "No such user list.", + code: "NO_SUCH_USER_LIST", + id: "1c6b35c9-943e-48c2-81e4-2844989407f7", }, noSuchUserGroup: { - message: 'No such user group.', - code: 'NO_SUCH_USER_GROUP', - id: '109ed789-b6eb-456e-b8a9-6059d567d385', + message: "No such user group.", + code: "NO_SUCH_USER_GROUP", + id: "109ed789-b6eb-456e-b8a9-6059d567d385", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Antenna', + type: "object", + optional: false, + nullable: false, + ref: "Antenna", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - antennaId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 100 }, - src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] }, - userListId: { type: 'string', format: 'misskey:id', nullable: true }, - userGroupId: { type: 'string', format: 'misskey:id', nullable: true }, - keywords: { type: 'array', items: { - type: 'array', items: { - type: 'string', + antennaId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 100 }, + src: { type: "string", enum: ["home", "all", "users", "list", "group"] }, + userListId: { type: "string", format: "misskey:id", nullable: true }, + userGroupId: { type: "string", format: "misskey:id", nullable: true }, + keywords: { + type: "array", + items: { + type: "array", + items: { + type: "string", + }, }, - } }, - excludeKeywords: { type: 'array', items: { - type: 'array', items: { - type: 'string', + }, + excludeKeywords: { + type: "array", + items: { + type: "array", + items: { + type: "string", + }, }, - } }, - users: { type: 'array', items: { - type: 'string', - } }, - caseSensitive: { type: 'boolean' }, - withReplies: { type: 'boolean' }, - withFile: { type: 'boolean' }, - notify: { type: 'boolean' }, + }, + users: { + type: "array", + items: { + type: "string", + }, + }, + caseSensitive: { type: "boolean" }, + withReplies: { type: "boolean" }, + withFile: { type: "boolean" }, + notify: { type: "boolean" }, }, - required: ['antennaId', 'name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'], + required: [ + "antennaId", + "name", + "src", + "keywords", + "excludeKeywords", + "users", + "caseSensitive", + "withReplies", + "withFile", + "notify", + ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the antenna const antenna = await Antennas.findOneBy({ @@ -81,7 +103,7 @@ export default define(meta, paramDef, async (ps, user) => { let userList; let userGroupJoining; - if (ps.src === 'list' && ps.userListId) { + if (ps.src === "list" && ps.userListId) { userList = await UserLists.findOneBy({ id: ps.userListId, userId: user.id, @@ -90,7 +112,7 @@ export default define(meta, paramDef, async (ps, user) => { if (userList == null) { throw new ApiError(meta.errors.noSuchUserList); } - } else if (ps.src === 'group' && ps.userGroupId) { + } else if (ps.src === "group" && ps.userGroupId) { userGroupJoining = await UserGroupJoinings.findOneBy({ userGroupId: ps.userGroupId, userId: user.id, @@ -115,7 +137,10 @@ export default define(meta, paramDef, async (ps, user) => { notify: ps.notify, }); - publishInternalEvent('antennaUpdated', await Antennas.findOneByOrFail({ id: antenna.id })); + publishInternalEvent( + "antennaUpdated", + await Antennas.findOneByOrFail({ id: antenna.id }), + ); return await Antennas.pack(antenna.id); }); diff --git a/packages/backend/src/server/api/endpoints/ap/get.ts b/packages/backend/src/server/api/endpoints/ap/get.ts index 559bc277f..f0db67a34 100644 --- a/packages/backend/src/server/api/endpoints/ap/get.ts +++ b/packages/backend/src/server/api/endpoints/ap/get.ts @@ -1,9 +1,9 @@ -import define from '../../define.js'; -import Resolver from '@/remote/activitypub/resolver.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import Resolver from "@/remote/activitypub/resolver.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, @@ -12,24 +12,23 @@ export const meta = { max: 30, }, - errors: { - }, + errors: {}, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - uri: { type: 'string' }, + uri: { type: "string" }, }, - required: ['uri'], + required: ["uri"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const resolver = new Resolver(); const object = await resolver.resolve(ps.uri); diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index b65f5d078..fa804802e 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -1,21 +1,22 @@ -import define from '../../define.js'; -import config from '@/config/index.js'; -import { createPerson } from '@/remote/activitypub/models/person.js'; -import { createNote } from '@/remote/activitypub/models/note.js'; -import DbResolver from '@/remote/activitypub/db-resolver.js'; -import Resolver from '@/remote/activitypub/resolver.js'; -import { ApiError } from '../../error.js'; -import { extractDbHost } from '@/misc/convert-host.js'; -import { Users, Notes } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { CacheableLocalUser, User } from '@/models/entities/user.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { isActor, isPost, getApId } from '@/remote/activitypub/type.js'; -import { SchemaType } from '@/misc/schema.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import config from "@/config/index.js"; +import { createPerson } from "@/remote/activitypub/models/person.js"; +import { createNote } from "@/remote/activitypub/models/note.js"; +import DbResolver from "@/remote/activitypub/db-resolver.js"; +import Resolver from "@/remote/activitypub/resolver.js"; +import { ApiError } from "../../error.js"; +import { extractDbHost } from "@/misc/convert-host.js"; +import { Users, Notes } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import type { CacheableLocalUser, User } from "@/models/entities/user.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { isActor, isPost, getApId } from "@/remote/activitypub/type.js"; +import type { SchemaType } from "@/misc/schema.js"; +import { HOUR } from "@/const.js"; +import { shouldBlockInstance } from "@/misc/should-block-instance.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, @@ -26,58 +27,62 @@ export const meta = { errors: { noSuchObject: { - message: 'No such object.', - code: 'NO_SUCH_OBJECT', - id: 'dc94d745-1262-4e63-a17d-fecaa57efc82', + message: "No such object.", + code: "NO_SUCH_OBJECT", + id: "dc94d745-1262-4e63-a17d-fecaa57efc82", }, }, res: { - optional: false, nullable: false, + optional: false, + nullable: false, oneOf: [ { - type: 'object', + type: "object", properties: { type: { - type: 'string', - optional: false, nullable: false, - enum: ['User'], + type: "string", + optional: false, + nullable: false, + enum: ["User"], }, object: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', - } - } + type: "object", + optional: false, + nullable: false, + ref: "UserDetailedNotMe", + }, + }, }, { - type: 'object', + type: "object", properties: { type: { - type: 'string', - optional: false, nullable: false, - enum: ['Note'], + type: "string", + optional: false, + nullable: false, + enum: ["Note"], }, object: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', - } - } - } + type: "object", + optional: false, + nullable: false, + ref: "Note", + }, + }, + }, ], }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - uri: { type: 'string' }, + uri: { type: "string" }, }, - required: ['uri'], + required: ["uri"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const object = await fetchAny(ps.uri, me); if (object) { @@ -90,30 +95,38 @@ export default define(meta, paramDef, async (ps, me) => { /*** * Resolve User or Note from URI */ -async function fetchAny(uri: string, me: CacheableLocalUser | null | undefined): Promise | null> { +async function fetchAny( + uri: string, + me: CacheableLocalUser | null | undefined, +): Promise | null> { // Wait if blocked. - const fetchedMeta = await fetchMeta(); - if (fetchedMeta.blockedHosts.includes(extractDbHost(uri))) return null; + if (await shouldBlockInstance(extractDbHost(uri))) return null; const dbResolver = new DbResolver(); - let local = await mergePack(me, ...await Promise.all([ - dbResolver.getUserFromApId(uri), - dbResolver.getNoteFromApId(uri), - ])); + let local = await mergePack( + me, + ...(await Promise.all([ + dbResolver.getUserFromApId(uri), + dbResolver.getNoteFromApId(uri), + ])), + ); if (local != null) return local; // fetching Object once from remote const resolver = new Resolver(); - const object = await resolver.resolve(uri) as any; + const object = (await resolver.resolve(uri)) as any; // /@user If a URI other than the id is specified, // the URI is determined here if (uri !== object.id) { - local = await mergePack(me, ...await Promise.all([ - dbResolver.getUserFromApId(object.id), - dbResolver.getNoteFromApId(object.id), - ])); + local = await mergePack( + me, + ...(await Promise.all([ + dbResolver.getUserFromApId(object.id), + dbResolver.getNoteFromApId(object.id), + ])), + ); if (local != null) return local; } @@ -124,10 +137,14 @@ async function fetchAny(uri: string, me: CacheableLocalUser | null | undefined): ); } -async function mergePack(me: CacheableLocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise | null> { +async function mergePack( + me: CacheableLocalUser | null | undefined, + user: User | null | undefined, + note: Note | null | undefined, +): Promise | null> { if (user != null) { return { - type: 'User', + type: "User", object: await Users.pack(user, me, { detail: true }), }; } else if (note != null) { @@ -135,7 +152,7 @@ async function mergePack(me: CacheableLocalUser | null | undefined, user: User | const object = await Notes.pack(note, me, { detail: true }); return { - type: 'Note', + type: "Note", object, }; } catch (e) { diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts index 15b2089e7..013c5a10b 100644 --- a/packages/backend/src/server/api/endpoints/app/create.ts +++ b/packages/backend/src/server/api/endpoints/app/create.ts @@ -1,45 +1,52 @@ -import define from '../../define.js'; -import { Apps } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { unique } from '@/prelude/array.js'; -import { secureRndstr } from '@/misc/secure-rndstr.js'; +import define from "../../define.js"; +import { Apps } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { unique } from "@/prelude/array.js"; +import { secureRndstr } from "@/misc/secure-rndstr.js"; export const meta = { - tags: ['app'], + tags: ["app"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, - ref: 'App', + type: "object", + optional: false, + nullable: false, + ref: "App", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string' }, - description: { type: 'string' }, - permission: { type: 'array', uniqueItems: true, items: { - type: 'string', - } }, - callbackUrl: { type: 'string', nullable: true }, + name: { type: "string" }, + description: { type: "string" }, + permission: { + type: "array", + uniqueItems: true, + items: { + type: "string", + }, + }, + callbackUrl: { type: "string", nullable: true }, }, - required: ['name', 'description', 'permission'], + required: ["name", "description", "permission"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if(user && user.movedToUri != null) return await Apps.pack("", null, { - detail: true, - includeSecret: true, - });; + if (user?.movedToUri != null) + return await Apps.pack("", null, { + detail: true, + includeSecret: true, + }); // Generate secret const secret = secureRndstr(32, true); // for backward compatibility - const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1'))); + const permission = unique( + ps.permission.map((v) => v.replace(/^(.+)(\/|-)(read|write)$/, "$3:$1")), + ); // Create account const app = await Apps.insert({ @@ -51,7 +58,7 @@ export default define(meta, paramDef, async (ps, user) => { permission, callbackUrl: ps.callbackUrl, secret: secret, - }).then(x => Apps.findOneByOrFail(x.identifiers[0])); + }).then((x) => Apps.findOneByOrFail(x.identifiers[0])); return await Apps.pack(app, null, { detail: true, diff --git a/packages/backend/src/server/api/endpoints/app/show.ts b/packages/backend/src/server/api/endpoints/app/show.ts index 451969d97..60949512e 100644 --- a/packages/backend/src/server/api/endpoints/app/show.ts +++ b/packages/backend/src/server/api/endpoints/app/show.ts @@ -1,34 +1,34 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Apps } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Apps } from "@/models/index.js"; export const meta = { - tags: ['app'], + tags: ["app"], errors: { noSuchApp: { - message: 'No such app.', - code: 'NO_SUCH_APP', - id: 'dce83913-2dc6-4093-8a7b-71dbb11718a3', + message: "No such app.", + code: "NO_SUCH_APP", + id: "dce83913-2dc6-4093-8a7b-71dbb11718a3", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'App', + type: "object", + optional: false, + nullable: false, + ref: "App", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - appId: { type: 'string', format: 'misskey:id' }, + appId: { type: "string", format: "misskey:id" }, }, - required: ['appId'], + required: ["appId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user, token) => { const isSecure = user != null && token == null; @@ -41,6 +41,6 @@ export default define(meta, paramDef, async (ps, user, token) => { return await Apps.pack(ap, user, { detail: true, - includeSecret: isSecure && (ap.userId === user!.id), + includeSecret: isSecure && ap.userId === user!.id, }); }); diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index b5c06792b..35565e256 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -1,12 +1,12 @@ -import * as crypto from 'node:crypto'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { AuthSessions, AccessTokens, Apps } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { secureRndstr } from '@/misc/secure-rndstr.js'; +import * as crypto from "node:crypto"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { AuthSessions, AccessTokens, Apps } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { secureRndstr } from "@/misc/secure-rndstr.js"; export const meta = { - tags: ['auth'], + tags: ["auth"], requireCredential: true, @@ -14,26 +14,24 @@ export const meta = { errors: { noSuchSession: { - message: 'No such session.', - code: 'NO_SUCH_SESSION', - id: '9c72d8de-391a-43c1-9d06-08d29efde8df', + message: "No such session.", + code: "NO_SUCH_SESSION", + id: "9c72d8de-391a-43c1-9d06-08d29efde8df", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - token: { type: 'string' }, + token: { type: "string" }, }, - required: ['token'], + required: ["token"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch token - const session = await AuthSessions - .findOneBy({ token: ps.token }); + const session = await AuthSessions.findOneBy({ token: ps.token }); if (session == null) { throw new ApiError(meta.errors.noSuchSession); @@ -53,9 +51,9 @@ export default define(meta, paramDef, async (ps, user) => { const app = await Apps.findOneByOrFail({ id: session.appId }); // Generate Hash - const sha256 = crypto.createHash('sha256'); + const sha256 = crypto.createHash("sha256"); sha256.update(accessToken + app.secret); - const hash = sha256.digest('hex'); + const hash = sha256.digest("hex"); const now = new Date(); diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts index 717c3e508..1defb9400 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts @@ -1,49 +1,51 @@ -import { v4 as uuid } from 'uuid'; -import config from '@/config/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { Apps, AuthSessions } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import { v4 as uuid } from "uuid"; +import config from "@/config/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { Apps, AuthSessions } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['auth'], + tags: ["auth"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { token: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, url: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, }, }, errors: { noSuchApp: { - message: 'No such app.', - code: 'NO_SUCH_APP', - id: '92f93e63-428e-4f2f-a5a4-39e1407fe998', + message: "No such app.", + code: "NO_SUCH_APP", + id: "92f93e63-428e-4f2f-a5a4-39e1407fe998", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - appSecret: { type: 'string' }, + appSecret: { type: "string" }, }, - required: ['appSecret'], + required: ["appSecret"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Lookup app const app = await Apps.findOneBy({ @@ -63,7 +65,7 @@ export default define(meta, paramDef, async (ps) => { createdAt: new Date(), appId: app.id, token: token, - }).then(x => AuthSessions.findOneByOrFail(x.identifiers[0])); + }).then((x) => AuthSessions.findOneByOrFail(x.identifiers[0])); return { token: doc.token, diff --git a/packages/backend/src/server/api/endpoints/auth/session/show.ts b/packages/backend/src/server/api/endpoints/auth/session/show.ts index 3f3a4d142..01a5fe5dc 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/show.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/show.ts @@ -1,51 +1,54 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { AuthSessions } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { AuthSessions } from "@/models/index.js"; export const meta = { - tags: ['auth'], + tags: ["auth"], requireCredential: false, errors: { noSuchSession: { - message: 'No such session.', - code: 'NO_SUCH_SESSION', - id: 'bd72c97d-eba7-4adb-a467-f171b8847250', + message: "No such session.", + code: "NO_SUCH_SESSION", + id: "bd72c97d-eba7-4adb-a467-f171b8847250", }, }, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, app: { - type: 'object', - optional: false, nullable: false, - ref: 'App', + type: "object", + optional: false, + nullable: false, + ref: "App", }, token: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - token: { type: 'string' }, + token: { type: "string" }, }, - required: ['token'], + required: ["token"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Lookup session const session = await AuthSessions.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts index 89884ed38..0e97bf414 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts @@ -1,60 +1,62 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { Apps, AuthSessions, AccessTokens, Users } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { Apps, AuthSessions, AccessTokens, Users } from "@/models/index.js"; export const meta = { - tags: ['auth'], + tags: ["auth"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { accessToken: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, user: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailedNotMe", }, }, }, errors: { noSuchApp: { - message: 'No such app.', - code: 'NO_SUCH_APP', - id: 'fcab192a-2c5a-43b7-8ad8-9b7054d8d40d', + message: "No such app.", + code: "NO_SUCH_APP", + id: "fcab192a-2c5a-43b7-8ad8-9b7054d8d40d", }, noSuchSession: { - message: 'No such session.', - code: 'NO_SUCH_SESSION', - id: '5b5a1503-8bc8-4bd0-8054-dc189e8cdcb3', + message: "No such session.", + code: "NO_SUCH_SESSION", + id: "5b5a1503-8bc8-4bd0-8054-dc189e8cdcb3", }, pendingSession: { - message: 'This session is not completed yet.', - code: 'PENDING_SESSION', - id: '8c8a4145-02cc-4cca-8e66-29ba60445a8e', + message: "This session is not completed yet.", + code: "PENDING_SESSION", + id: "8c8a4145-02cc-4cca-8e66-29ba60445a8e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - appSecret: { type: 'string' }, - token: { type: 'string' }, + appSecret: { type: "string" }, + token: { type: "string" }, }, - required: ['appSecret', 'token'], + required: ["appSecret", "token"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Lookup app const app = await Apps.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index 4e88f32fb..4bd58d5ef 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -1,12 +1,12 @@ -import create from '@/services/blocking/create.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Blockings, NoteWatchings, Users } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import create from "@/services/blocking/create.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Blockings, NoteWatchings, Users } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['account'], + tags: ["account"], limit: { duration: HOUR, @@ -15,44 +15,44 @@ export const meta = { requireCredential: true, - kind: 'write:blocks', + kind: "write:blocks", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '7cc4f851-e2f1-4621-9633-ec9e1d00c01e', + message: "No such user.", + code: "NO_SUCH_USER", + id: "7cc4f851-e2f1-4621-9633-ec9e1d00c01e", }, blockeeIsYourself: { - message: 'Blockee is yourself.', - code: 'BLOCKEE_IS_YOURSELF', - id: '88b19138-f28d-42c0-8499-6a31bbd0fdc6', + message: "Blockee is yourself.", + code: "BLOCKEE_IS_YOURSELF", + id: "88b19138-f28d-42c0-8499-6a31bbd0fdc6", }, alreadyBlocking: { - message: 'You are already blocking that user.', - code: 'ALREADY_BLOCKING', - id: '787fed64-acb9-464a-82eb-afbd745b9614', + message: "You are already blocking that user.", + code: "ALREADY_BLOCKING", + id: "787fed64-acb9-464a-82eb-afbd745b9614", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailedNotMe", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const blocker = await Users.findOneByOrFail({ id: user.id }); @@ -62,8 +62,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get blockee - const blockee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const blockee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts index 37215bbd6..6c4ca2775 100644 --- a/packages/backend/src/server/api/endpoints/blocking/delete.ts +++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts @@ -1,12 +1,12 @@ -import deleteBlocking from '@/services/blocking/delete.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Blockings, Users } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import deleteBlocking from "@/services/blocking/delete.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Blockings, Users } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['account'], + tags: ["account"], limit: { duration: HOUR, @@ -15,44 +15,44 @@ export const meta = { requireCredential: true, - kind: 'write:blocks', + kind: "write:blocks", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '8621d8bf-c358-4303-a066-5ea78610eb3f', + message: "No such user.", + code: "NO_SUCH_USER", + id: "8621d8bf-c358-4303-a066-5ea78610eb3f", }, blockeeIsYourself: { - message: 'Blockee is yourself.', - code: 'BLOCKEE_IS_YOURSELF', - id: '06f6fac6-524b-473c-a354-e97a40ae6eac', + message: "Blockee is yourself.", + code: "BLOCKEE_IS_YOURSELF", + id: "06f6fac6-524b-473c-a354-e97a40ae6eac", }, notBlocking: { - message: 'You are not blocking that user.', - code: 'NOT_BLOCKING', - id: '291b2efa-60c6-45c0-9f6a-045c8f9b02cd', + message: "You are not blocking that user.", + code: "NOT_BLOCKING", + id: "291b2efa-60c6-45c0-9f6a-045c8f9b02cd", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailedNotMe", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const blocker = await Users.findOneByOrFail({ id: user.id }); @@ -62,8 +62,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get blockee - const blockee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const blockee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/blocking/list.ts b/packages/backend/src/server/api/endpoints/blocking/list.ts index 29095ebe2..83fca7b42 100644 --- a/packages/backend/src/server/api/endpoints/blocking/list.ts +++ b/packages/backend/src/server/api/endpoints/blocking/list.ts @@ -1,43 +1,45 @@ -import define from '../../define.js'; -import { Blockings } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Blockings } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'read:blocks', + kind: "read:blocks", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Blocking', + type: "object", + optional: false, + nullable: false, + ref: "Blocking", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 30 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Blockings.createQueryBuilder('blocking'), ps.sinceId, ps.untilId) - .andWhere(`blocking.blockerId = :meId`, { meId: me.id }); + const query = makePaginationQuery( + Blockings.createQueryBuilder("blocking"), + ps.sinceId, + ps.untilId, + ).andWhere("blocking.blockerId = :meId", { meId: me.id }); - const blockings = await query - .take(ps.limit) - .getMany(); + const blockings = await query.take(ps.limit).getMany(); return await Blockings.packMany(blockings, me); }); diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 94dcfe502..26a3448b2 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -1,42 +1,47 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Channels, DriveFiles } from '@/models/index.js'; -import { Channel } from '@/models/entities/channel.js'; -import { genId } from '@/misc/gen-id.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Channels, DriveFiles } from "@/models/index.js"; +import type { Channel } from "@/models/entities/channel.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: true, - kind: 'write:channels', + kind: "write:channels", res: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'cd1e9f3e-5a12-4ab4-96f6-5d0a2cc32050', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "cd1e9f3e-5a12-4ab4-96f6-5d0a2cc32050", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 128 }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, - bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + name: { type: "string", minLength: 1, maxLength: 128 }, + description: { + type: "string", + nullable: true, + minLength: 1, + maxLength: 2048, + }, + bannerId: { type: "string", format: "misskey:id", nullable: true }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { let banner = null; if (ps.bannerId != null) { @@ -57,7 +62,7 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, description: ps.description || null, bannerId: banner ? banner.id : null, - } as Channel).then(x => Channels.findOneByOrFail(x.identifiers[0])); + } as Channel).then((x) => Channels.findOneByOrFail(x.identifiers[0])); return await Channels.pack(channel, user); }); diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts index 13ad6ca7d..06e0e850f 100644 --- a/packages/backend/src/server/api/endpoints/channels/featured.ts +++ b/packages/backend/src/server/api/endpoints/channels/featured.ts @@ -1,36 +1,37 @@ -import define from '../../define.js'; -import { Channels } from '@/models/index.js'; +import define from "../../define.js"; +import { Channels } from "@/models/index.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Channels.createQueryBuilder('channel') - .where('channel.lastNotedAt IS NOT NULL') - .orderBy('channel.lastNotedAt', 'DESC'); + const query = Channels.createQueryBuilder("channel") + .where("channel.lastNotedAt IS NOT NULL") + .orderBy("channel.lastNotedAt", "DESC"); const channels = await query.take(10).getMany(); - return await Promise.all(channels.map(x => Channels.pack(x, me))); + return await Promise.all(channels.map((x) => Channels.pack(x, me))); }); diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index 895ffed0b..de0554383 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -1,34 +1,33 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Channels, ChannelFollowings } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: true, - kind: 'write:channels', + kind: "write:channels", errors: { noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: 'c0031718-d573-4e85-928e-10039f1fbb68', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "c0031718-d573-4e85-928e-10039f1fbb68", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - channelId: { type: 'string', format: 'misskey:id' }, + channelId: { type: "string", format: "misskey:id" }, }, - required: ['channelId'], + required: ["channelId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOneBy({ id: ps.channelId, @@ -45,5 +44,5 @@ export default define(meta, paramDef, async (ps, user) => { followeeId: channel.id, }); - publishUserEvent(user.id, 'followChannel', channel); + publishUserEvent(user.id, "followChannel", channel); }); diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts index e4aa4d161..63483a79a 100644 --- a/packages/backend/src/server/api/endpoints/channels/followed.ts +++ b/packages/backend/src/server/api/endpoints/channels/followed.ts @@ -1,43 +1,47 @@ -import define from '../../define.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Channels, ChannelFollowings } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['channels', 'account'], + tags: ["channels", "account"], requireCredential: true, - kind: 'read:channels', + kind: "read:channels", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 5 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(ChannelFollowings.createQueryBuilder(), ps.sinceId, ps.untilId) - .andWhere({ followerId: me.id }); + const query = makePaginationQuery( + ChannelFollowings.createQueryBuilder(), + ps.sinceId, + ps.untilId, + ).andWhere({ followerId: me.id }); - const followings = await query - .take(ps.limit) - .getMany(); + const followings = await query.take(ps.limit).getMany(); - return await Promise.all(followings.map(x => Channels.pack(x.followeeId, me))); + return await Promise.all( + followings.map((x) => Channels.pack(x.followeeId, me)), + ); }); diff --git a/packages/backend/src/server/api/endpoints/channels/owned.ts b/packages/backend/src/server/api/endpoints/channels/owned.ts index ed7e41cac..78d9e80cc 100644 --- a/packages/backend/src/server/api/endpoints/channels/owned.ts +++ b/packages/backend/src/server/api/endpoints/channels/owned.ts @@ -1,43 +1,45 @@ -import define from '../../define.js'; -import { Channels } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Channels } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['channels', 'account'], + tags: ["channels", "account"], requireCredential: true, - kind: 'read:channels', + kind: "read:channels", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 5 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Channels.createQueryBuilder(), ps.sinceId, ps.untilId) - .andWhere({ userId: me.id }); + const query = makePaginationQuery( + Channels.createQueryBuilder(), + ps.sinceId, + ps.untilId, + ).andWhere({ userId: me.id }); - const channels = await query - .take(ps.limit) - .getMany(); + const channels = await query.take(ps.limit).getMany(); - return await Promise.all(channels.map(x => Channels.pack(x, me))); + return await Promise.all(channels.map((x) => Channels.pack(x, me))); }); diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index 1c8461af4..e4ca75663 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -1,37 +1,37 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Channels } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Channels } from "@/models/index.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, errors: { noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: '6f6c314b-7486-4897-8966-c04a66a02923', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "6f6c314b-7486-4897-8966-c04a66a02923", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - channelId: { type: 'string', format: 'misskey:id' }, + channelId: { type: "string", format: "misskey:id" }, }, - required: ['channelId'], + required: ["channelId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const channel = await Channels.findOneBy({ id: ps.channelId, diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 18ba6b2e3..b5d532523 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -1,48 +1,49 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Notes, Channels } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { activeUsersChart } from '@/services/chart/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Notes, Channels } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { activeUsersChart } from "@/services/chart/index.js"; export const meta = { - tags: ['notes', 'channels'], + tags: ["notes", "channels"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: '4d0eeeba-a02c-4c3c-9966-ef60d38d2e7f', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "4d0eeeba-a02c-4c3c-9966-ef60d38d2e7f", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - channelId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + channelId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, - required: ['channelId'], + required: ["channelId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOneBy({ id: ps.channelId, @@ -53,20 +54,26 @@ export default define(meta, paramDef, async (ps, user) => { } //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('note.channelId = :channelId', { channelId: channel.id }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .leftJoinAndSelect('note.channel', 'channel'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere("note.channelId = :channelId", { channelId: channel.id }) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") + .leftJoinAndSelect("note.channel", "channel"); //#endregion const timeline = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/channels/unfollow.ts b/packages/backend/src/server/api/endpoints/channels/unfollow.ts index e065d897a..654a4fbba 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfollow.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfollow.ts @@ -1,33 +1,32 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Channels, ChannelFollowings } from "@/models/index.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: true, - kind: 'write:channels', + kind: "write:channels", errors: { noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: '19959ee9-0153-4c51-bbd9-a98c49dc59d6', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "19959ee9-0153-4c51-bbd9-a98c49dc59d6", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - channelId: { type: 'string', format: 'misskey:id' }, + channelId: { type: "string", format: "misskey:id" }, }, - required: ['channelId'], + required: ["channelId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOneBy({ id: ps.channelId, @@ -42,5 +41,5 @@ export default define(meta, paramDef, async (ps, user) => { followeeId: channel.id, }); - publishUserEvent(user.id, 'unfollowChannel', channel); + publishUserEvent(user.id, "unfollowChannel", channel); }); diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 13104f324..d9f6f7644 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -1,53 +1,58 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Channels, DriveFiles } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Channels, DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['channels'], + tags: ["channels"], requireCredential: true, - kind: 'write:channels', + kind: "write:channels", res: { - type: 'object', - optional: false, nullable: false, - ref: 'Channel', + type: "object", + optional: false, + nullable: false, + ref: "Channel", }, errors: { noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: 'f9c5467f-d492-4c3c-9a8d-a70dacc86512', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "f9c5467f-d492-4c3c-9a8d-a70dacc86512", }, accessDenied: { - message: 'You do not have edit privilege of the channel.', - code: 'ACCESS_DENIED', - id: '1fb7cb09-d46a-4fdf-b8df-057788cce513', + message: "You do not have edit privilege of the channel.", + code: "ACCESS_DENIED", + id: "1fb7cb09-d46a-4fdf-b8df-057788cce513", }, noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'e86c14a4-0da2-4032-8df3-e737a04c7f3b', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "e86c14a4-0da2-4032-8df3-e737a04c7f3b", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - channelId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 128 }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, - bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + channelId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 128 }, + description: { + type: "string", + nullable: true, + minLength: 1, + maxLength: 2048, + }, + bannerId: { type: "string", format: "misskey:id", nullable: true }, }, - required: ['channelId'], + required: ["channelId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const channel = await Channels.findOneBy({ id: ps.channelId, @@ -61,7 +66,6 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.accessDenied); } - // eslint:disable-next-line:no-unnecessary-initializer let banner = undefined; if (ps.bannerId != null) { banner = await DriveFiles.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/charts/active-users.ts b/packages/backend/src/server/api/endpoints/charts/active-users.ts index 216676020..3817a32ca 100644 --- a/packages/backend/src/server/api/endpoints/charts/active-users.ts +++ b/packages/backend/src/server/api/endpoints/charts/active-users.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts', 'users'], + tags: ["charts", "users"], requireCredentialPrivateMode: true, res: getJsonSchema(activeUsersChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await activeUsersChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await activeUsersChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/ap-request.ts b/packages/backend/src/server/api/endpoints/charts/ap-request.ts index a8f6e4564..9e9013ce5 100644 --- a/packages/backend/src/server/api/endpoints/charts/ap-request.ts +++ b/packages/backend/src/server/api/endpoints/charts/ap-request.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { apRequestChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { apRequestChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts'], + tags: ["charts"], requireCredentialPrivateMode: true, res: getJsonSchema(apRequestChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await apRequestChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await apRequestChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/drive.ts b/packages/backend/src/server/api/endpoints/charts/drive.ts index 14f82e39d..03ac4c047 100644 --- a/packages/backend/src/server/api/endpoints/charts/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/drive.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { driveChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { driveChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts', 'drive'], + tags: ["charts", "drive"], requireCredentialPrivateMode: true, res: getJsonSchema(driveChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await driveChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await driveChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/federation.ts b/packages/backend/src/server/api/endpoints/charts/federation.ts index 141e005ee..5862aad56 100644 --- a/packages/backend/src/server/api/endpoints/charts/federation.ts +++ b/packages/backend/src/server/api/endpoints/charts/federation.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { federationChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { federationChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts'], + tags: ["charts"], requireCredentialPrivateMode: true, res: getJsonSchema(federationChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await federationChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await federationChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/hashtag.ts b/packages/backend/src/server/api/endpoints/charts/hashtag.ts index d34153bc1..0af1e35ea 100644 --- a/packages/backend/src/server/api/endpoints/charts/hashtag.ts +++ b/packages/backend/src/server/api/endpoints/charts/hashtag.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { hashtagChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { hashtagChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts', 'hashtags'], + tags: ["charts", "hashtags"], requireCredentialPrivateMode: true, res: getJsonSchema(hashtagChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - tag: { type: 'string' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + tag: { type: "string" }, }, - required: ['span', 'tag'], + required: ["span", "tag"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await hashtagChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.tag); + return await hashtagChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.tag, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/instance.ts b/packages/backend/src/server/api/endpoints/charts/instance.ts index 3d9619d24..11a1dbce1 100644 --- a/packages/backend/src/server/api/endpoints/charts/instance.ts +++ b/packages/backend/src/server/api/endpoints/charts/instance.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { instanceChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { instanceChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts'], + tags: ["charts"], requireCredentialPrivateMode: true, res: getJsonSchema(instanceChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - host: { type: 'string' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + host: { type: "string" }, }, - required: ['span', 'host'], + required: ["span", "host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await instanceChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.host); + return await instanceChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.host, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/notes.ts b/packages/backend/src/server/api/endpoints/charts/notes.ts index 42befed27..27e69a4c9 100644 --- a/packages/backend/src/server/api/endpoints/charts/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/notes.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { notesChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { notesChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts', 'notes'], + tags: ["charts", "notes"], requireCredentialPrivateMode: true, res: getJsonSchema(notesChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await notesChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await notesChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/drive.ts b/packages/backend/src/server/api/endpoints/charts/user/drive.ts index cb73b4ac9..178ba453c 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/drive.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { perUserDriveChart } from '@/services/chart/index.js'; -import define from '../../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { perUserDriveChart } from "@/services/chart/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['charts', 'drive', 'users'], + tags: ["charts", "drive", "users"], requireCredentialPrivateMode: true, res: getJsonSchema(perUserDriveChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - userId: { type: 'string', format: 'misskey:id' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['span', 'userId'], + required: ["span", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await perUserDriveChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); + return await perUserDriveChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.userId, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/following.ts b/packages/backend/src/server/api/endpoints/charts/user/following.ts index 697a5f37a..6a0c22df1 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/following.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/following.ts @@ -1,9 +1,9 @@ -import define from '../../../define.js'; -import { getJsonSchema } from '@/services/chart/core.js'; -import { perUserFollowingChart } from '@/services/chart/index.js'; +import define from "../../../define.js"; +import { getJsonSchema } from "@/services/chart/core.js"; +import { perUserFollowingChart } from "@/services/chart/index.js"; export const meta = { - tags: ['charts', 'users', 'following'], + tags: ["charts", "users", "following"], requireCredentialPrivateMode: true, res: getJsonSchema(perUserFollowingChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - userId: { type: 'string', format: 'misskey:id' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['span', 'userId'], + required: ["span", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await perUserFollowingChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); + return await perUserFollowingChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.userId, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/notes.ts b/packages/backend/src/server/api/endpoints/charts/user/notes.ts index 5b576754d..d78807696 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/notes.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { perUserNotesChart } from '@/services/chart/index.js'; -import define from '../../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { perUserNotesChart } from "@/services/chart/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['charts', 'users', 'notes'], + tags: ["charts", "users", "notes"], requireCredentialPrivateMode: true, res: getJsonSchema(perUserNotesChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - userId: { type: 'string', format: 'misskey:id' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['span', 'userId'], + required: ["span", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await perUserNotesChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); + return await perUserNotesChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.userId, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts index 61c4527b9..5b0048c50 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { perUserReactionsChart } from '@/services/chart/index.js'; -import define from '../../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { perUserReactionsChart } from "@/services/chart/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['charts', 'users', 'reactions'], + tags: ["charts", "users", "reactions"], requireCredentialPrivateMode: true, res: getJsonSchema(perUserReactionsChart.schema), @@ -13,17 +13,21 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, - userId: { type: 'string', format: 'misskey:id' }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['span', 'userId'], + required: ["span", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await perUserReactionsChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); + return await perUserReactionsChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ps.userId, + ); }); diff --git a/packages/backend/src/server/api/endpoints/charts/users.ts b/packages/backend/src/server/api/endpoints/charts/users.ts index 0c799287c..8973f013b 100644 --- a/packages/backend/src/server/api/endpoints/charts/users.ts +++ b/packages/backend/src/server/api/endpoints/charts/users.ts @@ -1,9 +1,9 @@ -import { getJsonSchema } from '@/services/chart/core.js'; -import { usersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; +import { getJsonSchema } from "@/services/chart/core.js"; +import { usersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['charts', 'users'], + tags: ["charts", "users"], requireCredentialPrivateMode: true, res: getJsonSchema(usersChart.schema), @@ -13,16 +13,19 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - span: { type: 'string', enum: ['day', 'hour'] }, - limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, - offset: { type: 'integer', nullable: true, default: null }, + span: { type: "string", enum: ["day", "hour"] }, + limit: { type: "integer", minimum: 1, maximum: 500, default: 30 }, + offset: { type: "integer", nullable: true, default: null }, }, - required: ['span'], + required: ["span"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - return await usersChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); + return await usersChart.getChart( + ps.span, + ps.limit, + ps.offset ? new Date(ps.offset) : null, + ); }); diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index 91baa8eb7..b9d6b54c9 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -1,47 +1,46 @@ -import define from '../../define.js'; -import { ClipNotes, Clips } from '@/models/index.js'; -import { ApiError } from '../../error.js'; -import { genId } from '@/misc/gen-id.js'; -import { getNote } from '../../common/getters.js'; +import define from "../../define.js"; +import { ClipNotes, Clips } from "@/models/index.js"; +import { ApiError } from "../../error.js"; +import { genId } from "@/misc/gen-id.js"; +import { getNote } from "../../common/getters.js"; export const meta = { - tags: ['account', 'notes', 'clips'], + tags: ["account", "notes", "clips"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf', + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "d6e76cc0-a1b5-4c7c-a287-73fa9c716dcf", }, noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "fc8c0b49-c7a3-4664-a0a6-b418d386bb8b", }, alreadyClipped: { - message: 'The note has already been clipped.', - code: 'ALREADY_CLIPPED', - id: '734806c4-542c-463a-9311-15c512803965', + message: "The note has already been clipped.", + code: "ALREADY_CLIPPED", + id: "734806c4-542c-463a-9311-15c512803965", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clipId: { type: 'string', format: 'misskey:id' }, - noteId: { type: 'string', format: 'misskey:id' }, + clipId: { type: "string", format: "misskey:id" }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['clipId', 'noteId'], + required: ["clipId", "noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOneBy({ id: ps.clipId, @@ -52,8 +51,9 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchClip); } - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index 4afe4222a..918e9462a 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -1,32 +1,37 @@ -import define from '../../define.js'; -import { genId } from '@/misc/gen-id.js'; -import { Clips } from '@/models/index.js'; +import define from "../../define.js"; +import { genId } from "@/misc/gen-id.js"; +import { Clips } from "@/models/index.js"; export const meta = { - tags: ['clips'], + tags: ["clips"], requireCredential: true, - kind: 'write:account', + kind: "write:account", res: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 100 }, - isPublic: { type: 'boolean', default: false }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + name: { type: "string", minLength: 1, maxLength: 100 }, + isPublic: { type: "boolean", default: false }, + description: { + type: "string", + nullable: true, + minLength: 1, + maxLength: 2048, + }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.insert({ id: genId(), @@ -35,7 +40,7 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, isPublic: ps.isPublic, description: ps.description, - }).then(x => Clips.findOneByOrFail(x.identifiers[0])); + }).then((x) => Clips.findOneByOrFail(x.identifiers[0])); return await Clips.pack(clip); }); diff --git a/packages/backend/src/server/api/endpoints/clips/delete.ts b/packages/backend/src/server/api/endpoints/clips/delete.ts index b6c0eb702..8f2489ddd 100644 --- a/packages/backend/src/server/api/endpoints/clips/delete.ts +++ b/packages/backend/src/server/api/endpoints/clips/delete.ts @@ -1,32 +1,31 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Clips } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Clips } from "@/models/index.js"; export const meta = { - tags: ['clips'], + tags: ["clips"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: '70ca08ba-6865-4630-b6fb-8494759aa754', + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "70ca08ba-6865-4630-b6fb-8494759aa754", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clipId: { type: 'string', format: 'misskey:id' }, + clipId: { type: "string", format: "misskey:id" }, }, - required: ['clipId'], + required: ["clipId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOneBy({ id: ps.clipId, diff --git a/packages/backend/src/server/api/endpoints/clips/list.ts b/packages/backend/src/server/api/endpoints/clips/list.ts index 378811eba..d1625ee03 100644 --- a/packages/backend/src/server/api/endpoints/clips/list.ts +++ b/packages/backend/src/server/api/endpoints/clips/list.ts @@ -1,35 +1,36 @@ -import define from '../../define.js'; -import { Clips } from '@/models/index.js'; +import define from "../../define.js"; +import { Clips } from "@/models/index.js"; export const meta = { - tags: ['clips', 'account'], + tags: ["clips", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const clips = await Clips.findBy({ userId: me.id, }); - return await Promise.all(clips.map(x => Clips.pack(x))); + return await Promise.all(clips.map((x) => Clips.pack(x))); }); diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index eea6f0a0d..c641d9ba9 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -1,50 +1,51 @@ -import define from '../../define.js'; -import { ClipNotes, Clips, Notes } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { ApiError } from '../../error.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import define from "../../define.js"; +import { ClipNotes, Clips, Notes } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { ApiError } from "../../error.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['account', 'notes', 'clips'], + tags: ["account", "notes", "clips"], requireCredential: false, requireCredentialPrivateMode: true, - kind: 'read:account', + kind: "read:account", errors: { noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00', + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "1d7645e6-2b6d-4635-b0fe-fe22b0e72e00", }, }, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clipId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + clipId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['clipId'], + required: ["clipId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOneBy({ id: ps.clipId, @@ -54,24 +55,32 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchClip); } - if (!clip.isPublic && (user == null || (clip.userId !== user.id))) { + if (!clip.isPublic && (user == null || clip.userId !== user.id)) { throw new ApiError(meta.errors.noSuchClip); } - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .innerJoin(ClipNotes.metadata.targetName, 'clipNote', 'clipNote.noteId = note.id') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .andWhere('clipNote.clipId = :clipId', { clipId: clip.id }); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .innerJoin( + ClipNotes.metadata.targetName, + "clipNote", + "clipNote.noteId = note.id", + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") + .andWhere("clipNote.clipId = :clipId", { clipId: clip.id }); if (user) { generateVisibilityQuery(query, user); @@ -79,9 +88,7 @@ export default define(meta, paramDef, async (ps, user) => { generateBlockedUserQuery(query, user); } - const notes = await query - .take(ps.limit) - .getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, user); }); diff --git a/packages/backend/src/server/api/endpoints/clips/remove-note.ts b/packages/backend/src/server/api/endpoints/clips/remove-note.ts index 8b90e31f6..2cc19aca9 100644 --- a/packages/backend/src/server/api/endpoints/clips/remove-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/remove-note.ts @@ -1,57 +1,57 @@ -import define from '../../define.js'; -import { ClipNotes, Clips } from '@/models/index.js'; -import { ApiError } from '../../error.js'; -import { getNote } from '../../common/getters.js'; - -export const meta = { - tags: ['account', 'notes', 'clips'], - - requireCredential: true, - - kind: 'write:account', - - errors: { - noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', - }, - - noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'aff017de-190e-434b-893e-33a9ff5049d8', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - clipId: { type: 'string', format: 'misskey:id' }, - noteId: { type: 'string', format: 'misskey:id' }, - }, - required: ['clipId', 'noteId'], -} as const; - -// eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user) => { - const clip = await Clips.findOneBy({ - id: ps.clipId, - userId: user.id, - }); - - if (clip == null) { - throw new ApiError(meta.errors.noSuchClip); - } - - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; - }); - - await ClipNotes.delete({ - noteId: note.id, - clipId: clip.id, - }); -}); +import define from "../../define.js"; +import { ClipNotes, Clips } from "@/models/index.js"; +import { ApiError } from "../../error.js"; +import { getNote } from "../../common/getters.js"; + +export const meta = { + tags: ["account", "notes", "clips"], + + requireCredential: true, + + kind: "write:account", + + errors: { + noSuchClip: { + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "b80525c6-97f7-49d7-a42d-ebccd49cfd52", + }, + + noSuchNote: { + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "aff017de-190e-434b-893e-33a9ff5049d8", + }, + }, +} as const; + +export const paramDef = { + type: "object", + properties: { + clipId: { type: "string", format: "misskey:id" }, + noteId: { type: "string", format: "misskey:id" }, + }, + required: ["clipId", "noteId"], +} as const; + +export default define(meta, paramDef, async (ps, user) => { + const clip = await Clips.findOneBy({ + id: ps.clipId, + userId: user.id, + }); + + if (clip == null) { + throw new ApiError(meta.errors.noSuchClip); + } + + const note = await getNote(ps.noteId).catch((e) => { + if (e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); + throw e; + }); + + await ClipNotes.delete({ + noteId: note.id, + clipId: clip.id, + }); +}); diff --git a/packages/backend/src/server/api/endpoints/clips/show.ts b/packages/backend/src/server/api/endpoints/clips/show.ts index aec4c1253..14709b504 100644 --- a/packages/backend/src/server/api/endpoints/clips/show.ts +++ b/packages/backend/src/server/api/endpoints/clips/show.ts @@ -1,39 +1,39 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Clips } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Clips } from "@/models/index.js"; export const meta = { - tags: ['clips', 'account'], + tags: ["clips", "account"], requireCredential: false, requireCredentialPrivateMode: true, - kind: 'read:account', + kind: "read:account", errors: { noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20', + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "c3c5fe33-d62c-44d2-9ea5-d997703f5c20", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clipId: { type: 'string', format: 'misskey:id' }, + clipId: { type: "string", format: "misskey:id" }, }, - required: ['clipId'], + required: ["clipId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the clip const clip = await Clips.findOneBy({ @@ -44,7 +44,7 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.noSuchClip); } - if (!clip.isPublic && (me == null || (clip.userId !== me.id))) { + if (!clip.isPublic && (me == null || clip.userId !== me.id)) { throw new ApiError(meta.errors.noSuchClip); } diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index b67d844f6..e78f36e45 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -1,41 +1,46 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Clips } from '@/models/index.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Clips } from "@/models/index.js"; export const meta = { - tags: ['clips'], + tags: ["clips"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: 'b4d92d70-b216-46fa-9a3f-a8c811699257', + message: "No such clip.", + code: "NO_SUCH_CLIP", + id: "b4d92d70-b216-46fa-9a3f-a8c811699257", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clipId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 100 }, - isPublic: { type: 'boolean' }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + clipId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 100 }, + isPublic: { type: "boolean" }, + description: { + type: "string", + nullable: true, + minLength: 1, + maxLength: 2048, + }, }, - required: ['clipId', 'name'], + required: ["clipId", "name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the clip const clip = await Clips.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/compatibility/custom-emojis.ts b/packages/backend/src/server/api/endpoints/compatibility/custom-emojis.ts new file mode 100644 index 000000000..62e0836e8 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/compatibility/custom-emojis.ts @@ -0,0 +1,37 @@ +import { Emojis } from "@/models/index.js"; +import type { Emoji } from "@/models/entities/emoji.js"; +import { IsNull, In } from "typeorm"; +import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; +import define from "../../define.js"; + +export const meta = { + requireCredential: false, + requireCredentialPrivateMode: true, + allowGet: true, + + tags: ["meta"], +} as const; + +export const paramDef = { + type: "object", + properties: {}, + required: [], +} as const; + +export default define(meta, paramDef, async () => { + const now = Date.now(); + const emojis: Emoji[] = await Emojis.find({ + where: { host: IsNull(), type: In(FILE_TYPE_BROWSERSAFE) }, + select: ["name", "originalUrl", "publicUrl", "category"], + }); + + const emojiList = emojis.map((emoji) => ({ + shortcode: emoji.name, + url: emoji.originalUrl, + static_url: emoji.publicUrl, + visible_in_picker: true, + category: emoji.category, + })); + + return emojiList; +}); diff --git a/packages/backend/src/server/api/endpoints/compatibility/instance-info.ts b/packages/backend/src/server/api/endpoints/compatibility/instance-info.ts new file mode 100644 index 000000000..4e692568c --- /dev/null +++ b/packages/backend/src/server/api/endpoints/compatibility/instance-info.ts @@ -0,0 +1,232 @@ +import * as mfm from "mfm-js"; +import { toHtml } from "@/mfm/to-html.js"; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { + Users, + Notes, + Instances, + UserProfiles, + Emojis, + DriveFiles, +} from "@/models/index.js"; +import type { Emoji } from "@/models/entities/emoji.js"; +import type { User } from "@/models/entities/user.js"; +import { IsNull, In } from "typeorm"; +import { MAX_NOTE_TEXT_LENGTH, FILE_TYPE_BROWSERSAFE } from "@/const.js"; +import define from "../../define.js"; + +export const meta = { + requireCredential: false, + requireCredentialPrivateMode: true, + allowGet: true, + + tags: ["meta"], +} as const; + +export const paramDef = { + type: "object", + properties: {}, + required: [], +} as const; + +export default define(meta, paramDef, async () => { + const now = Date.now(); + const [meta, total, localPosts, instanceCount, firstAdmin, emojis] = + await Promise.all([ + fetchMeta(true), + Users.count({ where: { host: IsNull() } }), + Notes.count({ where: { userHost: IsNull(), replyId: IsNull() } }), + Instances.count(), + Users.findOne({ + where: { + host: IsNull(), + isAdmin: true, + isDeleted: false, + isBot: false, + }, + order: { id: "ASC" }, + }), + Emojis.find({ + where: { host: IsNull(), type: In(FILE_TYPE_BROWSERSAFE) }, + select: ["id", "name", "originalUrl", "publicUrl"], + }).then((l) => + l.reduce((a, e) => { + a[e.name] = e; + return a; + }, {} as Record), + ), + ]); + + const descSplit = splitN(meta.description, "\n", 2); + const shortDesc = markup(descSplit.length > 0 ? descSplit[0] : ""); + const longDesc = markup(meta.description ?? ""); + + return { + uri: config.hostname, + title: meta.name, + short_description: shortDesc, + description: longDesc, + email: meta.maintainerEmail, + version: config.version, + urls: { + streaming_api: `wss://${config.host}`, + }, + stats: { + user_count: total, + status_count: localPosts, + domain_count: instanceCount, + }, + thumbnail: meta.logoImageUrl, + languages: meta.langs, + registrations: !meta.disableRegistration, + approval_required: false, + invites_enabled: false, + configuration: { + accounts: { + max_featured_tags: 16, + }, + statuses: { + max_characters: MAX_NOTE_TEXT_LENGTH, + max_media_attachments: 16, + characters_reserved_per_url: 0, + }, + media_attachments: { + supported_mime_types: FILE_TYPE_BROWSERSAFE, + image_size_limit: 10485760, + image_matrix_limit: 16777216, + video_size_limit: 41943040, + video_frame_rate_limit: 60, + video_matrix_limit: 2304000, + }, + polls: { + max_options: 10, + max_characters_per_option: 50, + min_expiration: 15, + max_expiration: -1, + }, + }, + contact_account: await getContact(firstAdmin, emojis), + rules: [], + }; +}); + +const splitN = (s: string | null, split: string, n: number): string[] => { + const ret: string[] = []; + if (s == null) return ret; + if (s === "") { + ret.push(s); + return ret; + } + + let start = 0; + let pos = s.indexOf(split); + if (pos === -1) { + ret.push(s); + return ret; + } + + for (let i = 0; i < n - 1; i++) { + ret.push(s.substring(start, pos)); + start = pos + split.length; + pos = s.indexOf(split, start); + if (pos === -1) break; + } + ret.push(s.substring(start)); + + return ret; +}; + +type ContactType = { + id: string; + username: string; + acct: string; + display_name: string; + note?: string; + noindex?: boolean; + fields?: { + name: string; + value: string; + verified_at: string | null; + }[]; + locked: boolean; + bot: boolean; + created_at: string; + url: string; + followers_count: number; + following_count: number; + statuses_count: number; + last_status_at?: string; + emojis: any; +} | null; + +const getContact = async ( + user: User | null, + emojis: Record, +): Promise => { + if (!user) return null; + + let contact: ContactType = { + id: user.id, + username: user.username, + acct: user.username, + display_name: user.name ?? user.username, + locked: user.isLocked, + bot: user.isBot, + created_at: user.createdAt.toISOString(), + url: `${config.url}/@${user.username}`, + followers_count: user.followersCount, + following_count: user.followingCount, + statuses_count: user.notesCount, + last_status_at: user.lastActiveDate?.toISOString(), + emojis: emojis + ? user.emojis + .filter((e, i, a) => e in emojis && a.indexOf(e) === i) + .map((e) => ({ + shortcode: e, + static_url: emojis[e].publicUrl, + url: emojis[e].originalUrl, + visible_in_picker: true, + })) + : [], + }; + + const [profile] = await Promise.all([ + UserProfiles.findOne({ where: { userId: user.id } }), + loadDriveFiles(contact, "avatar", user.avatarId), + loadDriveFiles(contact, "header", user.bannerId), + ]); + + if (!profile) { + return contact; + } + + contact = { + ...contact, + note: markup(profile.description ?? ""), + noindex: profile.noCrawle, + fields: profile.fields.map((f) => ({ + name: f.name, + value: f.value, + verified_at: null, + })), + }; + + return contact; +}; + +const loadDriveFiles = async ( + contact: any, + key: string, + fileId: string | null, +) => { + if (fileId) { + const file = await DriveFiles.findOneBy({ id: fileId }); + if (file) { + contact[key] = file.webpublicUrl ?? file.url; + contact[`${key}_static`] = contact[key]; + } + } +}; + +const markup = (text: string): string => toHtml(mfm.parse(text)) ?? ""; diff --git a/packages/backend/src/server/api/endpoints/custom-motd.ts b/packages/backend/src/server/api/endpoints/custom-motd.ts index fd58424bd..098a676a5 100644 --- a/packages/backend/src/server/api/endpoints/custom-motd.ts +++ b/packages/backend/src/server/api/endpoints/custom-motd.ts @@ -1,32 +1,33 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import define from '../define.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const meta = await fetchMeta(); - const motd = await Promise.all(meta.customMOTD.map(x => x)); + const motd = await Promise.all(meta.customMOTD.map((x) => x)); return motd; }); diff --git a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts index 380e2131b..c4833a4ee 100644 --- a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts +++ b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts @@ -1,32 +1,33 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import define from '../define.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const meta = await fetchMeta(); - const icons = await Promise.all(meta.customSplashIcons.map(x => x)); + const icons = await Promise.all(meta.customSplashIcons.map((x) => x)); return icons; }); diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index 82497adef..ce98b53a6 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -1,37 +1,39 @@ -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { DriveFiles } from '@/models/index.js'; -import define from '../define.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { DriveFiles } from "@/models/index.js"; +import define from "../define.js"; export const meta = { - tags: ['drive', 'account'], + tags: ["drive", "account"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { capacity: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, usage: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const instance = await fetchMeta(true); @@ -39,7 +41,10 @@ export default define(meta, paramDef, async (ps, user) => { const usage = await DriveFiles.calcDriveUsageOf(user.id); return { - capacity: 1024 * 1024 * (user.driveCapacityOverrideMb || instance.localDriveCapacityMb), + capacity: + 1024 * + 1024 * + (user.driveCapacityOverrideMb || instance.localDriveCapacityMb), usage: usage, }; }); diff --git a/packages/backend/src/server/api/endpoints/drive/files.ts b/packages/backend/src/server/api/endpoints/drive/files.ts index 40e6c16c9..c749e4903 100644 --- a/packages/backend/src/server/api/endpoints/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/drive/files.ts @@ -1,53 +1,68 @@ -import define from '../../define.js'; -import { DriveFiles } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { DriveFiles } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + folderId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, + type: { + type: "string", + nullable: true, + pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1), + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId) - .andWhere('file.userId = :userId', { userId: user.id }); + const query = makePaginationQuery( + DriveFiles.createQueryBuilder("file"), + ps.sinceId, + ps.untilId, + ).andWhere("file.userId = :userId", { userId: user.id }); if (ps.folderId) { - query.andWhere('file.folderId = :folderId', { folderId: ps.folderId }); + query.andWhere("file.folderId = :folderId", { folderId: ps.folderId }); } else { - query.andWhere('file.folderId IS NULL'); + query.andWhere("file.folderId IS NULL"); } if (ps.type) { - if (ps.type.endsWith('/*')) { - query.andWhere('file.type like :type', { type: ps.type.replace('/*', '/') + '%' }); + if (ps.type.endsWith("/*")) { + query.andWhere("file.type like :type", { + type: `${ps.type.replace("/*", "/")}%`, + }); } else { - query.andWhere('file.type = :type', { type: ps.type }); + query.andWhere("file.type = :type", { type: ps.type }); } } diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts index 415a8cc69..9267da585 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts @@ -1,44 +1,45 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { DriveFiles, Notes } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { DriveFiles, Notes } from "@/models/index.js"; export const meta = { - tags: ['drive', 'notes'], + tags: ["drive", "notes"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", - description: 'Find the notes to which the given file is attached.', + description: "Find the notes to which the given file is attached.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'c118ece3-2e4b-4296-99d1-51756e32d232', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "c118ece3-2e4b-4296-99d1-51756e32d232", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch file const file = await DriveFiles.findOneBy({ @@ -50,8 +51,8 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchFile); } - const notes = await Notes.createQueryBuilder('note') - .where(':file = ANY(note.fileIds)', { file: file.id }) + const notes = await Notes.createQueryBuilder("note") + .where(":file = ANY(note.fileIds)", { file: file.id }) .getMany(); return await Notes.packMany(notes, user, { diff --git a/packages/backend/src/server/api/endpoints/drive/files/caption-image.ts b/packages/backend/src/server/api/endpoints/drive/files/caption-image.ts index 81455a501..1ab817bd0 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/caption-image.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/caption-image.ts @@ -1,40 +1,41 @@ -import define from '../../../define.js'; -import { createWorker } from 'tesseract.js'; +import define from "../../../define.js"; +import { createWorker } from "tesseract.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", - description: 'Return caption of image', + description: "Return caption of image", res: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - url: { type: 'string' }, + url: { type: "string" }, }, - required: ['url'], + required: ["url"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const worker = createWorker({ - logger: m => console.log(m) + logger: (m) => console.log(m), }); await worker.load(); - await worker.loadLanguage('eng'); - await worker.initialize('eng'); - const { data: { text } } = await worker.recognize(ps.url); + await worker.loadLanguage("eng"); + await worker.initialize("eng"); + const { + data: { text }, + } = await worker.recognize(ps.url); await worker.terminate(); return text; diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts index bbae9bf4e..df8968520 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts @@ -1,30 +1,30 @@ -import define from '../../../define.js'; -import { DriveFiles } from '@/models/index.js'; +import define from "../../../define.js"; +import { DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", - description: 'Check if a given file exists.', + description: "Check if a given file exists.", res: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - md5: { type: 'string' }, + md5: { type: "string" }, }, - required: ['md5'], + required: ["md5"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ md5: ps.md5, diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index a37e6cf0c..0a167178b 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -1,17 +1,15 @@ -import { addFile } from '@/services/drive/add-file.js'; -import { DriveFiles } from '@/models/index.js'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import define from '../../../define.js'; -import { apiLogger } from '../../../logger.js'; -import { ApiError } from '../../../error.js'; -import { DriveFiles } from '@/models/index.js'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; -import { HOUR } from '@/const.js'; +import { addFile } from "@/services/drive/add-file.js"; +import { DriveFiles } from "@/models/index.js"; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { HOUR } from "@/const.js"; +import define from "../../../define.js"; +import { apiLogger } from "../../../logger.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, @@ -22,92 +20,110 @@ export const meta = { requireFile: true, - kind: 'write:drive', + kind: "write:drive", - description: 'Upload a new drive file.', + description: "Upload a new drive file.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, errors: { invalidFileName: { - message: 'Invalid file name.', - code: 'INVALID_FILE_NAME', - id: 'f449b209-0c60-4e51-84d5-29486263bfd4', + message: "Invalid file name.", + code: "INVALID_FILE_NAME", + id: "f449b209-0c60-4e51-84d5-29486263bfd4", }, inappropriate: { - message: 'Cannot upload the file because it has been determined that it possibly contains inappropriate content.', - code: 'INAPPROPRIATE', - id: 'bec5bd69-fba3-43c9-b4fb-2894b66ad5d2', + message: + "Cannot upload the file because it has been determined that it possibly contains inappropriate content.", + code: "INAPPROPRIATE", + id: "bec5bd69-fba3-43c9-b4fb-2894b66ad5d2", }, noFreeSpace: { - message: 'Cannot upload the file because you have no free space of drive.', - code: 'NO_FREE_SPACE', - id: 'd08dbc37-a6a9-463a-8c47-96c32ab5f064', + message: + "Cannot upload the file because you have no free space of drive.", + code: "NO_FREE_SPACE", + id: "d08dbc37-a6a9-463a-8c47-96c32ab5f064", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - name: { type: 'string', nullable: true, default: null }, - comment: { type: 'string', nullable: true, maxLength: DB_MAX_IMAGE_COMMENT_LENGTH, default: null }, - isSensitive: { type: 'boolean', default: false }, - force: { type: 'boolean', default: false }, + folderId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, + name: { type: "string", nullable: true, default: null }, + comment: { + type: "string", + nullable: true, + maxLength: DB_MAX_IMAGE_COMMENT_LENGTH, + default: null, + }, + isSensitive: { type: "boolean", default: false }, + force: { type: "boolean", default: false }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user, _, file, cleanup, ip, headers) => { - // Get 'name' parameter - let name = ps.name || file.originalname; - if (name !== undefined && name !== null) { - name = name.trim(); - if (name.length === 0) { +export default define( + meta, + paramDef, + async (ps, user, _, file, cleanup, ip, headers) => { + // Get 'name' parameter + let name = ps.name || file.originalname; + if (name !== undefined && name !== null) { + name = name.trim(); + if (name.length === 0) { + name = null; + } else if (name === "blob") { + name = null; + } else if (!DriveFiles.validateFileName(name)) { + throw new ApiError(meta.errors.invalidFileName); + } + } else { name = null; - } else if (name === 'blob') { - name = null; - } else if (!DriveFiles.validateFileName(name)) { - throw new ApiError(meta.errors.invalidFileName); } - } else { - name = null; - } - const meta = await fetchMeta(); + const meta = await fetchMeta(); - try { - // Create file - const driveFile = await addFile({ - user, - path: file.path, - name, - comment: ps.comment, - folderId: ps.folderId, - force: ps.force, - sensitive: ps.isSensitive, - requestIp: meta.enableIpLogging ? ip : null, - requestHeaders: meta.enableIpLogging ? headers : null, - }); - return await DriveFiles.pack(driveFile, { self: true }); - } catch (e) { - if (e instanceof Error || typeof e === 'string') { - apiLogger.error(e); + try { + // Create file + const driveFile = await addFile({ + user, + path: file.path, + name, + comment: ps.comment, + folderId: ps.folderId, + force: ps.force, + sensitive: ps.isSensitive, + requestIp: meta.enableIpLogging ? ip : null, + requestHeaders: meta.enableIpLogging ? headers : null, + }); + return await DriveFiles.pack(driveFile, { self: true }); + } catch (e) { + if (e instanceof Error || typeof e === "string") { + apiLogger.error(e); + } + if (e instanceof IdentifiableError) { + if (e.id === "282f77bf-5816-4f72-9264-aa14d8261a21") + throw new ApiError(meta.errors.inappropriate); + if (e.id === "c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6") + throw new ApiError(meta.errors.noFreeSpace); + } + throw new ApiError(); + } finally { + cleanup!(); } - if (e instanceof IdentifiableError) { - if (e.id === '282f77bf-5816-4f72-9264-aa14d8261a21') throw new ApiError(meta.errors.inappropriate); - if (e.id === 'c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6') throw new ApiError(meta.errors.noFreeSpace); - } - throw new ApiError(); - } finally { - cleanup!(); - } -}); + }, +); diff --git a/packages/backend/src/server/api/endpoints/drive/files/delete.ts b/packages/backend/src/server/api/endpoints/drive/files/delete.ts index 6108ae7da..4e8b4156f 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/delete.ts @@ -1,42 +1,41 @@ -import { deleteFile } from '@/services/drive/delete-file.js'; -import { publishDriveStream } from '@/services/stream.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { DriveFiles, Users } from '@/models/index.js'; +import { deleteFile } from "@/services/drive/delete-file.js"; +import { publishDriveStream } from "@/services/stream.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { DriveFiles, Users } from "@/models/index.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'write:drive', + kind: "write:drive", - description: 'Delete an existing drive file.', + description: "Delete an existing drive file.", errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: '908939ec-e52b-4458-b395-1025195cea58', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "908939ec-e52b-4458-b395-1025195cea58", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '5eb8d909-2540-4970-90b8-dd6f86088121', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "5eb8d909-2540-4970-90b8-dd6f86088121", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); @@ -44,7 +43,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchFile); } - if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { + if (!(user.isAdmin || user.isModerator) && file.userId !== user.id) { throw new ApiError(meta.errors.accessDenied); } @@ -52,5 +51,5 @@ export default define(meta, paramDef, async (ps, user) => { await deleteFile(file); // Publish fileDeleted event - publishDriveStream(user.id, 'fileDeleted', file.id); + publishDriveStream(user.id, "fileDeleted", file.id); }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts index f2bc7348c..ce14f4e09 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts @@ -1,35 +1,36 @@ -import { DriveFiles } from '@/models/index.js'; -import define from '../../../define.js'; +import { DriveFiles } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", - description: 'Search for a drive file by a hash of the contents.', + description: "Search for a drive file by a hash of the contents.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - md5: { type: 'string' }, + md5: { type: "string" }, }, - required: ['md5'], + required: ["md5"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const files = await DriveFiles.findBy({ md5: ps.md5, diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts index 245fb45a6..c2ad95126 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts @@ -1,37 +1,43 @@ -import define from '../../../define.js'; -import { DriveFiles } from '@/models/index.js'; -import { IsNull } from 'typeorm'; +import define from "../../../define.js"; +import { DriveFiles } from "@/models/index.js"; +import { IsNull } from "typeorm"; export const meta = { requireCredential: true, - tags: ['drive'], + tags: ["drive"], - kind: 'read:drive', + kind: "read:drive", - description: 'Search for a drive file by the given parameters.', + description: "Search for a drive file by the given parameters.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + name: { type: "string" }, + folderId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const files = await DriveFiles.findBy({ name: ps.name, @@ -39,5 +45,7 @@ export default define(meta, paramDef, async (ps, user) => { folderId: ps.folderId ?? IsNull(), }); - return await Promise.all(files.map(file => DriveFiles.pack(file, { self: true }))); + return await Promise.all( + files.map((file) => DriveFiles.pack(file, { self: true })), + ); }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/show.ts b/packages/backend/src/server/api/endpoints/drive/files/show.ts index 2c604c54c..291e3f56b 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/show.ts @@ -1,57 +1,57 @@ -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles, Users } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles, Users } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", - description: 'Show the properties of a drive file.', + description: "Show the properties of a drive file.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: '067bc436-2718-4795-b0fb-ecbe43949e31', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "067bc436-2718-4795-b0fb-ecbe43949e31", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '25b73c73-68b1-41d0-bad1-381cfdf6579f', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "25b73c73-68b1-41d0-bad1-381cfdf6579f", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", anyOf: [ { properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], }, { properties: { - url: { type: 'string' }, + url: { type: "string" }, }, - required: ['url'], + required: ["url"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { let file: DriveFile | null = null; @@ -59,13 +59,17 @@ export default define(meta, paramDef, async (ps, user) => { file = await DriveFiles.findOneBy({ id: ps.fileId }); } else if (ps.url) { file = await DriveFiles.findOne({ - where: [{ - url: ps.url, - }, { - webpublicUrl: ps.url, - }, { - thumbnailUrl: ps.url, - }], + where: [ + { + url: ps.url, + }, + { + webpublicUrl: ps.url, + }, + { + thumbnailUrl: ps.url, + }, + ], }); } @@ -73,7 +77,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchFile); } - if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { + if (!(user.isAdmin || user.isModerator) && file.userId !== user.id) { throw new ApiError(meta.errors.accessDenied); } diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index fa2ec8519..d113b978f 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -1,64 +1,64 @@ -import { publishDriveStream } from '@/services/stream.js'; -import { DriveFiles, DriveFolders, Users } from '@/models/index.js'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { publishDriveStream } from "@/services/stream.js"; +import { DriveFiles, DriveFolders, Users } from "@/models/index.js"; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'write:drive', + kind: "write:drive", - description: 'Update the properties of a drive file.', + description: "Update the properties of a drive file.", errors: { invalidFileName: { - message: 'Invalid file name.', - code: 'INVALID_FILE_NAME', - id: '395e7156-f9f0-475e-af89-53c3c23080c2', + message: "Invalid file name.", + code: "INVALID_FILE_NAME", + id: "395e7156-f9f0-475e-af89-53c3c23080c2", }, noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'e7778c7e-3af9-49cd-9690-6dbc3e6c972d', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "e7778c7e-3af9-49cd-9690-6dbc3e6c972d", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '01a53b27-82fc-445b-a0c1-b558465a8ed2', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "01a53b27-82fc-445b-a0c1-b558465a8ed2", }, noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73', + message: "No such folder.", + code: "NO_SUCH_FOLDER", + id: "ea8fb7a5-af77-4a08-b608-c0218176cd73", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true }, - name: { type: 'string' }, - isSensitive: { type: 'boolean' }, - comment: { type: 'string', nullable: true, maxLength: 512 }, + fileId: { type: "string", format: "misskey:id" }, + folderId: { type: "string", format: "misskey:id", nullable: true }, + name: { type: "string" }, + isSensitive: { type: "boolean" }, + comment: { type: "string", nullable: true, maxLength: 512 }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); @@ -66,7 +66,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchFile); } - if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { + if (!(user.isAdmin || user.isModerator) && file.userId !== user.id) { throw new ApiError(meta.errors.accessDenied); } @@ -106,7 +106,7 @@ export default define(meta, paramDef, async (ps, user) => { const fileObj = await DriveFiles.pack(file, { self: true }); // Publish fileUpdated event - publishDriveStream(user.id, 'fileUpdated', fileObj); + publishDriveStream(user.id, "fileUpdated", fileObj); return fileObj; }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts index 88a448f21..7bb47dbef 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts @@ -1,42 +1,54 @@ -import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; -import define from '../../../define.js'; -import { DriveFiles } from '@/models/index.js'; -import { publishMainStream } from '@/services/stream.js'; -import { HOUR } from '@/const.js'; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import define from "../../../define.js"; +import { DriveFiles } from "@/models/index.js"; +import { publishMainStream } from "@/services/stream.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], limit: { duration: HOUR, max: 60, }, - description: 'Request the server to download a new drive file from the specified URL.', + description: + "Request the server to download a new drive file from the specified URL.", requireCredential: true, - kind: 'write:drive', + kind: "write:drive", } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - url: { type: 'string' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - isSensitive: { type: 'boolean', default: false }, - comment: { type: 'string', nullable: true, maxLength: 512, default: null }, - marker: { type: 'string', nullable: true, default: null }, - force: { type: 'boolean', default: false }, + url: { type: "string" }, + folderId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, + isSensitive: { type: "boolean", default: false }, + comment: { type: "string", nullable: true, maxLength: 512, default: null }, + marker: { type: "string", nullable: true, default: null }, + force: { type: "boolean", default: false }, }, - required: ['url'], + required: ["url"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - uploadFromUrl({ url: ps.url, user, folderId: ps.folderId, sensitive: ps.isSensitive, force: ps.force, comment: ps.comment }).then(file => { - DriveFiles.pack(file, { self: true }).then(packedFile => { - publishMainStream(user.id, 'urlUploadFinished', { + uploadFromUrl({ + url: ps.url, + user, + folderId: ps.folderId, + sensitive: ps.isSensitive, + force: ps.force, + comment: ps.comment, + }).then((file) => { + DriveFiles.pack(file, { self: true }).then((packedFile) => { + publishMainStream(user.id, "urlUploadFinished", { marker: ps.marker, file: packedFile, }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders.ts b/packages/backend/src/server/api/endpoints/drive/folders.ts index d4d530ba9..ed0d38844 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders.ts @@ -1,48 +1,57 @@ -import define from '../../define.js'; -import { DriveFolders } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { DriveFolders } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFolder', + type: "object", + optional: false, + nullable: false, + ref: "DriveFolder", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + folderId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(DriveFolders.createQueryBuilder('folder'), ps.sinceId, ps.untilId) - .andWhere('folder.userId = :userId', { userId: user.id }); + const query = makePaginationQuery( + DriveFolders.createQueryBuilder("folder"), + ps.sinceId, + ps.untilId, + ).andWhere("folder.userId = :userId", { userId: user.id }); if (ps.folderId) { - query.andWhere('folder.parentId = :parentId', { parentId: ps.folderId }); + query.andWhere("folder.parentId = :parentId", { parentId: ps.folderId }); } else { - query.andWhere('folder.parentId IS NULL'); + query.andWhere("folder.parentId IS NULL"); } const folders = await query.take(ps.limit).getMany(); - return await Promise.all(folders.map(folder => DriveFolders.pack(folder))); + return await Promise.all(folders.map((folder) => DriveFolders.pack(folder))); }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts index 3d7f514c8..d50f5f281 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts @@ -1,41 +1,41 @@ -import { publishDriveStream } from '@/services/stream.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { DriveFolders } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import { publishDriveStream } from "@/services/stream.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { DriveFolders } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'write:drive', + kind: "write:drive", errors: { noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: '53326628-a00d-40a6-a3cd-8975105c0f95', + message: "No such folder.", + code: "NO_SUCH_FOLDER", + id: "53326628-a00d-40a6-a3cd-8975105c0f95", }, }, res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'DriveFolder', + type: "object" as const, + optional: false as const, + nullable: false as const, + ref: "DriveFolder", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', default: "Untitled", maxLength: 200 }, - parentId: { type: 'string', format: 'misskey:id', nullable: true }, + name: { type: "string", default: "Untitled", maxLength: 200 }, + parentId: { type: "string", format: "misskey:id", nullable: true }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // If the parent folder is specified let parent = null; @@ -58,12 +58,12 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, parentId: parent !== null ? parent.id : null, userId: user.id, - }).then(x => DriveFolders.findOneByOrFail(x.identifiers[0])); + }).then((x) => DriveFolders.findOneByOrFail(x.identifiers[0])); const folderObj = await DriveFolders.pack(folder); // Publish folderCreated event - publishDriveStream(user.id, 'folderCreated', folderObj); + publishDriveStream(user.id, "folderCreated", folderObj); return folderObj; }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts index ab9d411ec..98895a732 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts @@ -1,39 +1,38 @@ -import define from '../../../define.js'; -import { publishDriveStream } from '@/services/stream.js'; -import { ApiError } from '../../../error.js'; -import { DriveFolders, DriveFiles } from '@/models/index.js'; +import define from "../../../define.js"; +import { publishDriveStream } from "@/services/stream.js"; +import { ApiError } from "../../../error.js"; +import { DriveFolders, DriveFiles } from "@/models/index.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'write:drive', + kind: "write:drive", errors: { noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: '1069098f-c281-440f-b085-f9932edbe091', + message: "No such folder.", + code: "NO_SUCH_FOLDER", + id: "1069098f-c281-440f-b085-f9932edbe091", }, hasChildFilesOrFolders: { - message: 'This folder has child files or folders.', - code: 'HAS_CHILD_FILES_OR_FOLDERS', - id: 'b0fc8a17-963c-405d-bfbc-859a487295e1', + message: "This folder has child files or folders.", + code: "HAS_CHILD_FILES_OR_FOLDERS", + id: "b0fc8a17-963c-405d-bfbc-859a487295e1", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - folderId: { type: 'string', format: 'misskey:id' }, + folderId: { type: "string", format: "misskey:id" }, }, - required: ['folderId'], + required: ["folderId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get folder const folder = await DriveFolders.findOneBy({ @@ -57,5 +56,5 @@ export default define(meta, paramDef, async (ps, user) => { await DriveFolders.delete(folder.id); // Publish folderCreated event - publishDriveStream(user.id, 'folderDeleted', folder.id); + publishDriveStream(user.id, "folderDeleted", folder.id); }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/find.ts b/packages/backend/src/server/api/endpoints/drive/folders/find.ts index 1feab273a..45451fb90 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/find.ts @@ -1,35 +1,41 @@ -import define from '../../../define.js'; -import { DriveFolders } from '@/models/index.js'; -import { IsNull } from 'typeorm'; +import define from "../../../define.js"; +import { DriveFolders } from "@/models/index.js"; +import { IsNull } from "typeorm"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFolder', + type: "object", + optional: false, + nullable: false, + ref: "DriveFolder", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string' }, - parentId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + name: { type: "string" }, + parentId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const folders = await DriveFolders.findBy({ name: ps.name, @@ -37,5 +43,5 @@ export default define(meta, paramDef, async (ps, user) => { parentId: ps.parentId ?? IsNull(), }); - return await Promise.all(folders.map(folder => DriveFolders.pack(folder))); + return await Promise.all(folders.map((folder) => DriveFolders.pack(folder))); }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/show.ts b/packages/backend/src/server/api/endpoints/drive/folders/show.ts index 1e7aa2b16..6a72a2277 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/show.ts @@ -1,38 +1,38 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { DriveFolders } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { DriveFolders } from "@/models/index.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFolder', + type: "object", + optional: false, + nullable: false, + ref: "DriveFolder", }, errors: { noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: 'd74ab9eb-bb09-4bba-bf24-fb58f761e1e9', + message: "No such folder.", + code: "NO_SUCH_FOLDER", + id: "d74ab9eb-bb09-4bba-bf24-fb58f761e1e9", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - folderId: { type: 'string', format: 'misskey:id' }, + folderId: { type: "string", format: "misskey:id" }, }, - required: ['folderId'], + required: ["folderId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get folder const folder = await DriveFolders.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts index 1aa2e8429..929a69bde 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts @@ -1,53 +1,53 @@ -import { publishDriveStream } from '@/services/stream.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { DriveFolders } from '@/models/index.js'; +import { publishDriveStream } from "@/services/stream.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { DriveFolders } from "@/models/index.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'write:drive', + kind: "write:drive", errors: { noSuchFolder: { - message: 'No such folder.', - code: 'NO_SUCH_FOLDER', - id: 'f7974dac-2c0d-4a27-926e-23583b28e98e', + message: "No such folder.", + code: "NO_SUCH_FOLDER", + id: "f7974dac-2c0d-4a27-926e-23583b28e98e", }, noSuchParentFolder: { - message: 'No such parent folder.', - code: 'NO_SUCH_PARENT_FOLDER', - id: 'ce104e3a-faaf-49d5-b459-10ff0cbbcaa1', + message: "No such parent folder.", + code: "NO_SUCH_PARENT_FOLDER", + id: "ce104e3a-faaf-49d5-b459-10ff0cbbcaa1", }, recursiveNesting: { - message: 'It can not be structured like nesting folders recursively.', - code: 'NO_SUCH_PARENT_FOLDER', - id: 'ce104e3a-faaf-49d5-b459-10ff0cbbcaa1', + message: "It can not be structured like nesting folders recursively.", + code: "NO_SUCH_PARENT_FOLDER", + id: "ce104e3a-faaf-49d5-b459-10ff0cbbcaa1", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFolder', + type: "object", + optional: false, + nullable: false, + ref: "DriveFolder", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - folderId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', maxLength: 200 }, - parentId: { type: 'string', format: 'misskey:id', nullable: true }, + folderId: { type: "string", format: "misskey:id" }, + name: { type: "string", maxLength: 200 }, + parentId: { type: "string", format: "misskey:id", nullable: true }, }, - required: ['folderId'], + required: ["folderId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch folder const folder = await DriveFolders.findOneBy({ @@ -112,7 +112,7 @@ export default define(meta, paramDef, async (ps, user) => { const folderObj = await DriveFolders.pack(folder); // Publish folderUpdated event - publishDriveStream(user.id, 'folderUpdated', folderObj); + publishDriveStream(user.id, "folderUpdated", folderObj); return folderObj; }); diff --git a/packages/backend/src/server/api/endpoints/drive/stream.ts b/packages/backend/src/server/api/endpoints/drive/stream.ts index 99e8d024f..0c9654ca2 100644 --- a/packages/backend/src/server/api/endpoints/drive/stream.ts +++ b/packages/backend/src/server/api/endpoints/drive/stream.ts @@ -1,46 +1,55 @@ -import define from '../../define.js'; -import { DriveFiles } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { DriveFiles } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['drive'], + tags: ["drive"], requireCredential: true, - kind: 'read:drive', + kind: "read:drive", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'DriveFile', + type: "object", + optional: false, + nullable: false, + ref: "DriveFile", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - type: { type: 'string', pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + type: { + type: "string", + pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1), + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId) - .andWhere('file.userId = :userId', { userId: user.id }); + const query = makePaginationQuery( + DriveFiles.createQueryBuilder("file"), + ps.sinceId, + ps.untilId, + ).andWhere("file.userId = :userId", { userId: user.id }); if (ps.type) { - if (ps.type.endsWith('/*')) { - query.andWhere('file.type like :type', { type: ps.type.replace('/*', '/') + '%' }); + if (ps.type.endsWith("/*")) { + query.andWhere("file.type like :type", { + type: `${ps.type.replace("/*", "/")}%`, + }); } else { - query.andWhere('file.type = :type', { type: ps.type }); + query.andWhere("file.type = :type", { type: ps.type }); } } diff --git a/packages/backend/src/server/api/endpoints/email-address/available.ts b/packages/backend/src/server/api/endpoints/email-address/available.ts index 07064ce9f..dc3c5e4b8 100644 --- a/packages/backend/src/server/api/endpoints/email-address/available.ts +++ b/packages/backend/src/server/api/endpoints/email-address/available.ts @@ -1,36 +1,38 @@ -import define from '../../define.js'; -import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; +import define from "../../define.js"; +import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { available: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, reason: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - emailAddress: { type: 'string' }, + emailAddress: { type: "string" }, }, - required: ['emailAddress'], + required: ["emailAddress"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { return await validateEmailForAccount(ps.emailAddress); }); diff --git a/packages/backend/src/server/api/endpoints/endpoint.ts b/packages/backend/src/server/api/endpoints/endpoint.ts index c17412677..ad0ce4562 100644 --- a/packages/backend/src/server/api/endpoints/endpoint.ts +++ b/packages/backend/src/server/api/endpoints/endpoint.ts @@ -1,23 +1,22 @@ -import define from '../define.js'; -import endpoints from '../endpoints.js'; +import define from "../define.js"; +import endpoints from "../endpoints.js"; export const meta = { requireCredential: false, - tags: ['meta'], + tags: ["meta"], } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - endpoint: { type: 'string' }, + endpoint: { type: "string" }, }, - required: ['endpoint'], + required: ["endpoint"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const ep = endpoints.find(x => x.name === ps.endpoint); + const ep = endpoints.find((x) => x.name === ps.endpoint); if (ep == null) return null; return { params: Object.entries(ep.params.properties || {}).map(([k, v]) => ({ diff --git a/packages/backend/src/server/api/endpoints/endpoints.ts b/packages/backend/src/server/api/endpoints/endpoints.ts index b20da96eb..c5844f843 100644 --- a/packages/backend/src/server/api/endpoints/endpoints.ts +++ b/packages/backend/src/server/api/endpoints/endpoints.ts @@ -1,34 +1,35 @@ -import define from '../define.js'; -import endpoints from '../endpoints.js'; +import define from "../define.js"; +import endpoints from "../endpoints.js"; export const meta = { requireCredential: false, - tags: ['meta'], + tags: ["meta"], res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, example: [ - 'admin/abuse-user-reports', - 'admin/accounts/create', - 'admin/announcements/create', - '...', + "admin/abuse-user-reports", + "admin/accounts/create", + "admin/announcements/create", + "...", ], }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { - return endpoints.map(x => x.name); + return endpoints.map((x) => x.name); }); diff --git a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts index 3dc9d4e9f..f4fc43c17 100644 --- a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts +++ b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts @@ -1,6 +1,6 @@ -import { createExportCustomEmojisJob } from '@/queue/index.js'; -import define from '../define.js'; -import { HOUR } from '@/const.js'; +import { createExportCustomEmojisJob } from "@/queue/index.js"; +import define from "../define.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -12,12 +12,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportCustomEmojisJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts index 01df3939e..4c6d83abd 100644 --- a/packages/backend/src/server/api/endpoints/federation/followers.ts +++ b/packages/backend/src/server/api/endpoints/federation/followers.ts @@ -1,44 +1,46 @@ -import define from '../../define.js'; -import { Followings } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Followings } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, requireAdmin: true, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', + type: "object", + optional: false, + nullable: false, + ref: "Following", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + host: { type: "string" }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followeeHost = :host`, { host: ps.host }); + const query = makePaginationQuery( + Followings.createQueryBuilder("following"), + ps.sinceId, + ps.untilId, + ).andWhere("following.followeeHost = :host", { host: ps.host }); - const followings = await query - .take(ps.limit) - .getMany(); + const followings = await query.take(ps.limit).getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); }); diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts index 17abf2e12..88b168600 100644 --- a/packages/backend/src/server/api/endpoints/federation/following.ts +++ b/packages/backend/src/server/api/endpoints/federation/following.ts @@ -1,44 +1,46 @@ -import define from '../../define.js'; -import { Followings } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Followings } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, requireAdmin: true, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', + type: "object", + optional: false, + nullable: false, + ref: "Following", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + host: { type: "string" }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followerHost = :host`, { host: ps.host }); + const query = makePaginationQuery( + Followings.createQueryBuilder("following"), + ps.sinceId, + ps.untilId, + ).andWhere("following.followerHost = :host", { host: ps.host }); - const followings = await query - .take(ps.limit) - .getMany(); + const followings = await query.take(ps.limit).getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); }); diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 41750f13e..3ab37ff6f 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,116 +1,165 @@ -import config from '@/config/index.js'; -import define from '../../define.js'; -import { Instances } from '@/models/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import config from "@/config/index.js"; +import define from "../../define.js"; +import { Instances } from "@/models/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'FederationInstance', + type: "object", + optional: false, + nullable: false, + ref: "FederationInstance", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string', nullable: true, description: 'Omit or use `null` to not filter by host.' }, - blocked: { type: 'boolean', nullable: true }, - notResponding: { type: 'boolean', nullable: true }, - suspended: { type: 'boolean', nullable: true }, - federating: { type: 'boolean', nullable: true }, - subscribing: { type: 'boolean', nullable: true }, - publishing: { type: 'boolean', nullable: true }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, - offset: { type: 'integer', default: 0 }, - sort: { type: 'string' }, + host: { + type: "string", + nullable: true, + description: "Omit or use `null` to not filter by host.", + }, + blocked: { type: "boolean", nullable: true }, + notResponding: { type: "boolean", nullable: true }, + suspended: { type: "boolean", nullable: true }, + federating: { type: "boolean", nullable: true }, + subscribing: { type: "boolean", nullable: true }, + publishing: { type: "boolean", nullable: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 30 }, + offset: { type: "integer", default: 0 }, + sort: { type: "string" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Instances.createQueryBuilder('instance'); + const query = Instances.createQueryBuilder("instance"); switch (ps.sort) { - case '+pubSub': query.orderBy('instance.followingCount', 'DESC').orderBy('instance.followersCount', 'DESC'); break; - case '-pubSub': query.orderBy('instance.followingCount', 'ASC').orderBy('instance.followersCount', 'ASC'); break; - case '+notes': query.orderBy('instance.notesCount', 'DESC'); break; - case '-notes': query.orderBy('instance.notesCount', 'ASC'); break; - case '+users': query.orderBy('instance.usersCount', 'DESC'); break; - case '-users': query.orderBy('instance.usersCount', 'ASC'); break; - case '+following': query.orderBy('instance.followingCount', 'DESC'); break; - case '-following': query.orderBy('instance.followingCount', 'ASC'); break; - case '+followers': query.orderBy('instance.followersCount', 'DESC'); break; - case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; - case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; - case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; - case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; - case '-lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'ASC'); break; + case "+pubSub": + query + .orderBy("instance.followingCount", "DESC") + .orderBy("instance.followersCount", "DESC"); + break; + case "-pubSub": + query + .orderBy("instance.followingCount", "ASC") + .orderBy("instance.followersCount", "ASC"); + break; + case "+notes": + query.orderBy("instance.notesCount", "DESC"); + break; + case "-notes": + query.orderBy("instance.notesCount", "ASC"); + break; + case "+users": + query.orderBy("instance.usersCount", "DESC"); + break; + case "-users": + query.orderBy("instance.usersCount", "ASC"); + break; + case "+following": + query.orderBy("instance.followingCount", "DESC"); + break; + case "-following": + query.orderBy("instance.followingCount", "ASC"); + break; + case "+followers": + query.orderBy("instance.followersCount", "DESC"); + break; + case "-followers": + query.orderBy("instance.followersCount", "ASC"); + break; + case "+caughtAt": + query.orderBy("instance.caughtAt", "DESC"); + break; + case "-caughtAt": + query.orderBy("instance.caughtAt", "ASC"); + break; + case "+lastCommunicatedAt": + query.orderBy("instance.lastCommunicatedAt", "DESC"); + break; + case "-lastCommunicatedAt": + query.orderBy("instance.lastCommunicatedAt", "ASC"); + break; - default: query.orderBy('instance.id', 'DESC'); break; + default: + query.orderBy("instance.id", "DESC"); + break; } - if (typeof ps.blocked === 'boolean') { + if (typeof ps.blocked === "boolean") { const meta = await fetchMeta(true); if (ps.blocked) { - query.andWhere('instance.host IN (:...blocks)', { blocks: meta.blockedHosts }); + query.andWhere("instance.host IN (:...blocks)", { + blocks: meta.blockedHosts, + }); } else { - query.andWhere('instance.host NOT IN (:...blocks)', { blocks: meta.blockedHosts }); + query.andWhere("instance.host NOT IN (:...blocks)", { + blocks: meta.blockedHosts, + }); } } - if (typeof ps.notResponding === 'boolean') { + if (typeof ps.notResponding === "boolean") { if (ps.notResponding) { - query.andWhere('instance.isNotResponding = TRUE'); + query.andWhere("instance.isNotResponding = TRUE"); } else { - query.andWhere('instance.isNotResponding = FALSE'); + query.andWhere("instance.isNotResponding = FALSE"); } } - if (typeof ps.suspended === 'boolean') { + if (typeof ps.suspended === "boolean") { if (ps.suspended) { - query.andWhere('instance.isSuspended = TRUE'); + query.andWhere("instance.isSuspended = TRUE"); } else { - query.andWhere('instance.isSuspended = FALSE'); + query.andWhere("instance.isSuspended = FALSE"); } } - if (typeof ps.federating === 'boolean') { + if (typeof ps.federating === "boolean") { if (ps.federating) { - query.andWhere('((instance.followingCount > 0) OR (instance.followersCount > 0))'); + query.andWhere( + "((instance.followingCount > 0) OR (instance.followersCount > 0))", + ); } else { - query.andWhere('((instance.followingCount = 0) AND (instance.followersCount = 0))'); + query.andWhere( + "((instance.followingCount = 0) AND (instance.followersCount = 0))", + ); } } - if (typeof ps.subscribing === 'boolean') { + if (typeof ps.subscribing === "boolean") { if (ps.subscribing) { - query.andWhere('instance.followersCount > 0'); + query.andWhere("instance.followersCount > 0"); } else { - query.andWhere('instance.followersCount = 0'); + query.andWhere("instance.followersCount = 0"); } } - if (typeof ps.publishing === 'boolean') { + if (typeof ps.publishing === "boolean") { if (ps.publishing) { - query.andWhere('instance.followingCount > 0'); + query.andWhere("instance.followingCount > 0"); } else { - query.andWhere('instance.followingCount = 0'); + query.andWhere("instance.followingCount = 0"); } } if (ps.host) { - query.andWhere('instance.host like :host', { host: '%' + ps.host.toLowerCase() + '%' }); + query.andWhere("instance.host like :host", { + host: `%${ps.host.toLowerCase()}%`, + }); } const instances = await query.take(ps.limit).skip(ps.offset).getMany(); diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 8e6c59fc8..633bb5707 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -1,35 +1,36 @@ -import define from '../../define.js'; -import { Instances } from '@/models/index.js'; -import { toPuny } from '@/misc/convert-host.js'; +import define from "../../define.js"; +import { Instances } from "@/models/index.js"; +import { toPuny } from "@/misc/convert-host.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, requireCredentialPrivateMode: true, res: { - oneOf: [{ - type: 'object', - ref: 'FederationInstance', - }, { - type: 'null', - }], + oneOf: [ + { + type: "object", + ref: "FederationInstance", + }, + { + type: "null", + }, + ], }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, + host: { type: "string" }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const instance = await Instances - .findOneBy({ host: toPuny(ps.host) }); + const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); return instance ? await Instances.pack(instance) : null; }); diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index e02c7b97e..ede7a56c2 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -1,10 +1,10 @@ -import { IsNull, MoreThan, Not } from 'typeorm'; -import { Followings, Instances } from '@/models/index.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import define from '../../define.js'; +import { IsNull, MoreThan, Not } from "typeorm"; +import { Followings, Instances } from "@/models/index.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import define from "../../define.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: false, @@ -13,48 +13,52 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const [topSubInstances, topPubInstances, allSubCount, allPubCount] = await Promise.all([ - Instances.find({ - where: { - followersCount: MoreThan(0), - }, - order: { - followersCount: 'DESC', - }, - take: ps.limit, - }), - Instances.find({ - where: { - followingCount: MoreThan(0), - }, - order: { - followingCount: 'DESC', - }, - take: ps.limit, - }), - Followings.count({ - where: { - followeeHost: Not(IsNull()), - }, - }), - Followings.count({ - where: { - followerHost: Not(IsNull()), - }, - }), - ]); + const [topSubInstances, topPubInstances, allSubCount, allPubCount] = + await Promise.all([ + Instances.find({ + where: { + followersCount: MoreThan(0), + }, + order: { + followersCount: "DESC", + }, + take: ps.limit, + }), + Instances.find({ + where: { + followingCount: MoreThan(0), + }, + order: { + followingCount: "DESC", + }, + take: ps.limit, + }), + Followings.count({ + where: { + followeeHost: Not(IsNull()), + }, + }), + Followings.count({ + where: { + followerHost: Not(IsNull()), + }, + }), + ]); - const gotSubCount = topSubInstances.map(x => x.followersCount).reduce((a, b) => a + b, 0); - const gotPubCount = topPubInstances.map(x => x.followingCount).reduce((a, b) => a + b, 0); + const gotSubCount = topSubInstances + .map((x) => x.followersCount) + .reduce((a, b) => a + b, 0); + const gotPubCount = topPubInstances + .map((x) => x.followingCount) + .reduce((a, b) => a + b, 0); return await awaitAll({ topSubInstances: Instances.packMany(topSubInstances), diff --git a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts index 409cc7695..f4c3f6d18 100644 --- a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts +++ b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts @@ -1,22 +1,21 @@ -import define from '../../define.js'; -import { getRemoteUser } from '../../common/getters.js'; -import { updatePerson } from '@/remote/activitypub/models/person.js'; +import define from "../../define.js"; +import { getRemoteUser } from "../../common/getters.js"; +import { updatePerson } from "@/remote/activitypub/models/person.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await getRemoteUser(ps.userId); await updatePerson(user.uri!); diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts index a9b3f3a8c..ded0a26c5 100644 --- a/packages/backend/src/server/api/endpoints/federation/users.ts +++ b/packages/backend/src/server/api/endpoints/federation/users.ts @@ -1,43 +1,45 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['federation'], + tags: ["federation"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailedNotMe", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + host: { type: "string" }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, - required: ['host'], + required: ["host"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Users.createQueryBuilder('user'), ps.sinceId, ps.untilId) - .andWhere(`user.host = :host`, { host: ps.host }); + const query = makePaginationQuery( + Users.createQueryBuilder("user"), + ps.sinceId, + ps.untilId, + ).andWhere("user.host = :host", { host: ps.host }); - const users = await query - .take(ps.limit) - .getMany(); + const users = await query.take(ps.limit).getMany(); return await Users.packMany(users, me, { detail: true }); }); diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index 05fa22a9e..b73d7262c 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -1,12 +1,12 @@ -import Parser from 'rss-parser'; -import { getResponse } from '@/misc/fetch.js'; -import config from '@/config/index.js'; -import define from '../define.js'; +import Parser from "rss-parser"; +import { getResponse } from "@/misc/fetch.js"; +import config from "@/config/index.js"; +import define from "../define.js"; const rssParser = new Parser(); export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, allowGet: true, @@ -14,21 +14,20 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - url: { type: 'string' }, + url: { type: "string" }, }, - required: ['url'], + required: ["url"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const res = await getResponse({ url: ps.url, - method: 'GET', + method: "GET", headers: Object.assign({ - 'User-Agent': config.userAgent, - Accept: 'application/rss+xml, */*', + "User-Agent": config.userAgent, + Accept: "application/rss+xml, */*", }), timeout: 5000, }); diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index 3a12a55b8..e617c1ffb 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -1,13 +1,13 @@ -import create from '@/services/following/create.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Followings, Users } from '@/models/index.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { HOUR } from '@/const.js'; +import create from "@/services/following/create.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Followings, Users } from "@/models/index.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['following', 'users'], + tags: ["following", "users"], limit: { duration: HOUR, @@ -16,56 +16,56 @@ export const meta = { requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5', + message: "No such user.", + code: "NO_SUCH_USER", + id: "fcd2eef9-a9b2-4c4f-8624-038099e90aa5", }, followeeIsYourself: { - message: 'Followee is yourself.', - code: 'FOLLOWEE_IS_YOURSELF', - id: '26fbe7bb-a331-4857-af17-205b426669a9', + message: "Followee is yourself.", + code: "FOLLOWEE_IS_YOURSELF", + id: "26fbe7bb-a331-4857-af17-205b426669a9", }, alreadyFollowing: { - message: 'You are already following that user.', - code: 'ALREADY_FOLLOWING', - id: '35387507-38c7-4cb9-9197-300b93783fa0', + message: "You are already following that user.", + code: "ALREADY_FOLLOWING", + id: "35387507-38c7-4cb9-9197-300b93783fa0", }, blocking: { - message: 'You are blocking that user.', - code: 'BLOCKING', - id: '4e2206ec-aa4f-4960-b865-6c23ac38e2d9', + message: "You are blocking that user.", + code: "BLOCKING", + id: "4e2206ec-aa4f-4960-b865-6c23ac38e2d9", }, blocked: { - message: 'You are blocked by that user.', - code: 'BLOCKED', - id: 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0', + message: "You are blocked by that user.", + code: "BLOCKED", + id: "c4ab57cc-4e41-45e9-bfd9-584f61e35ce0", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const follower = user; @@ -75,8 +75,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get followee - const followee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const followee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -94,8 +95,10 @@ export default define(meta, paramDef, async (ps, user) => { await create(follower, followee); } catch (e) { if (e instanceof IdentifiableError) { - if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); - if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked); + if (e.id === "710e8fb0-b8c3-4922-be49-d5d93d8e6a6e") + throw new ApiError(meta.errors.blocking); + if (e.id === "3338392a-f764-498d-8855-db939dcf8c48") + throw new ApiError(meta.errors.blocked); } throw e; } diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts index a454f2d72..2eebe8a90 100644 --- a/packages/backend/src/server/api/endpoints/following/delete.ts +++ b/packages/backend/src/server/api/endpoints/following/delete.ts @@ -1,12 +1,12 @@ -import deleteFollowing from '@/services/following/delete.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Followings, Users } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import deleteFollowing from "@/services/following/delete.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Followings, Users } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['following', 'users'], + tags: ["following", "users"], limit: { duration: HOUR, @@ -15,44 +15,44 @@ export const meta = { requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '5b12c78d-2b28-4dca-99d2-f56139b42ff8', + message: "No such user.", + code: "NO_SUCH_USER", + id: "5b12c78d-2b28-4dca-99d2-f56139b42ff8", }, followeeIsYourself: { - message: 'Followee is yourself.', - code: 'FOLLOWEE_IS_YOURSELF', - id: 'd9e400b9-36b0-4808-b1d8-79e707f1296c', + message: "Followee is yourself.", + code: "FOLLOWEE_IS_YOURSELF", + id: "d9e400b9-36b0-4808-b1d8-79e707f1296c", }, notFollowing: { - message: 'You are not following that user.', - code: 'NOT_FOLLOWING', - id: '5dbf82f5-c92b-40b1-87d1-6c8c0741fd09', + message: "You are not following that user.", + code: "NOT_FOLLOWING", + id: "5dbf82f5-c92b-40b1-87d1-6c8c0741fd09", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const follower = user; @@ -62,8 +62,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get followee - const followee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const followee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts index cf3a21406..979d298f7 100644 --- a/packages/backend/src/server/api/endpoints/following/invalidate.ts +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -1,12 +1,12 @@ -import deleteFollowing from '@/services/following/delete.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Followings, Users } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import deleteFollowing from "@/services/following/delete.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Followings, Users } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['following', 'users'], + tags: ["following", "users"], limit: { duration: HOUR, @@ -15,44 +15,44 @@ export const meta = { requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '5b12c78d-2b28-4dca-99d2-f56139b42ff8', + message: "No such user.", + code: "NO_SUCH_USER", + id: "5b12c78d-2b28-4dca-99d2-f56139b42ff8", }, followerIsYourself: { - message: 'Follower is yourself.', - code: 'FOLLOWER_IS_YOURSELF', - id: '07dc03b9-03da-422d-885b-438313707662', + message: "Follower is yourself.", + code: "FOLLOWER_IS_YOURSELF", + id: "07dc03b9-03da-422d-885b-438313707662", }, notFollowing: { - message: 'The other use is not following you.', - code: 'NOT_FOLLOWING', - id: '5dbf82f5-c92b-40b1-87d1-6c8c0741fd09', + message: "The other use is not following you.", + code: "NOT_FOLLOWING", + id: "5dbf82f5-c92b-40b1-87d1-6c8c0741fd09", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const followee = user; @@ -62,8 +62,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get follower - const follower = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const follower = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/following/requests/accept.ts b/packages/backend/src/server/api/endpoints/following/requests/accept.ts index e5df55375..a4fc05236 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/accept.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/accept.ts @@ -1,47 +1,48 @@ -import acceptFollowRequest from '@/services/following/requests/accept.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import acceptFollowRequest from "@/services/following/requests/accept.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['following', 'account'], + tags: ["following", "account"], requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '66ce1645-d66c-46bb-8b79-96739af885bd', + message: "No such user.", + code: "NO_SUCH_USER", + id: "66ce1645-d66c-46bb-8b79-96739af885bd", }, noFollowRequest: { - message: 'No follow request.', - code: 'NO_FOLLOW_REQUEST', - id: 'bcde4f8b-0913-4614-8881-614e522fb041', + message: "No follow request.", + code: "NO_FOLLOW_REQUEST", + id: "bcde4f8b-0913-4614-8881-614e522fb041", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch follower - const follower = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const follower = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); - await acceptFollowRequest(user, follower).catch(e => { - if (e.id === '8884c2dd-5795-4ac9-b27e-6a01d38190f9') throw new ApiError(meta.errors.noFollowRequest); + await acceptFollowRequest(user, follower).catch((e) => { + if (e.id === "8884c2dd-5795-4ac9-b27e-6a01d38190f9") + throw new ApiError(meta.errors.noFollowRequest); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts index 80d37fb07..f309e3299 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts @@ -1,51 +1,52 @@ -import cancelFollowRequest from '@/services/following/requests/cancel.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; -import { Users } from '@/models/index.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import cancelFollowRequest from "@/services/following/requests/cancel.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; +import { Users } from "@/models/index.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; export const meta = { - tags: ['following', 'account'], + tags: ["following", "account"], requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '4e68c551-fc4c-4e46-bb41-7d4a37bf9dab', + message: "No such user.", + code: "NO_SUCH_USER", + id: "4e68c551-fc4c-4e46-bb41-7d4a37bf9dab", }, followRequestNotFound: { - message: 'Follow request not found.', - code: 'FOLLOW_REQUEST_NOT_FOUND', - id: '089b125b-d338-482a-9a09-e2622ac9f8d4', + message: "Follow request not found.", + code: "FOLLOW_REQUEST_NOT_FOUND", + id: "089b125b-d338-482a-9a09-e2622ac9f8d4", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch followee - const followee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const followee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -53,7 +54,8 @@ export default define(meta, paramDef, async (ps, user) => { await cancelFollowRequest(followee, user); } catch (e) { if (e instanceof IdentifiableError) { - if (e.id === '17447091-ce07-46dd-b331-c1fd4f15b1e7') throw new ApiError(meta.errors.followRequestNotFound); + if (e.id === "17447091-ce07-46dd-b331-c1fd4f15b1e7") + throw new ApiError(meta.errors.followRequestNotFound); } throw e; } diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts index a8f42c481..6ba23de58 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/list.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts @@ -1,34 +1,39 @@ -import define from '../../../define.js'; -import { FollowRequests } from '@/models/index.js'; +import define from "../../../define.js"; +import { FollowRequests } from "@/models/index.js"; export const meta = { - tags: ['following', 'account'], + tags: ["following", "account"], requireCredential: true, - kind: 'read:following', + kind: "read:following", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, follower: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, followee: { - type: 'object', - optional: false, nullable: false, - ref: 'UserLite', + type: "object", + optional: false, + nullable: false, + ref: "UserLite", }, }, }, @@ -36,16 +41,15 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const reqs = await FollowRequests.findBy({ followeeId: user.id, }); - return await Promise.all(reqs.map(req => FollowRequests.pack(req))); + return await Promise.all(reqs.map((req) => FollowRequests.pack(req))); }); diff --git a/packages/backend/src/server/api/endpoints/following/requests/reject.ts b/packages/backend/src/server/api/endpoints/following/requests/reject.ts index cebe60428..fedc0db48 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/reject.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/reject.ts @@ -1,37 +1,37 @@ -import { rejectFollowRequest } from '@/services/following/reject.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import { rejectFollowRequest } from "@/services/following/reject.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['following', 'account'], + tags: ["following", "account"], requireCredential: true, - kind: 'write:following', + kind: "write:following", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'abc2ffa6-25b2-4380-ba99-321ff3a94555', + message: "No such user.", + code: "NO_SUCH_USER", + id: "abc2ffa6-25b2-4380-ba99-321ff3a94555", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch follower - const follower = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const follower = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts index 52232c5cc..d478e8e3b 100644 --- a/packages/backend/src/server/api/endpoints/gallery/featured.ts +++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts @@ -1,35 +1,38 @@ -import define from '../../define.js'; -import { GalleryPosts } from '@/models/index.js'; +import define from "../../define.js"; +import { GalleryPosts } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = GalleryPosts.createQueryBuilder('post') - .andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) }) - .andWhere('post.likedCount > 0') - .orderBy('post.likedCount', 'DESC'); + const query = GalleryPosts.createQueryBuilder("post") + .andWhere("post.createdAt > :date", { + date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3), + }) + .andWhere("post.likedCount > 0") + .orderBy("post.likedCount", "DESC"); const posts = await query.take(10).getMany(); diff --git a/packages/backend/src/server/api/endpoints/gallery/popular.ts b/packages/backend/src/server/api/endpoints/gallery/popular.ts index 5286dcd8b..5eef68d97 100644 --- a/packages/backend/src/server/api/endpoints/gallery/popular.ts +++ b/packages/backend/src/server/api/endpoints/gallery/popular.ts @@ -1,34 +1,35 @@ -import define from '../../define.js'; -import { GalleryPosts } from '@/models/index.js'; +import define from "../../define.js"; +import { GalleryPosts } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = GalleryPosts.createQueryBuilder('post') - .andWhere('post.likedCount > 0') - .orderBy('post.likedCount', 'DESC'); + const query = GalleryPosts.createQueryBuilder("post") + .andWhere("post.likedCount > 0") + .orderBy("post.likedCount", "DESC"); const posts = await query.take(10).getMany(); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts.ts b/packages/backend/src/server/api/endpoints/gallery/posts.ts index f556ec513..f97c161af 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts.ts @@ -1,36 +1,40 @@ -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { GalleryPosts } from '@/models/index.js'; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { GalleryPosts } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) - .innerJoinAndSelect('post.user', 'user'); + const query = makePaginationQuery( + GalleryPosts.createQueryBuilder("post"), + ps.sinceId, + ps.untilId, + ).innerJoinAndSelect("post.user", "user"); const posts = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index eec4d2ba1..f3b3768e2 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -1,17 +1,17 @@ -import define from '../../../define.js'; -import { DriveFiles, GalleryPosts } from '@/models/index.js'; -import { genId } from '../../../../../misc/gen-id.js'; -import { GalleryPost } from '@/models/entities/gallery-post.js'; -import { ApiError } from '../../../error.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { HOUR } from '@/const.js'; +import define from "../../../define.js"; +import { DriveFiles, GalleryPosts } from "@/models/index.js"; +import { genId } from "../../../../../misc/gen-id.js"; +import { GalleryPost } from "@/models/entities/gallery-post.js"; +import { ApiError } from "../../../error.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: true, - kind: 'write:gallery', + kind: "write:gallery", limit: { duration: HOUR, @@ -19,52 +19,63 @@ export const meta = { }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, - errors: { - - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - title: { type: 'string', minLength: 1 }, - description: { type: 'string', nullable: true }, - fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: { - type: 'string', format: 'misskey:id', - } }, - isSensitive: { type: 'boolean', default: false }, + title: { type: "string", minLength: 1 }, + description: { type: "string", nullable: true }, + fileIds: { + type: "array", + uniqueItems: true, + minItems: 1, + maxItems: 32, + items: { + type: "string", + format: "misskey:id", + }, + }, + isSensitive: { type: "boolean", default: false }, }, - required: ['title', 'fileIds'], + required: ["title", "fileIds"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const files = (await Promise.all(ps.fileIds.map(fileId => - DriveFiles.findOneBy({ - id: fileId, - userId: user.id, - }) - ))).filter((file): file is DriveFile => file != null); + const files = ( + await Promise.all( + ps.fileIds.map((fileId) => + DriveFiles.findOneBy({ + id: fileId, + userId: user.id, + }), + ), + ) + ).filter((file): file is DriveFile => file != null); if (files.length === 0) { throw new Error(); } - const post = await GalleryPosts.insert(new GalleryPost({ - id: genId(), - createdAt: new Date(), - updatedAt: new Date(), - title: ps.title, - description: ps.description, - userId: user.id, - isSensitive: ps.isSensitive, - fileIds: files.map(file => file.id), - })).then(x => GalleryPosts.findOneByOrFail(x.identifiers[0])); + const post = await GalleryPosts.insert( + new GalleryPost({ + id: genId(), + createdAt: new Date(), + updatedAt: new Date(), + title: ps.title, + description: ps.description, + userId: user.id, + isSensitive: ps.isSensitive, + fileIds: files.map((file) => file.id), + }), + ).then((x) => GalleryPosts.findOneByOrFail(x.identifiers[0])); return await GalleryPosts.pack(post, user); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts index b00ee0e2a..9fd9a5009 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts @@ -1,32 +1,31 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { GalleryPosts } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { GalleryPosts } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: true, - kind: 'write:gallery', + kind: "write:gallery", errors: { noSuchPost: { - message: 'No such post.', - code: 'NO_SUCH_POST', - id: 'ae52f367-4bd7-4ecd-afc6-5672fff427f5', + message: "No such post.", + code: "NO_SUCH_POST", + id: "ae52f367-4bd7-4ecd-afc6-5672fff427f5", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - postId: { type: 'string', format: 'misskey:id' }, + postId: { type: "string", format: "misskey:id" }, }, - required: ['postId'], + required: ["postId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOneBy({ id: ps.postId, diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index 9e722e71c..fd46406bd 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -1,39 +1,38 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { GalleryPosts, GalleryLikes } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { GalleryPosts, GalleryLikes } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: true, - kind: 'write:gallery-likes', + kind: "write:gallery-likes", errors: { noSuchPost: { - message: 'No such post.', - code: 'NO_SUCH_POST', - id: '56c06af3-1287-442f-9701-c93f7c4a62ff', + message: "No such post.", + code: "NO_SUCH_POST", + id: "56c06af3-1287-442f-9701-c93f7c4a62ff", }, alreadyLiked: { - message: 'The post has already been liked.', - code: 'ALREADY_LIKED', - id: '40e9ed56-a59c-473a-bf3f-f289c54fb5a7', + message: "The post has already been liked.", + code: "ALREADY_LIKED", + id: "40e9ed56-a59c-473a-bf3f-f289c54fb5a7", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - postId: { type: 'string', format: 'misskey:id' }, + postId: { type: "string", format: "misskey:id" }, }, - required: ['postId'], + required: ["postId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOneBy({ id: ps.postId }); if (post == null) { @@ -58,5 +57,5 @@ export default define(meta, paramDef, async (ps, user) => { userId: user.id, }); - GalleryPosts.increment({ id: post.id }, 'likedCount', 1); + GalleryPosts.increment({ id: post.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts index 48468f410..87e272f01 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts @@ -1,37 +1,37 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { GalleryPosts } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { GalleryPosts } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: false, requireCredentialPrivateMode: true, errors: { noSuchPost: { - message: 'No such post.', - code: 'NO_SUCH_POST', - id: '1137bf14-c5b0-4604-85bb-5b5371b1cd45', + message: "No such post.", + code: "NO_SUCH_POST", + id: "1137bf14-c5b0-4604-85bb-5b5371b1cd45", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - postId: { type: 'string', format: 'misskey:id' }, + postId: { type: "string", format: "misskey:id" }, }, - required: ['postId'], + required: ["postId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const post = await GalleryPosts.findOneBy({ id: ps.postId, diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index d136239e5..772dc9202 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -1,38 +1,37 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { GalleryPosts, GalleryLikes } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { GalleryPosts, GalleryLikes } from "@/models/index.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: true, - kind: 'write:gallery-likes', + kind: "write:gallery-likes", errors: { noSuchPost: { - message: 'No such post.', - code: 'NO_SUCH_POST', - id: 'c32e6dd0-b555-4413-925e-b3757d19ed84', + message: "No such post.", + code: "NO_SUCH_POST", + id: "c32e6dd0-b555-4413-925e-b3757d19ed84", }, notLiked: { - message: 'You have not liked that post.', - code: 'NOT_LIKED', - id: 'e3e8e06e-be37-41f7-a5b4-87a8250288f0', + message: "You have not liked that post.", + code: "NOT_LIKED", + id: "e3e8e06e-be37-41f7-a5b4-87a8250288f0", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - postId: { type: 'string', format: 'misskey:id' }, + postId: { type: "string", format: "misskey:id" }, }, - required: ['postId'], + required: ["postId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOneBy({ id: ps.postId }); if (post == null) { @@ -51,5 +50,5 @@ export default define(meta, paramDef, async (ps, user) => { // Delete like await GalleryLikes.delete(exist.id); - GalleryPosts.decrement({ id: post.id }, 'likedCount', 1); + GalleryPosts.decrement({ id: post.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index b333d947d..64e204172 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -1,16 +1,16 @@ -import define from '../../../define.js'; -import { DriveFiles, GalleryPosts } from '@/models/index.js'; -import { GalleryPost } from '@/models/entities/gallery-post.js'; -import { ApiError } from '../../../error.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { HOUR } from '@/const.js'; +import define from "../../../define.js"; +import { DriveFiles, GalleryPosts } from "@/models/index.js"; +import { GalleryPost } from "@/models/entities/gallery-post.js"; +import { ApiError } from "../../../error.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['gallery'], + tags: ["gallery"], requireCredential: true, - kind: 'write:gallery', + kind: "write:gallery", limit: { duration: HOUR, @@ -18,53 +18,65 @@ export const meta = { }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, - errors: { - - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - postId: { type: 'string', format: 'misskey:id' }, - title: { type: 'string', minLength: 1 }, - description: { type: 'string', nullable: true }, - fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: { - type: 'string', format: 'misskey:id', - } }, - isSensitive: { type: 'boolean', default: false }, + postId: { type: "string", format: "misskey:id" }, + title: { type: "string", minLength: 1 }, + description: { type: "string", nullable: true }, + fileIds: { + type: "array", + uniqueItems: true, + minItems: 1, + maxItems: 32, + items: { + type: "string", + format: "misskey:id", + }, + }, + isSensitive: { type: "boolean", default: false }, }, - required: ['postId', 'title', 'fileIds'], + required: ["postId", "title", "fileIds"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const files = (await Promise.all(ps.fileIds.map(fileId => - DriveFiles.findOneBy({ - id: fileId, - userId: user.id, - }) - ))).filter((file): file is DriveFile => file != null); + const files = ( + await Promise.all( + ps.fileIds.map((fileId) => + DriveFiles.findOneBy({ + id: fileId, + userId: user.id, + }), + ), + ) + ).filter((file): file is DriveFile => file != null); if (files.length === 0) { throw new Error(); } - await GalleryPosts.update({ - id: ps.postId, - userId: user.id, - }, { - updatedAt: new Date(), - title: ps.title, - description: ps.description, - isSensitive: ps.isSensitive, - fileIds: files.map(file => file.id), - }); + await GalleryPosts.update( + { + id: ps.postId, + userId: user.id, + }, + { + updatedAt: new Date(), + title: ps.title, + description: ps.description, + isSensitive: ps.isSensitive, + fileIds: files.map((file) => file.id), + }, + ); const post = await GalleryPosts.findOneByOrFail({ id: ps.postId }); diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index a8febe05b..805674a5b 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -1,22 +1,21 @@ -import { MoreThan } from 'typeorm'; -import { USER_ONLINE_THRESHOLD } from '@/const.js'; -import { Users } from '@/models/index.js'; -import define from '../define.js'; +import { MoreThan } from "typeorm"; +import { USER_ONLINE_THRESHOLD } from "@/const.js"; +import { Users } from "@/models/index.js"; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const count = await Users.countBy({ lastActiveDate: MoreThan(new Date(Date.now() - USER_ONLINE_THRESHOLD)), diff --git a/packages/backend/src/server/api/endpoints/hashtags/list.ts b/packages/backend/src/server/api/endpoints/hashtags/list.ts index 4b18cb76a..df99a1e5a 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/list.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/list.ts @@ -1,66 +1,109 @@ -import define from '../../define.js'; -import { Hashtags } from '@/models/index.js'; +import define from "../../define.js"; +import { Hashtags } from "@/models/index.js"; export const meta = { - tags: ['hashtags'], + tags: ["hashtags"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Hashtag', + type: "object", + optional: false, + nullable: false, + ref: "Hashtag", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - attachedToUserOnly: { type: 'boolean', default: false }, - attachedToLocalUserOnly: { type: 'boolean', default: false }, - attachedToRemoteUserOnly: { type: 'boolean', default: false }, - sort: { type: 'string', enum: ['+mentionedUsers', '-mentionedUsers', '+mentionedLocalUsers', '-mentionedLocalUsers', '+mentionedRemoteUsers', '-mentionedRemoteUsers', '+attachedUsers', '-attachedUsers', '+attachedLocalUsers', '-attachedLocalUsers', '+attachedRemoteUsers', '-attachedRemoteUsers'] }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + attachedToUserOnly: { type: "boolean", default: false }, + attachedToLocalUserOnly: { type: "boolean", default: false }, + attachedToRemoteUserOnly: { type: "boolean", default: false }, + sort: { + type: "string", + enum: [ + "+mentionedUsers", + "-mentionedUsers", + "+mentionedLocalUsers", + "-mentionedLocalUsers", + "+mentionedRemoteUsers", + "-mentionedRemoteUsers", + "+attachedUsers", + "-attachedUsers", + "+attachedLocalUsers", + "-attachedLocalUsers", + "+attachedRemoteUsers", + "-attachedRemoteUsers", + ], + }, }, - required: ['sort'], + required: ["sort"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Hashtags.createQueryBuilder('tag'); + const query = Hashtags.createQueryBuilder("tag"); - if (ps.attachedToUserOnly) query.andWhere('tag.attachedUsersCount != 0'); - if (ps.attachedToLocalUserOnly) query.andWhere('tag.attachedLocalUsersCount != 0'); - if (ps.attachedToRemoteUserOnly) query.andWhere('tag.attachedRemoteUsersCount != 0'); + if (ps.attachedToUserOnly) query.andWhere("tag.attachedUsersCount != 0"); + if (ps.attachedToLocalUserOnly) + query.andWhere("tag.attachedLocalUsersCount != 0"); + if (ps.attachedToRemoteUserOnly) + query.andWhere("tag.attachedRemoteUsersCount != 0"); switch (ps.sort) { - case '+mentionedUsers': query.orderBy('tag.mentionedUsersCount', 'DESC'); break; - case '-mentionedUsers': query.orderBy('tag.mentionedUsersCount', 'ASC'); break; - case '+mentionedLocalUsers': query.orderBy('tag.mentionedLocalUsersCount', 'DESC'); break; - case '-mentionedLocalUsers': query.orderBy('tag.mentionedLocalUsersCount', 'ASC'); break; - case '+mentionedRemoteUsers': query.orderBy('tag.mentionedRemoteUsersCount', 'DESC'); break; - case '-mentionedRemoteUsers': query.orderBy('tag.mentionedRemoteUsersCount', 'ASC'); break; - case '+attachedUsers': query.orderBy('tag.attachedUsersCount', 'DESC'); break; - case '-attachedUsers': query.orderBy('tag.attachedUsersCount', 'ASC'); break; - case '+attachedLocalUsers': query.orderBy('tag.attachedLocalUsersCount', 'DESC'); break; - case '-attachedLocalUsers': query.orderBy('tag.attachedLocalUsersCount', 'ASC'); break; - case '+attachedRemoteUsers': query.orderBy('tag.attachedRemoteUsersCount', 'DESC'); break; - case '-attachedRemoteUsers': query.orderBy('tag.attachedRemoteUsersCount', 'ASC'); break; + case "+mentionedUsers": + query.orderBy("tag.mentionedUsersCount", "DESC"); + break; + case "-mentionedUsers": + query.orderBy("tag.mentionedUsersCount", "ASC"); + break; + case "+mentionedLocalUsers": + query.orderBy("tag.mentionedLocalUsersCount", "DESC"); + break; + case "-mentionedLocalUsers": + query.orderBy("tag.mentionedLocalUsersCount", "ASC"); + break; + case "+mentionedRemoteUsers": + query.orderBy("tag.mentionedRemoteUsersCount", "DESC"); + break; + case "-mentionedRemoteUsers": + query.orderBy("tag.mentionedRemoteUsersCount", "ASC"); + break; + case "+attachedUsers": + query.orderBy("tag.attachedUsersCount", "DESC"); + break; + case "-attachedUsers": + query.orderBy("tag.attachedUsersCount", "ASC"); + break; + case "+attachedLocalUsers": + query.orderBy("tag.attachedLocalUsersCount", "DESC"); + break; + case "-attachedLocalUsers": + query.orderBy("tag.attachedLocalUsersCount", "ASC"); + break; + case "+attachedRemoteUsers": + query.orderBy("tag.attachedRemoteUsersCount", "DESC"); + break; + case "-attachedRemoteUsers": + query.orderBy("tag.attachedRemoteUsersCount", "ASC"); + break; } query.select([ - 'tag.name', - 'tag.mentionedUsersCount', - 'tag.mentionedLocalUsersCount', - 'tag.mentionedRemoteUsersCount', - 'tag.attachedUsersCount', - 'tag.attachedLocalUsersCount', - 'tag.attachedRemoteUsersCount', + "tag.name", + "tag.mentionedUsersCount", + "tag.mentionedLocalUsersCount", + "tag.mentionedRemoteUsersCount", + "tag.attachedUsersCount", + "tag.attachedLocalUsersCount", + "tag.attachedRemoteUsersCount", ]); const tags = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index ed1abf1a1..95bc608ec 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,41 +1,42 @@ -import define from '../../define.js'; -import { Hashtags } from '@/models/index.js'; +import define from "../../define.js"; +import { Hashtags } from "@/models/index.js"; export const meta = { - tags: ['hashtags'], + tags: ["hashtags"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - query: { type: 'string' }, - offset: { type: 'integer', default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + query: { type: "string" }, + offset: { type: "integer", default: 0 }, }, - required: ['query'], + required: ["query"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const hashtags = await Hashtags.createQueryBuilder('tag') - .where('tag.name like :q', { q: ps.query.toLowerCase() + '%' }) - .orderBy('tag.count', 'DESC') - .groupBy('tag.id') + const hashtags = await Hashtags.createQueryBuilder("tag") + .where("tag.name like :q", { q: `${ps.query.toLowerCase()}%` }) + .orderBy("tag.count", "DESC") + .groupBy("tag.id") .take(ps.limit) .skip(ps.offset) .getMany(); - return hashtags.map(tag => tag.name); + return hashtags.map((tag) => tag.name); }); diff --git a/packages/backend/src/server/api/endpoints/hashtags/show.ts b/packages/backend/src/server/api/endpoints/hashtags/show.ts index 409233c24..8cf90e450 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/show.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/show.ts @@ -1,40 +1,42 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Hashtags } from '@/models/index.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Hashtags } from "@/models/index.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; export const meta = { - tags: ['hashtags'], + tags: ["hashtags"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Hashtag', + type: "object", + optional: false, + nullable: false, + ref: "Hashtag", }, errors: { noSuchHashtag: { - message: 'No such hashtag.', - code: 'NO_SUCH_HASHTAG', - id: '110ee688-193e-4a3a-9ecf-c167b2e6981e', + message: "No such hashtag.", + code: "NO_SUCH_HASHTAG", + id: "110ee688-193e-4a3a-9ecf-c167b2e6981e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - tag: { type: 'string' }, + tag: { type: "string" }, }, - required: ['tag'], + required: ["tag"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const hashtag = await Hashtags.findOneBy({ name: normalizeForSearch(ps.tag) }); + const hashtag = await Hashtags.findOneBy({ + name: normalizeForSearch(ps.tag), + }); if (hashtag == null) { throw new ApiError(meta.errors.noSuchHashtag); } diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index 8795927e6..e2a834511 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,10 +1,10 @@ -import { Brackets } from 'typeorm'; -import define from '../../define.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { safeForSql } from '@/misc/safe-for-sql.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { Brackets } from "typeorm"; +import define from "../../define.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Notes } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import { safeForSql } from "@/misc/safe-for-sql.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; /* トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要 @@ -21,33 +21,39 @@ const rangeA = 1000 * 60 * 60; // 60分 const max = 5; export const meta = { - tags: ['hashtags'], + tags: ["hashtags"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { tag: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, chart: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, usersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, @@ -55,27 +61,29 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const instance = await fetchMeta(true); - const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); + const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t)); const now = new Date(); // 5分単位で丸めた現在日時 now.setMinutes(Math.round(now.getMinutes() / 5) * 5, 0, 0); - const tagNotes = await Notes.createQueryBuilder('note') - .where(`note.createdAt > :date`, { date: new Date(now.getTime() - rangeA) }) - .andWhere(new Brackets(qb => { qb - .where(`note.visibility = 'public'`) - .orWhere(`note.visibility = 'home'`); - })) + const tagNotes = await Notes.createQueryBuilder("note") + .where("note.createdAt > :date", { date: new Date(now.getTime() - rangeA) }) + .andWhere( + new Brackets((qb) => { + qb.where(`note.visibility = 'public'`).orWhere( + `note.visibility = 'home'`, + ); + }), + ) .andWhere(`note.tags != '{}'`) - .select(['note.tags', 'note.userId']) + .select(["note.tags", "note.userId"]) .cache(60000) // 1 min .getMany(); @@ -85,14 +93,14 @@ export default define(meta, paramDef, async () => { const tags: { name: string; - users: Note['userId'][]; + users: Note["userId"][]; }[] = []; for (const note of tagNotes) { for (const tag of note.tags) { if (hiddenTags.includes(tag)) continue; - const x = tags.find(x => x.name === tag); + const x = tags.find((x) => x.name === tag); if (x) { if (!x.users.includes(note.userId)) { x.users.push(note.userId); @@ -109,7 +117,7 @@ export default define(meta, paramDef, async () => { // タグを人気順に並べ替え const hots = tags .sort((a, b) => b.users.length - a.users.length) - .map(tag => tag.name) + .map((tag) => tag.name) .slice(0, max); //#region 2(または3)で話題と判定されたタグそれぞれについて過去の投稿数グラフを取得する @@ -121,32 +129,48 @@ export default define(meta, paramDef, async () => { const interval = 1000 * 60 * 10; for (let i = 0; i < range; i++) { - countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note') - .select('count(distinct note.userId)') - .where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`) - .andWhere('note.createdAt < :lt', { lt: new Date(now.getTime() - (interval * i)) }) - .andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - (interval * (i + 1))) }) - .cache(60000) // 1 min - .getRawOne() - .then(x => parseInt(x.count, 10)) - ))); + countPromises.push( + Promise.all( + hots.map((tag) => + Notes.createQueryBuilder("note") + .select("count(distinct note.userId)") + .where( + `'{"${safeForSql(tag) ? tag : "aichan_kawaii"}"}' <@ note.tags`, + ) + .andWhere("note.createdAt < :lt", { + lt: new Date(now.getTime() - interval * i), + }) + .andWhere("note.createdAt > :gt", { + gt: new Date(now.getTime() - interval * (i + 1)), + }) + .cache(60000) // 1 min + .getRawOne() + .then((x) => parseInt(x.count, 10)), + ), + ), + ); } const countsLog = await Promise.all(countPromises); //#endregion - const totalCounts = await Promise.all(hots.map(tag => Notes.createQueryBuilder('note') - .select('count(distinct note.userId)') - .where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`) - .andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - rangeA) }) - .cache(60000 * 60) // 60 min - .getRawOne() - .then(x => parseInt(x.count, 10)) - )); + const totalCounts = await Promise.all( + hots.map((tag) => + Notes.createQueryBuilder("note") + .select("count(distinct note.userId)") + .where(`'{"${safeForSql(tag) ? tag : "aichan_kawaii"}"}' <@ note.tags`) + .andWhere("note.createdAt > :gt", { + gt: new Date(now.getTime() - rangeA), + }) + .cache(60000 * 60) // 60 min + .getRawOne() + .then((x) => parseInt(x.count, 10)), + ), + ); const stats = hots.map((tag, i) => ({ tag, - chart: countsLog.map(counts => counts[i]), + chart: countsLog.map((counts) => counts[i]), usersCount: totalCounts[i], })); diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts index 1d18a9ce7..532c66307 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/users.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts @@ -1,60 +1,89 @@ -import define from '../../define.js'; -import { Users } from '@/models/index.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import define from "../../define.js"; +import { Users } from "@/models/index.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; export const meta = { requireCredential: false, requireCredentialPrivateMode: true, - tags: ['hashtags', 'users'], + tags: ["hashtags", "users"], res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - tag: { type: 'string' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, - state: { type: 'string', enum: ['all', 'alive'], default: "all" }, - origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + tag: { type: "string" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sort: { + type: "string", + enum: [ + "+follower", + "-follower", + "+createdAt", + "-createdAt", + "+updatedAt", + "-updatedAt", + ], + }, + state: { type: "string", enum: ["all", "alive"], default: "all" }, + origin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "local", + }, }, - required: ['tag', 'sort'], + required: ["tag", "sort"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Users.createQueryBuilder('user') - .where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) }); + const query = Users.createQueryBuilder("user").where( + ":tag = ANY(user.tags)", + { tag: normalizeForSearch(ps.tag) }, + ); - const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); + const recent = new Date(Date.now() - 1000 * 60 * 60 * 24 * 5); - if (ps.state === 'alive') { - query.andWhere('user.updatedAt > :date', { date: recent }); + if (ps.state === "alive") { + query.andWhere("user.updatedAt > :date", { date: recent }); } - if (ps.origin === 'local') { - query.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - query.andWhere('user.host IS NOT NULL'); + if (ps.origin === "local") { + query.andWhere("user.host IS NULL"); + } else if (ps.origin === "remote") { + query.andWhere("user.host IS NOT NULL"); } switch (ps.sort) { - case '+follower': query.orderBy('user.followersCount', 'DESC'); break; - case '-follower': query.orderBy('user.followersCount', 'ASC'); break; - case '+createdAt': query.orderBy('user.createdAt', 'DESC'); break; - case '-createdAt': query.orderBy('user.createdAt', 'ASC'); break; - case '+updatedAt': query.orderBy('user.updatedAt', 'DESC'); break; - case '-updatedAt': query.orderBy('user.updatedAt', 'ASC'); break; + case "+follower": + query.orderBy("user.followersCount", "DESC"); + break; + case "-follower": + query.orderBy("user.followersCount", "ASC"); + break; + case "+createdAt": + query.orderBy("user.createdAt", "DESC"); + break; + case "-createdAt": + query.orderBy("user.createdAt", "ASC"); + break; + case "+updatedAt": + query.orderBy("user.updatedAt", "DESC"); + break; + case "-updatedAt": + query.orderBy("user.updatedAt", "ASC"); + break; } const users = await query.take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts index 22aedfeee..39543442c 100644 --- a/packages/backend/src/server/api/endpoints/i.ts +++ b/packages/backend/src/server/api/endpoints/i.ts @@ -1,25 +1,25 @@ -import { Users } from '@/models/index.js'; -import define from '../define.js'; +import { Users } from "@/models/index.js"; +import define from "../define.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, res: { - type: 'object', - optional: false, nullable: false, - ref: 'MeDetailed', + type: "object", + optional: false, + nullable: false, + ref: "MeDetailed", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user, token) => { const isSecure = token == null; diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts index 35806b2bc..1e9892f03 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts @@ -1,6 +1,6 @@ -import * as speakeasy from 'speakeasy'; -import define from '../../../define.js'; -import { UserProfiles } from '@/models/index.js'; +import * as speakeasy from "speakeasy"; +import define from "../../../define.js"; +import { UserProfiles } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -9,31 +9,30 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - token: { type: 'string' }, + token: { type: "string" }, }, - required: ['token'], + required: ["token"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const token = ps.token.replace(/\s/g, ''); + const token = ps.token.replace(/\s/g, ""); const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.twoFactorTempSecret == null) { - throw new Error('二段階認証の設定が開始されていません'); + throw new Error("二段階認証の設定が開始されていません"); } const verified = (speakeasy as any).totp.verify({ secret: profile.twoFactorTempSecret, - encoding: 'base32', + encoding: "base32", token: token, }); if (!verified) { - throw new Error('not verified'); + throw new Error("not verified"); } await UserProfiles.update(user.id, { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index 1afb34bfd..e80dc4d71 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -1,19 +1,19 @@ -import bcrypt from 'bcryptjs'; -import { promisify } from 'node:util'; -import * as cbor from 'cbor'; -import define from '../../../define.js'; +import bcrypt from "bcryptjs"; +import { promisify } from "node:util"; +import * as cbor from "cbor"; +import define from "../../../define.js"; import { UserProfiles, UserSecurityKeys, AttestationChallenges, Users, -} from '@/models/index.js'; -import config from '@/config/index.js'; -import { procedures, hash } from '../../../2fa.js'; -import { publishMainStream } from '@/services/stream.js'; +} from "@/models/index.js"; +import config from "@/config/index.js"; +import { procedures, hash } from "../../../2fa.js"; +import { publishMainStream } from "@/services/stream.js"; const cborDecodeFirst = promisify(cbor.decodeFirst) as any; -const rpIdHashReal = hash(Buffer.from(config.hostname, 'utf-8')); +const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8")); export const meta = { requireCredential: true, @@ -22,18 +22,23 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - clientDataJSON: { type: 'string' }, - attestationObject: { type: 'string' }, - password: { type: 'string' }, - challengeId: { type: 'string' }, - name: { type: 'string' }, + clientDataJSON: { type: "string" }, + attestationObject: { type: "string" }, + password: { type: "string" }, + challengeId: { type: "string" }, + name: { type: "string" }, }, - required: ['clientDataJSON', 'attestationObject', 'password', 'challengeId', 'name'], + required: [ + "clientDataJSON", + "attestationObject", + "password", + "challengeId", + "name", + ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -41,36 +46,35 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } if (!profile.twoFactorEnabled) { - throw new Error('2fa not enabled'); + throw new Error("2fa not enabled"); } const clientData = JSON.parse(ps.clientDataJSON); - if (clientData.type !== 'webauthn.create') { - throw new Error('not a creation attestation'); + if (clientData.type !== "webauthn.create") { + throw new Error("not a creation attestation"); } - if (clientData.origin !== config.scheme + '://' + config.host) { - throw new Error('origin mismatch'); + if (clientData.origin !== `${config.scheme}://${config.host}`) { + throw new Error("origin mismatch"); } - const clientDataJSONHash = hash(Buffer.from(ps.clientDataJSON, 'utf-8')); + const clientDataJSONHash = hash(Buffer.from(ps.clientDataJSON, "utf-8")); const attestation = await cborDecodeFirst(ps.attestationObject); const rpIdHash = attestation.authData.slice(0, 32); if (!rpIdHashReal.equals(rpIdHash)) { - throw new Error('rpIdHash mismatch'); + throw new Error("rpIdHash mismatch"); } const flags = attestation.authData[32]; - // eslint:disable-next-line:no-bitwise if (!(flags & 1)) { - throw new Error('user not present'); + throw new Error("user not present"); } const authData = Buffer.from(attestation.authData); @@ -79,11 +83,11 @@ export default define(meta, paramDef, async (ps, user) => { const publicKeyData = authData.slice(55 + credentialIdLength); const publicKey: Map = await cborDecodeFirst(publicKeyData); if (publicKey.get(3) !== -7) { - throw new Error('alg mismatch'); + throw new Error("alg mismatch"); } if (!(procedures as any)[attestation.fmt]) { - throw new Error('unsupported fmt'); + throw new Error("unsupported fmt"); } const verificationData = (procedures as any)[attestation.fmt].verify({ @@ -94,17 +98,17 @@ export default define(meta, paramDef, async (ps, user) => { publicKey, rpIdHash, }); - if (!verificationData.valid) throw new Error('signature invalid'); + if (!verificationData.valid) throw new Error("signature invalid"); const attestationChallenge = await AttestationChallenges.findOneBy({ userId: user.id, id: ps.challengeId, registrationChallenge: true, - challenge: hash(clientData.challenge).toString('hex'), + challenge: hash(clientData.challenge).toString("hex"), }); if (!attestationChallenge) { - throw new Error('non-existent challenge'); + throw new Error("non-existent challenge"); } await AttestationChallenges.delete({ @@ -117,24 +121,28 @@ export default define(meta, paramDef, async (ps, user) => { new Date().getTime() - attestationChallenge.createdAt.getTime() >= 5 * 60 * 1000 ) { - throw new Error('expired challenge'); + throw new Error("expired challenge"); } - const credentialIdString = credentialId.toString('hex'); + const credentialIdString = credentialId.toString("hex"); await UserSecurityKeys.insert({ userId: user.id, id: credentialIdString, lastUsed: new Date(), name: ps.name, - publicKey: verificationData.publicKey.toString('hex'), + publicKey: verificationData.publicKey.toString("hex"), }); // Publish meUpdated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user.id, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user.id, user, { + detail: true, + includeSecrets: true, + }), + ); return { id: credentialIdString, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts index 4bfa24f97..11b2e9a2e 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; -import { UserProfiles } from '@/models/index.js'; +import define from "../../../define.js"; +import { UserProfiles } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,14 +8,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - value: { type: 'boolean' }, + value: { type: "boolean" }, }, - required: ['value'], + required: ["value"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { await UserProfiles.update(user.id, { usePasswordLessLogin: ps.value, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index e906b8204..8c0af28ee 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -1,10 +1,10 @@ -import bcrypt from 'bcryptjs'; -import define from '../../../define.js'; -import { UserProfiles, AttestationChallenges } from '@/models/index.js'; -import { promisify } from 'node:util'; -import * as crypto from 'node:crypto'; -import { genId } from '@/misc/gen-id.js'; -import { hash } from '../../../2fa.js'; +import bcrypt from "bcryptjs"; +import define from "../../../define.js"; +import { UserProfiles, AttestationChallenges } from "@/models/index.js"; +import { promisify } from "node:util"; +import * as crypto from "node:crypto"; +import { genId } from "@/misc/gen-id.js"; +import { hash } from "../../../2fa.js"; const randomBytes = promisify(crypto.randomBytes); @@ -15,14 +15,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, + password: { type: "string" }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -30,26 +29,27 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } if (!profile.twoFactorEnabled) { - throw new Error('2fa not enabled'); + throw new Error("2fa not enabled"); } // 32 byte challenge const entropy = await randomBytes(32); - const challenge = entropy.toString('base64') - .replace(/=/g, '') - .replace(/\+/g, '-') - .replace(/\//g, '_'); + const challenge = entropy + .toString("base64") + .replace(/=/g, "") + .replace(/\+/g, "-") + .replace(/\//g, "_"); const challengeId = genId(); await AttestationChallenges.insert({ userId: user.id, id: challengeId, - challenge: hash(Buffer.from(challenge, 'utf-8')).toString('hex'), + challenge: hash(Buffer.from(challenge, "utf-8")).toString("hex"), createdAt: new Date(), registrationChallenge: true, }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index 33f571772..9019787f2 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -1,9 +1,9 @@ -import bcrypt from 'bcryptjs'; -import * as speakeasy from 'speakeasy'; -import * as QRCode from 'qrcode'; -import config from '@/config/index.js'; -import { UserProfiles } from '@/models/index.js'; -import define from '../../../define.js'; +import bcrypt from "bcryptjs"; +import * as speakeasy from "speakeasy"; +import * as QRCode from "qrcode"; +import config from "@/config/index.js"; +import { UserProfiles } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { requireCredential: true, @@ -12,14 +12,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, + password: { type: "string" }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -27,7 +26,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } // Generate user's secret key @@ -42,7 +41,7 @@ export default define(meta, paramDef, async (ps, user) => { // Get the data URL of the authenticator URL const url = speakeasy.otpauthURL({ secret: secret.base32, - encoding: 'base32', + encoding: "base32", label: user.username, issuer: config.host, }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index eb2f75308..d491f0a6e 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -1,7 +1,7 @@ -import bcrypt from 'bcryptjs'; -import define from '../../../define.js'; -import { UserProfiles, UserSecurityKeys, Users } from '@/models/index.js'; -import { publishMainStream } from '@/services/stream.js'; +import bcrypt from "bcryptjs"; +import define from "../../../define.js"; +import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js"; +import { publishMainStream } from "@/services/stream.js"; export const meta = { requireCredential: true, @@ -10,15 +10,14 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, - credentialId: { type: 'string' }, + password: { type: "string" }, + credentialId: { type: "string" }, }, - required: ['password', 'credentialId'], + required: ["password", "credentialId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -26,7 +25,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } // Make sure we only delete the user's own creds @@ -36,10 +35,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Publish meUpdated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user.id, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user.id, user, { + detail: true, + includeSecrets: true, + }), + ); return {}; }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index 45e7a9863..9bb1538b0 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -1,6 +1,6 @@ -import bcrypt from 'bcryptjs'; -import define from '../../../define.js'; -import { UserProfiles } from '@/models/index.js'; +import bcrypt from "bcryptjs"; +import define from "../../../define.js"; +import { UserProfiles } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -9,14 +9,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, + password: { type: "string" }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -24,7 +23,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } await UserProfiles.update(user.id, { diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index eca955884..b95160194 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -1,5 +1,5 @@ -import define from '../../define.js'; -import { AccessTokens } from '@/models/index.js'; +import define from "../../define.js"; +import { AccessTokens } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,33 +8,49 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - sort: { type: 'string', enum: ['+createdAt', '-createdAt', '+lastUsedAt', '-lastUsedAt'] }, + sort: { + type: "string", + enum: ["+createdAt", "-createdAt", "+lastUsedAt", "-lastUsedAt"], + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = AccessTokens.createQueryBuilder('token') - .where('token.userId = :userId', { userId: user.id }); + const query = AccessTokens.createQueryBuilder("token").where( + "token.userId = :userId", + { userId: user.id }, + ); switch (ps.sort) { - case '+createdAt': query.orderBy('token.createdAt', 'DESC'); break; - case '-createdAt': query.orderBy('token.createdAt', 'ASC'); break; - case '+lastUsedAt': query.orderBy('token.lastUsedAt', 'DESC'); break; - case '-lastUsedAt': query.orderBy('token.lastUsedAt', 'ASC'); break; - default: query.orderBy('token.id', 'ASC'); break; + case "+createdAt": + query.orderBy("token.createdAt", "DESC"); + break; + case "-createdAt": + query.orderBy("token.createdAt", "ASC"); + break; + case "+lastUsedAt": + query.orderBy("token.lastUsedAt", "DESC"); + break; + case "-lastUsedAt": + query.orderBy("token.lastUsedAt", "ASC"); + break; + default: + query.orderBy("token.id", "ASC"); + break; } const tokens = await query.getMany(); - return await Promise.all(tokens.map(token => ({ - id: token.id, - name: token.name, - createdAt: token.createdAt, - lastUsedAt: token.lastUsedAt, - permission: token.permission, - }))); + return await Promise.all( + tokens.map((token) => ({ + id: token.id, + name: token.name, + createdAt: token.createdAt, + lastUsedAt: token.lastUsedAt, + permission: token.permission, + })), + ); }); diff --git a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts index 68bd103a6..f759b2303 100644 --- a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts +++ b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts @@ -1,5 +1,5 @@ -import define from '../../define.js'; -import { AccessTokens, Apps } from '@/models/index.js'; +import define from "../../define.js"; +import { AccessTokens, Apps } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,16 +8,15 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, - sort: { type: 'string', enum: ['desc', 'asc'], default: "desc" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, + sort: { type: "string", enum: ["desc", "asc"], default: "desc" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get tokens const tokens = await AccessTokens.find({ @@ -27,11 +26,15 @@ export default define(meta, paramDef, async (ps, user) => { take: ps.limit, skip: ps.offset, order: { - id: ps.sort === 'asc' ? 1 : -1, + id: ps.sort === "asc" ? 1 : -1, }, }); - return await Promise.all(tokens.map(token => Apps.pack(token.appId, user, { - detail: true, - }))); + return await Promise.all( + tokens.map((token) => + Apps.pack(token.appId, user, { + detail: true, + }), + ), + ); }); diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index f9f6a33a8..fcfc38bd1 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -1,6 +1,6 @@ -import bcrypt from 'bcryptjs'; -import define from '../../define.js'; -import { UserProfiles } from '@/models/index.js'; +import bcrypt from "bcryptjs"; +import define from "../../define.js"; +import { UserProfiles } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -9,15 +9,14 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - currentPassword: { type: 'string' }, - newPassword: { type: 'string', minLength: 1 }, + currentPassword: { type: "string" }, + newPassword: { type: "string", minLength: 1 }, }, - required: ['currentPassword', 'newPassword'], + required: ["currentPassword", "newPassword"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -25,7 +24,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.currentPassword, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } // Generate hash of password diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index ede4a9d03..81aee9a41 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -1,7 +1,7 @@ -import bcrypt from 'bcryptjs'; -import { UserProfiles, Users } from '@/models/index.js'; -import { deleteAccount } from '@/services/delete-account.js'; -import define from '../../define.js'; +import bcrypt from "bcryptjs"; +import { UserProfiles, Users } from "@/models/index.js"; +import { deleteAccount } from "@/services/delete-account.js"; +import define from "../../define.js"; export const meta = { requireCredential: true, @@ -10,14 +10,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, + password: { type: "string" }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); const userDetailed = await Users.findOneByOrFail({ id: user.id }); @@ -29,7 +28,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } await deleteAccount(user); diff --git a/packages/backend/src/server/api/endpoints/i/export-blocking.ts b/packages/backend/src/server/api/endpoints/i/export-blocking.ts index 682d39552..4517ad5fa 100644 --- a/packages/backend/src/server/api/endpoints/i/export-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/export-blocking.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { createExportBlockingJob } from '@/queue/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createExportBlockingJob } from "@/queue/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -12,12 +12,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportBlockingJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-following.ts b/packages/backend/src/server/api/endpoints/i/export-following.ts index 3d56ab7ee..a228de8f1 100644 --- a/packages/backend/src/server/api/endpoints/i/export-following.ts +++ b/packages/backend/src/server/api/endpoints/i/export-following.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { createExportFollowingJob } from '@/queue/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createExportFollowingJob } from "@/queue/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -12,15 +12,14 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - excludeMuting: { type: 'boolean', default: false }, - excludeInactive: { type: 'boolean', default: false }, + excludeMuting: { type: "boolean", default: false }, + excludeInactive: { type: "boolean", default: false }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportFollowingJob(user, ps.excludeMuting, ps.excludeInactive); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-mute.ts b/packages/backend/src/server/api/endpoints/i/export-mute.ts index b6cc1eea4..7bddc434d 100644 --- a/packages/backend/src/server/api/endpoints/i/export-mute.ts +++ b/packages/backend/src/server/api/endpoints/i/export-mute.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { createExportMuteJob } from '@/queue/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createExportMuteJob } from "@/queue/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -12,12 +12,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportMuteJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-notes.ts b/packages/backend/src/server/api/endpoints/i/export-notes.ts index 4856b84ab..48506ed6d 100644 --- a/packages/backend/src/server/api/endpoints/i/export-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/export-notes.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { createExportNotesJob } from '@/queue/index.js'; -import { DAY } from '@/const.js'; +import define from "../../define.js"; +import { createExportNotesJob } from "@/queue/index.js"; +import { DAY } from "@/const.js"; export const meta = { secure: true, @@ -12,12 +12,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportNotesJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts index 1aa02707d..a71b1730b 100644 --- a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { createExportUserListsJob } from '@/queue/index.js'; -import { MINUTE } from '@/const.js'; +import define from "../../define.js"; +import { createExportUserListsJob } from "@/queue/index.js"; +import { MINUTE } from "@/const.js"; export const meta = { secure: true, @@ -12,12 +12,11 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { createExportUserListsJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/favorites.ts b/packages/backend/src/server/api/endpoints/i/favorites.ts index 3c420e4d0..f0dbd2de6 100644 --- a/packages/backend/src/server/api/endpoints/i/favorites.ts +++ b/packages/backend/src/server/api/endpoints/i/favorites.ts @@ -1,44 +1,47 @@ -import define from '../../define.js'; -import { NoteFavorites } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { NoteFavorites } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'notes', 'favorites'], + tags: ["account", "notes", "favorites"], requireCredential: true, - kind: 'read:favorites', + kind: "read:favorites", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'NoteFavorite', + type: "object", + optional: false, + nullable: false, + ref: "NoteFavorite", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(NoteFavorites.createQueryBuilder('favorite'), ps.sinceId, ps.untilId) - .andWhere(`favorite.userId = :meId`, { meId: user.id }) - .leftJoinAndSelect('favorite.note', 'note'); + const query = makePaginationQuery( + NoteFavorites.createQueryBuilder("favorite"), + ps.sinceId, + ps.untilId, + ) + .andWhere("favorite.userId = :meId", { meId: user.id }) + .leftJoinAndSelect("favorite.note", "note"); - const favorites = await query - .take(ps.limit) - .getMany(); + const favorites = await query.take(ps.limit).getMany(); return await NoteFavorites.packMany(favorites, user); }); diff --git a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts index a38383f30..d71ee3e5a 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts @@ -1,55 +1,60 @@ -import define from '../../../define.js'; -import { GalleryLikes } from '@/models/index.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import define from "../../../define.js"; +import { GalleryLikes } from "@/models/index.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'gallery'], + tags: ["account", "gallery"], requireCredential: true, - kind: 'read:gallery-likes', + kind: "read:gallery-likes", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, post: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, - } + }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(GalleryLikes.createQueryBuilder('like'), ps.sinceId, ps.untilId) - .andWhere(`like.userId = :meId`, { meId: user.id }) - .leftJoinAndSelect('like.post', 'post'); + const query = makePaginationQuery( + GalleryLikes.createQueryBuilder("like"), + ps.sinceId, + ps.untilId, + ) + .andWhere("like.userId = :meId", { meId: user.id }) + .leftJoinAndSelect("like.post", "post"); - const likes = await query - .take(ps.limit) - .getMany(); + const likes = await query.take(ps.limit).getMany(); return await GalleryLikes.packMany(likes, user); }); diff --git a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts index 2ecd47f1b..e471731ae 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts @@ -1,43 +1,45 @@ -import { GalleryPosts } from '@/models/index.js'; -import define from '../../../define.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import { GalleryPosts } from "@/models/index.js"; +import define from "../../../define.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'gallery'], + tags: ["account", "gallery"], requireCredential: true, - kind: 'read:gallery', + kind: "read:gallery", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) - .andWhere('post.userId = :meId', { meId: user.id }); + const query = makePaginationQuery( + GalleryPosts.createQueryBuilder("post"), + ps.sinceId, + ps.untilId, + ).andWhere("post.userId = :meId", { meId: user.id }); - const posts = await query - .take(ps.limit) - .getMany(); + const posts = await query.take(ps.limit).getMany(); return await GalleryPosts.packMany(posts, user); }); diff --git a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts index e7d7518c5..bd58f9257 100644 --- a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts +++ b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts @@ -1,37 +1,38 @@ -import define from '../../define.js'; -import { MutedNotes } from '@/models/index.js'; +import define from "../../define.js"; +import { MutedNotes } from "@/models/index.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { count: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { return { count: await MutedNotes.countBy({ userId: user.id, - reason: 'word', + reason: "word", }), }; }); diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts index 5e5bcba7a..e4f1da60c 100644 --- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts @@ -1,8 +1,8 @@ -import define from '../../define.js'; -import { createImportBlockingJob } from '@/queue/index.js'; -import { ApiError } from '../../error.js'; -import { DriveFiles } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createImportBlockingJob } from "@/queue/index.js"; +import { ApiError } from "../../error.js"; +import { DriveFiles } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -15,40 +15,39 @@ export const meta = { errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'ebb53e5f-6574-9c0c-0b92-7ca6def56d7e', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "ebb53e5f-6574-9c0c-0b92-7ca6def56d7e", }, unexpectedFileType: { - message: 'We need csv file.', - code: 'UNEXPECTED_FILE_TYPE', - id: 'b6fab7d6-d945-d67c-dfdb-32da1cd12cfe', + message: "We need csv file.", + code: "UNEXPECTED_FILE_TYPE", + id: "b6fab7d6-d945-d67c-dfdb-32da1cd12cfe", }, tooBigFile: { - message: 'That file is too big.', - code: 'TOO_BIG_FILE', - id: 'b7fbf0b1-aeef-3b21-29ef-fadd4cb72ccf', + message: "That file is too big.", + code: "TOO_BIG_FILE", + id: "b7fbf0b1-aeef-3b21-29ef-fadd4cb72ccf", }, emptyFile: { - message: 'That file is empty.', - code: 'EMPTY_FILE', - id: '6f3a4dcc-f060-a707-4950-806fbdbe60d6', + message: "That file is empty.", + code: "EMPTY_FILE", + id: "6f3a4dcc-f060-a707-4950-806fbdbe60d6", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 23414547f..1a6c9b565 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -1,8 +1,8 @@ -import define from '../../define.js'; -import { createImportFollowingJob } from '@/queue/index.js'; -import { ApiError } from '../../error.js'; -import { DriveFiles } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createImportFollowingJob } from "@/queue/index.js"; +import { ApiError } from "../../error.js"; +import { DriveFiles } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -14,46 +14,45 @@ export const meta = { errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'b98644cf-a5ac-4277-a502-0b8054a709a3', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "b98644cf-a5ac-4277-a502-0b8054a709a3", }, unexpectedFileType: { - message: 'Must be a CSV or JSON file.', - code: 'UNEXPECTED_FILE_TYPE', - id: '660f3599-bce0-4f95-9dde-311fd841c183', + message: "Must be a CSV or JSON file.", + code: "UNEXPECTED_FILE_TYPE", + id: "660f3599-bce0-4f95-9dde-311fd841c183", }, tooBigFile: { - message: 'That file is too big.', - code: 'TOO_BIG_FILE', - id: 'dee9d4ed-ad07-43ed-8b34-b2856398bc60', + message: "That file is too big.", + code: "TOO_BIG_FILE", + id: "dee9d4ed-ad07-43ed-8b34-b2856398bc60", }, emptyFile: { - message: 'That file is empty.', - code: 'EMPTY_FILE', - id: '31a1b42c-06f7-42ae-8a38-a661c5c9f691', + message: "That file is empty.", + code: "EMPTY_FILE", + id: "31a1b42c-06f7-42ae-8a38-a661c5c9f691", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); //if (!file.type.endsWith('/csv')) throw new ApiError(meta.errors.unexpectedFileType); - if (file.size > 50000) throw new ApiError(meta.errors.tooBigFile); + if (file.size > 2_000_000) throw new ApiError(meta.errors.tooBigFile); if (file.size === 0) throw new ApiError(meta.errors.emptyFile); createImportFollowingJob(user, file.id); diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts index 4165da020..20d240e73 100644 --- a/packages/backend/src/server/api/endpoints/i/import-muting.ts +++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts @@ -1,8 +1,8 @@ -import define from '../../define.js'; -import { createImportMutingJob } from '@/queue/index.js'; -import { ApiError } from '../../error.js'; -import { DriveFiles } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createImportMutingJob } from "@/queue/index.js"; +import { ApiError } from "../../error.js"; +import { DriveFiles } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -15,40 +15,39 @@ export const meta = { errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'e674141e-bd2a-ba85-e616-aefb187c9c2a', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "e674141e-bd2a-ba85-e616-aefb187c9c2a", }, unexpectedFileType: { - message: 'We need csv file.', - code: 'UNEXPECTED_FILE_TYPE', - id: '568c6e42-c86c-ba09-c004-517f83f9f1a8', + message: "We need csv file.", + code: "UNEXPECTED_FILE_TYPE", + id: "568c6e42-c86c-ba09-c004-517f83f9f1a8", }, tooBigFile: { - message: 'That file is too big.', - code: 'TOO_BIG_FILE', - id: '9b4ada6d-d7f7-0472-0713-4f558bd1ec9c', + message: "That file is too big.", + code: "TOO_BIG_FILE", + id: "9b4ada6d-d7f7-0472-0713-4f558bd1ec9c", }, emptyFile: { - message: 'That file is empty.', - code: 'EMPTY_FILE', - id: 'd2f12af1-e7b4-feac-86a3-519548f2728e', + message: "That file is empty.", + code: "EMPTY_FILE", + id: "d2f12af1-e7b4-feac-86a3-519548f2728e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts index 6b3949c99..03b1dffbb 100644 --- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts @@ -1,8 +1,8 @@ -import define from '../../define.js'; -import { createImportUserListsJob } from '@/queue/index.js'; -import { ApiError } from '../../error.js'; -import { DriveFiles } from '@/models/index.js'; -import { HOUR } from '@/const.js'; +import define from "../../define.js"; +import { createImportUserListsJob } from "@/queue/index.js"; +import { ApiError } from "../../error.js"; +import { DriveFiles } from "@/models/index.js"; +import { HOUR } from "@/const.js"; export const meta = { secure: true, @@ -14,40 +14,39 @@ export const meta = { errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'ea9cc34f-c415-4bc6-a6fe-28ac40357049', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "ea9cc34f-c415-4bc6-a6fe-28ac40357049", }, unexpectedFileType: { - message: 'We need csv file.', - code: 'UNEXPECTED_FILE_TYPE', - id: 'a3c9edda-dd9b-4596-be6a-150ef813745c', + message: "We need csv file.", + code: "UNEXPECTED_FILE_TYPE", + id: "a3c9edda-dd9b-4596-be6a-150ef813745c", }, tooBigFile: { - message: 'That file is too big.', - code: 'TOO_BIG_FILE', - id: 'ae6e7a22-971b-4b52-b2be-fc0b9b121fe9', + message: "That file is too big.", + code: "TOO_BIG_FILE", + id: "ae6e7a22-971b-4b52-b2be-fc0b9b121fe9", }, emptyFile: { - message: 'That file is empty.', - code: 'EMPTY_FILE', - id: '99efe367-ce6e-4d44-93f8-5fae7b040356', + message: "That file is empty.", + code: "EMPTY_FILE", + id: "99efe367-ce6e-4d44-93f8-5fae7b040356", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - fileId: { type: 'string', format: 'misskey:id' }, + fileId: { type: "string", format: "misskey:id" }, }, - required: ['fileId'], + required: ["fileId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); diff --git a/packages/backend/src/server/api/endpoints/i/known-as.ts b/packages/backend/src/server/api/endpoints/i/known-as.ts index a7a32aee6..5e86e8b95 100644 --- a/packages/backend/src/server/api/endpoints/i/known-as.ts +++ b/packages/backend/src/server/api/endpoints/i/known-as.ts @@ -49,7 +49,6 @@ export const paramDef = { required: ["alsoKnownAs"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { if (!ps.alsoKnownAs) throw new ApiError(meta.errors.noSuchUser); @@ -59,7 +58,7 @@ export default define(meta, paramDef, async (ps, user) => { if (!unfiltered) { updates.alsoKnownAs = null; } else { - if (unfiltered.startsWith('acct:')) unfiltered = unfiltered.substring(5); + if (unfiltered.startsWith("acct:")) unfiltered = unfiltered.substring(5); if (unfiltered.startsWith("@")) unfiltered = unfiltered.substring(1); if (!unfiltered.includes("@")) throw new ApiError(meta.errors.notRemote); @@ -68,10 +67,10 @@ export default define(meta, paramDef, async (ps, user) => { (e) => { apiLogger.warn(`failed to resolve remote user: ${e}`); throw new ApiError(meta.errors.noSuchUser); - } + }, ); - let toUrl: string | null = knownAs.uri; + const toUrl: string | null = knownAs.uri; if (!toUrl) { throw new ApiError(meta.errors.uriNull); } diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index d22b178b3..bfeba0459 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -1,22 +1,22 @@ -import type { User } from '@/models/entities/user.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { DAY } from '@/const.js'; -import DeliverManager from '@/remote/activitypub/deliver-manager.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { genId } from '@/misc/gen-id.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { apiLogger } from '../../logger.js'; -import deleteFollowing from '@/services/following/delete.js'; -import create from '@/services/following/create.js'; -import { getUser } from '@/server/api/common/getters.js'; -import { Followings, Users } from '@/models/index.js'; -import { UserProfiles } from '@/models/index.js'; -import config from '@/config/index.js'; -import { publishMainStream } from '@/services/stream.js'; +import type { User } from "@/models/entities/user.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { DAY } from "@/const.js"; +import DeliverManager from "@/remote/activitypub/deliver-manager.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { genId } from "@/misc/gen-id.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { apiLogger } from "../../logger.js"; +import deleteFollowing from "@/services/following/delete.js"; +import create from "@/services/following/create.js"; +import { getUser } from "@/server/api/common/getters.js"; +import { Followings, Users } from "@/models/index.js"; +import { UserProfiles } from "@/models/index.js"; +import config from "@/config/index.js"; +import { publishMainStream } from "@/services/stream.js"; export const meta = { - tags: ['users'], + tags: ["users"], secure: true, requireCredential: true, @@ -28,29 +28,30 @@ export const meta = { errors: { noSuchMoveTarget: { - message: 'No such move target.', - code: 'NO_SUCH_MOVE_TARGET', - id: 'b5c90186-4ab0-49c8-9bba-a1f76c202ba4', + message: "No such move target.", + code: "NO_SUCH_MOVE_TARGET", + id: "b5c90186-4ab0-49c8-9bba-a1f76c202ba4", }, remoteAccountForbids: { - message: 'Remote account doesn\'t have proper \'Known As\' alias. Did you remember to set it?', - code: 'REMOTE_ACCOUNT_FORBIDS', - id: 'b5c90186-4ab0-49c8-9bba-a1f766282ba4', + message: + "Remote account doesn't have proper 'Known As' alias. Did you remember to set it?", + code: "REMOTE_ACCOUNT_FORBIDS", + id: "b5c90186-4ab0-49c8-9bba-a1f766282ba4", }, notRemote: { - message: 'User is not remote. You can only migrate to other instances.', - code: 'NOT_REMOTE', - id: '4362f8dc-731f-4ad8-a694-be2a88922a24', + message: "User is not remote. You can only migrate to other instances.", + code: "NOT_REMOTE", + id: "4362f8dc-731f-4ad8-a694-be2a88922a24", }, adminForbidden: { - message: 'Admins cant migrate.', - code: 'NOT_ADMIN_FORBIDDEN', - id: '4362e8dc-731f-4ad8-a694-be2a88922a24', + message: "Admins cant migrate.", + code: "NOT_ADMIN_FORBIDDEN", + id: "4362e8dc-731f-4ad8-a694-be2a88922a24", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5', + message: "No such user.", + code: "NO_SUCH_USER", + id: "fcd2eef9-a9b2-4c4f-8624-038099e90aa5", }, uriNull: { message: "User ActivityPup URI is null.", @@ -71,18 +72,18 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - moveToAccount: { type: 'string' }, + moveToAccount: { type: "string" }, }, - required: ['moveToAccount'], + required: ["moveToAccount"], } as const; function moveActivity(toUrl: string, fromUrl: string) { const activity = { id: genId(), actor: fromUrl, - type: 'Move', + type: "Move", object: fromUrl, target: toUrl, } as any; @@ -90,7 +91,6 @@ function moveActivity(toUrl: string, fromUrl: string) { return renderActivity(activity); } -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { if (!ps.moveToAccount) throw new ApiError(meta.errors.noSuchMoveTarget); if (user.isAdmin) throw new ApiError(meta.errors.adminForbidden); @@ -101,36 +101,39 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchMoveTarget); } - if (unfiltered.startsWith('acct:')) unfiltered = unfiltered.substring(5); - if (unfiltered.startsWith('@')) unfiltered = unfiltered.substring(1); - if (!unfiltered.includes('@')) throw new ApiError(meta.errors.notRemote); + if (unfiltered.startsWith("acct:")) unfiltered = unfiltered.substring(5); + if (unfiltered.startsWith("@")) unfiltered = unfiltered.substring(1); + if (!unfiltered.includes("@")) throw new ApiError(meta.errors.notRemote); - const userAddress: string[] = unfiltered.split('@'); - const moveTo: User = await resolveUser(userAddress[0], userAddress[1]).catch(e => { - apiLogger.warn(`failed to resolve remote user: ${e}`); - throw new ApiError(meta.errors.noSuchMoveTarget); - }); + const userAddress: string[] = unfiltered.split("@"); + const moveTo: User = await resolveUser(userAddress[0], userAddress[1]).catch( + (e) => { + apiLogger.warn(`failed to resolve remote user: ${e}`); + throw new ApiError(meta.errors.noSuchMoveTarget); + }, + ); let fromUrl: string | null = user.uri; - if(!fromUrl) { + if (!fromUrl) { fromUrl = `${config.url}/users/${user.id}`; } let toUrl: string | null = moveTo.uri; - if(!toUrl) { + if (!toUrl) { throw new ApiError(meta.errors.uriNull); } let allowed = false; - moveTo.alsoKnownAs?.forEach(element => { + moveTo.alsoKnownAs?.forEach((element) => { if (fromUrl!.includes(element)) allowed = true; }); - if (!allowed || !toUrl || !fromUrl) throw new ApiError(meta.errors.remoteAccountForbids); + if (!(allowed && toUrl && fromUrl)) + throw new ApiError(meta.errors.remoteAccountForbids); const updates = {} as Partial; - if (!toUrl) toUrl = ''; + if (!toUrl) toUrl = ""; updates.movedToUri = toUrl; await Users.update(user.id, updates); @@ -145,23 +148,26 @@ export default define(meta, paramDef, async (ps, user) => { dm.execute(); // Publish meUpdated event - publishMainStream(user.id, 'meUpdated', iObj); + publishMainStream(user.id, "meUpdated", iObj); const followings = await Followings.findBy({ followeeId: user.id, }); - followings.forEach(async following => { + followings.forEach(async (following) => { //if follower is local if (!following.followerHost) { - const follower = await getUser(following.followerId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const follower = await getUser(following.followerId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); await deleteFollowing(follower!, user); try { await create(follower!, moveTo); - } catch (e) { /* empty */ } + } catch (e) { + /* empty */ + } } }); diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index 2b343dabd..6e1aabef7 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -1,13 +1,19 @@ -import { Brackets } from 'typeorm'; -import { Notifications, Followings, Mutings, Users, UserProfiles } from '@/models/index.js'; -import { notificationTypes } from '@/types.js'; -import read from '@/services/note/read.js'; -import { readNotification } from '../../common/read-notification.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Brackets } from "typeorm"; +import { + Notifications, + Followings, + Mutings, + Users, + UserProfiles, +} from "@/models/index.js"; +import { notificationTypes } from "@/types.js"; +import read from "@/services/note/read.js"; +import { readNotification } from "../../common/read-notification.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'notifications'], + tags: ["account", "notifications"], requireCredential: true, @@ -16,125 +22,161 @@ export const meta = { max: 15, }, - kind: 'read:notifications', + kind: "read:notifications", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Notification', + type: "object", + optional: false, + nullable: false, + ref: "Notification", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - following: { type: 'boolean', default: false }, - unreadOnly: { type: 'boolean', default: false }, - markAsRead: { type: 'boolean', default: true }, - includeTypes: { type: 'array', items: { - type: 'string', enum: notificationTypes, - } }, - excludeTypes: { type: 'array', items: { - type: 'string', enum: notificationTypes, - } }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + following: { type: "boolean", default: false }, + unreadOnly: { type: "boolean", default: false }, + markAsRead: { type: "boolean", default: true }, + includeTypes: { + type: "array", + items: { + type: "string", + enum: notificationTypes, + }, + }, + excludeTypes: { + type: "array", + items: { + type: "string", + enum: notificationTypes, + }, + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // includeTypes が空の場合はクエリしない if (ps.includeTypes && ps.includeTypes.length === 0) { return []; } // excludeTypes に全指定されている場合はクエリしない - if (notificationTypes.every(type => ps.excludeTypes?.includes(type))) { + if (notificationTypes.every((type) => ps.excludeTypes?.includes(type))) { return []; } - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: user.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: user.id }); - const mutingQuery = Mutings.createQueryBuilder('muting') - .select('muting.muteeId') - .where('muting.muterId = :muterId', { muterId: user.id }); + const mutingQuery = Mutings.createQueryBuilder("muting") + .select("muting.muteeId") + .where("muting.muterId = :muterId", { muterId: user.id }); - const mutingInstanceQuery = UserProfiles.createQueryBuilder('user_profile') - .select('user_profile.mutedInstances') - .where('user_profile.userId = :muterId', { muterId: user.id }); + const mutingInstanceQuery = UserProfiles.createQueryBuilder("user_profile") + .select("user_profile.mutedInstances") + .where("user_profile.userId = :muterId", { muterId: user.id }); - const suspendedQuery = Users.createQueryBuilder('users') - .select('users.id') - .where('users.isSuspended = TRUE'); + const suspendedQuery = Users.createQueryBuilder("users") + .select("users.id") + .where("users.isSuspended = TRUE"); - const query = makePaginationQuery(Notifications.createQueryBuilder('notification'), ps.sinceId, ps.untilId) - .andWhere('notification.notifieeId = :meId', { meId: user.id }) - .leftJoinAndSelect('notification.notifier', 'notifier') - .leftJoinAndSelect('notification.note', 'note') - .leftJoinAndSelect('notifier.avatar', 'notifierAvatar') - .leftJoinAndSelect('notifier.banner', 'notifierBanner') - .leftJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notifications.createQueryBuilder("notification"), + ps.sinceId, + ps.untilId, + ) + .andWhere("notification.notifieeId = :meId", { meId: user.id }) + .leftJoinAndSelect("notification.notifier", "notifier") + .leftJoinAndSelect("notification.note", "note") + .leftJoinAndSelect("notifier.avatar", "notifierAvatar") + .leftJoinAndSelect("notifier.banner", "notifierBanner") + .leftJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); // muted users - query.andWhere(new Brackets(qb => { qb - .where(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`) - .orWhere('notification.notifierId IS NULL'); - })); + query.andWhere( + new Brackets((qb) => { + qb.where( + `notification.notifierId NOT IN (${mutingQuery.getQuery()})`, + ).orWhere("notification.notifierId IS NULL"); + }), + ); query.setParameters(mutingQuery.getParameters()); // muted instances - query.andWhere(new Brackets(qb => { qb - .andWhere('notifier.host IS NULL') - .orWhere(`NOT (( ${mutingInstanceQuery.getQuery()} )::jsonb ? notifier.host)`); - })); + query.andWhere( + new Brackets((qb) => { + qb.andWhere("notifier.host IS NULL").orWhere( + `NOT (( ${mutingInstanceQuery.getQuery()} )::jsonb ? notifier.host)`, + ); + }), + ); query.setParameters(mutingInstanceQuery.getParameters()); // suspended users - query.andWhere(new Brackets(qb => { qb - .where(`notification.notifierId NOT IN (${ suspendedQuery.getQuery() })`) - .orWhere('notification.notifierId IS NULL'); - })); + query.andWhere( + new Brackets((qb) => { + qb.where( + `notification.notifierId NOT IN (${suspendedQuery.getQuery()})`, + ).orWhere("notification.notifierId IS NULL"); + }), + ); if (ps.following) { - query.andWhere(`((notification.notifierId IN (${ followingQuery.getQuery() })) OR (notification.notifierId = :meId))`, { meId: user.id }); + query.andWhere( + `((notification.notifierId IN (${followingQuery.getQuery()})) OR (notification.notifierId = :meId))`, + { meId: user.id }, + ); query.setParameters(followingQuery.getParameters()); } if (ps.includeTypes && ps.includeTypes.length > 0) { - query.andWhere('notification.type IN (:...includeTypes)', { includeTypes: ps.includeTypes }); + query.andWhere("notification.type IN (:...includeTypes)", { + includeTypes: ps.includeTypes, + }); } else if (ps.excludeTypes && ps.excludeTypes.length > 0) { - query.andWhere('notification.type NOT IN (:...excludeTypes)', { excludeTypes: ps.excludeTypes }); + query.andWhere("notification.type NOT IN (:...excludeTypes)", { + excludeTypes: ps.excludeTypes, + }); } if (ps.unreadOnly) { - query.andWhere('notification.isRead = false'); + query.andWhere("notification.isRead = false"); } const notifications = await query.take(ps.limit).getMany(); // Mark all as read if (notifications.length > 0 && ps.markAsRead) { - readNotification(user.id, notifications.map(x => x.id)); + readNotification( + user.id, + notifications.map((x) => x.id), + ); } - const notes = notifications.filter(notification => ['mention', 'reply', 'quote'].includes(notification.type)).map(notification => notification.note!); + const notes = notifications + .filter((notification) => + ["mention", "reply", "quote"].includes(notification.type), + ) + .map((notification) => notification.note!); if (notes.length > 0) { read(user.id, notes); diff --git a/packages/backend/src/server/api/endpoints/i/page-likes.ts b/packages/backend/src/server/api/endpoints/i/page-likes.ts index 987387237..1be783a06 100644 --- a/packages/backend/src/server/api/endpoints/i/page-likes.ts +++ b/packages/backend/src/server/api/endpoints/i/page-likes.ts @@ -1,29 +1,32 @@ -import { PageLikes } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { PageLikes } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'pages'], + tags: ["account", "pages"], requireCredential: true, - kind: 'read:page-likes', + kind: "read:page-likes", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, page: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, }, }, @@ -31,24 +34,25 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(PageLikes.createQueryBuilder('like'), ps.sinceId, ps.untilId) - .andWhere('like.userId = :meId', { meId: user.id }) - .leftJoinAndSelect('like.page', 'page'); + const query = makePaginationQuery( + PageLikes.createQueryBuilder("like"), + ps.sinceId, + ps.untilId, + ) + .andWhere("like.userId = :meId", { meId: user.id }) + .leftJoinAndSelect("like.page", "page"); - const likes = await query - .take(ps.limit) - .getMany(); + const likes = await query.take(ps.limit).getMany(); return PageLikes.packMany(likes, user); }); diff --git a/packages/backend/src/server/api/endpoints/i/pages.ts b/packages/backend/src/server/api/endpoints/i/pages.ts index 7e1820d45..78b72e3bc 100644 --- a/packages/backend/src/server/api/endpoints/i/pages.ts +++ b/packages/backend/src/server/api/endpoints/i/pages.ts @@ -1,43 +1,45 @@ -import { Pages } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Pages } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'pages'], + tags: ["account", "pages"], requireCredential: true, - kind: 'read:pages', + kind: "read:pages", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId) - .andWhere('page.userId = :meId', { meId: user.id }); + const query = makePaginationQuery( + Pages.createQueryBuilder("page"), + ps.sinceId, + ps.untilId, + ).andWhere("page.userId = :meId", { meId: user.id }); - const pages = await query - .take(ps.limit) - .getMany(); + const pages = await query.take(ps.limit).getMany(); return await Pages.packMany(pages); }); diff --git a/packages/backend/src/server/api/endpoints/i/pin.ts b/packages/backend/src/server/api/endpoints/i/pin.ts index 67b7026be..40aa57918 100644 --- a/packages/backend/src/server/api/endpoints/i/pin.ts +++ b/packages/backend/src/server/api/endpoints/i/pin.ts @@ -1,56 +1,59 @@ -import { addPinned } from '@/services/i/pin.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Users } from '@/models/index.js'; +import { addPinned } from "@/services/i/pin.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Users } from "@/models/index.js"; export const meta = { - tags: ['account', 'notes'], + tags: ["account", "notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '56734f8b-3928-431e-bf80-6ff87df40cb3', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "56734f8b-3928-431e-bf80-6ff87df40cb3", }, pinLimitExceeded: { - message: 'You can not pin notes any more.', - code: 'PIN_LIMIT_EXCEEDED', - id: '72dab508-c64d-498f-8740-a8eec1ba385a', + message: "You can not pin notes any more.", + code: "PIN_LIMIT_EXCEEDED", + id: "72dab508-c64d-498f-8740-a8eec1ba385a", }, alreadyPinned: { - message: 'That note has already been pinned.', - code: 'ALREADY_PINNED', - id: '8b18c2b7-68fe-4edb-9892-c0cbaeb6c913', + message: "That note has already been pinned.", + code: "ALREADY_PINNED", + id: "8b18c2b7-68fe-4edb-9892-c0cbaeb6c913", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'MeDetailed', + type: "object", + optional: false, + nullable: false, + ref: "MeDetailed", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - await addPinned(user, ps.noteId).catch(e => { - if (e.id === '70c4e51f-5bea-449c-a030-53bee3cce202') throw new ApiError(meta.errors.noSuchNote); - if (e.id === '15a018eb-58e5-4da1-93be-330fcc5e4e1a') throw new ApiError(meta.errors.pinLimitExceeded); - if (e.id === '23f0cf4e-59a3-4276-a91d-61a5891c1514') throw new ApiError(meta.errors.alreadyPinned); + await addPinned(user, ps.noteId).catch((e) => { + if (e.id === "70c4e51f-5bea-449c-a030-53bee3cce202") + throw new ApiError(meta.errors.noSuchNote); + if (e.id === "15a018eb-58e5-4da1-93be-330fcc5e4e1a") + throw new ApiError(meta.errors.pinLimitExceeded); + if (e.id === "23f0cf4e-59a3-4276-a91d-61a5891c1514") + throw new ApiError(meta.errors.alreadyPinned); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts index 7ff6409ca..033367727 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts @@ -1,41 +1,48 @@ -import { publishMainStream } from '@/services/stream.js'; -import define from '../../define.js'; -import { MessagingMessages, UserGroupJoinings } from '@/models/index.js'; +import { publishMainStream } from "@/services/stream.js"; +import define from "../../define.js"; +import { MessagingMessages, UserGroupJoinings } from "@/models/index.js"; export const meta = { - tags: ['account', 'messaging'], + tags: ["account", "messaging"], requireCredential: true, - kind: 'write:account', + kind: "write:account", } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Update documents - await MessagingMessages.update({ - recipientId: user.id, - isRead: false, - }, { - isRead: true, - }); + await MessagingMessages.update( + { + recipientId: user.id, + isRead: false, + }, + { + isRead: true, + }, + ); const joinings = await UserGroupJoinings.findBy({ userId: user.id }); - await Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder().update() - .set({ - reads: (() => `array_append("reads", '${user.id}')`) as any, - }) - .where(`groupId = :groupId`, { groupId: j.userGroupId }) - .andWhere('userId != :userId', { userId: user.id }) - .andWhere('NOT (:userId = ANY(reads))', { userId: user.id }) - .execute())); + await Promise.all( + joinings.map((j) => + MessagingMessages.createQueryBuilder() + .update() + .set({ + reads: (() => `array_append("reads", '${user.id}')`) as any, + }) + .where("groupId = :groupId", { groupId: j.userGroupId }) + .andWhere("userId != :userId", { userId: user.id }) + .andWhere("NOT (:userId = ANY(reads))", { userId: user.id }) + .execute(), + ), + ); - publishMainStream(user.id, 'readAllMessagingMessages'); + publishMainStream(user.id, "readAllMessagingMessages"); }); diff --git a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts index 49f3deb33..8a8857c83 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts @@ -1,22 +1,21 @@ -import { publishMainStream } from '@/services/stream.js'; -import define from '../../define.js'; -import { NoteUnreads } from '@/models/index.js'; +import { publishMainStream } from "@/services/stream.js"; +import define from "../../define.js"; +import { NoteUnreads } from "@/models/index.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'write:account', + kind: "write:account", } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Remove documents await NoteUnreads.delete({ @@ -24,6 +23,6 @@ export default define(meta, paramDef, async (ps, user) => { }); // 全て既読になったイベントを発行 - publishMainStream(user.id, 'readAllUnreadMentions'); - publishMainStream(user.id, 'readAllUnreadSpecifiedNotes'); + publishMainStream(user.id, "readAllUnreadMentions"); + publishMainStream(user.id, "readAllUnreadSpecifiedNotes"); }); diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index 45b6e98c8..5218dba87 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -1,34 +1,33 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { genId } from '@/misc/gen-id.js'; -import { AnnouncementReads, Announcements, Users } from '@/models/index.js'; -import { publishMainStream } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { genId } from "@/misc/gen-id.js"; +import { AnnouncementReads, Announcements, Users } from "@/models/index.js"; +import { publishMainStream } from "@/services/stream.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchAnnouncement: { - message: 'No such announcement.', - code: 'NO_SUCH_ANNOUNCEMENT', - id: '184663db-df88-4bc2-8b52-fb85f0681939', + message: "No such announcement.", + code: "NO_SUCH_ANNOUNCEMENT", + id: "184663db-df88-4bc2-8b52-fb85f0681939", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - announcementId: { type: 'string', format: 'misskey:id' }, + announcementId: { type: "string", format: "misskey:id" }, }, - required: ['announcementId'], + required: ["announcementId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Check if announcement exists const announcement = await Announcements.findOneBy({ id: ps.announcementId }); @@ -55,7 +54,7 @@ export default define(meta, paramDef, async (ps, user) => { userId: user.id, }); - if (!await Users.getHasUnreadAnnouncement(user.id)) { - publishMainStream(user.id, 'readAllAnnouncements'); + if (!(await Users.getHasUnreadAnnouncement(user.id))) { + publishMainStream(user.id, "readAllAnnouncements"); } }); diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index af929b04e..dff37cf3d 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -1,8 +1,12 @@ -import bcrypt from 'bcryptjs'; -import { publishInternalEvent, publishMainStream, publishUserEvent } from '@/services/stream.js'; -import generateUserToken from '../../common/generate-native-user-token.js'; -import define from '../../define.js'; -import { Users, UserProfiles } from '@/models/index.js'; +import bcrypt from "bcryptjs"; +import { + publishInternalEvent, + publishMainStream, + publishUserEvent, +} from "@/services/stream.js"; +import generateUserToken from "../../common/generate-native-user-token.js"; +import define from "../../define.js"; +import { Users, UserProfiles } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -11,14 +15,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, + password: { type: "string" }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const freshUser = await Users.findOneByOrFail({ id: user.id }); const oldToken = freshUser.token; @@ -29,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => { const same = await bcrypt.compare(ps.password, profile.password!); if (!same) { - throw new Error('incorrect password'); + throw new Error("incorrect password"); } const newToken = generateUserToken(); @@ -39,11 +42,15 @@ export default define(meta, paramDef, async (ps, user) => { }); // Publish event - publishInternalEvent('userTokenRegenerated', { id: user.id, oldToken, newToken }); - publishMainStream(user.id, 'myTokenRegenerated'); + publishInternalEvent("userTokenRegenerated", { + id: user.id, + oldToken, + newToken, + }); + publishMainStream(user.id, "myTokenRegenerated"); // Terminate streaming setTimeout(() => { - publishUserEvent(user.id, 'terminate', {}); + publishUserEvent(user.id, "terminate", {}); }, 5000); }); diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts index d0b16dbc4..ee9fe7e9d 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,21 +8,25 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const items = await query.getMany(); diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts index cc5d5a8c6..85900bd74 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts @@ -1,6 +1,6 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { requireCredential: true, @@ -9,31 +9,35 @@ export const meta = { errors: { noSuchKey: { - message: 'No such key.', - code: 'NO_SUCH_KEY', - id: '97a1e8e7-c0f7-47d2-957a-92e61256e01a', + message: "No such key.", + code: "NO_SUCH_KEY", + id: "97a1e8e7-c0f7-47d2-957a-92e61256e01a", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - key: { type: 'string' }, - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + key: { type: "string" }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, - required: ['key'], + required: ["key"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.key = :key', { key: ps.key }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.key = :key", { key: ps.key }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const item = await query.getOne(); diff --git a/packages/backend/src/server/api/endpoints/i/registry/get.ts b/packages/backend/src/server/api/endpoints/i/registry/get.ts index a79319744..b143b7228 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get.ts @@ -1,6 +1,6 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { requireCredential: true, @@ -9,31 +9,35 @@ export const meta = { errors: { noSuchKey: { - message: 'No such key.', - code: 'NO_SUCH_KEY', - id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a', + message: "No such key.", + code: "NO_SUCH_KEY", + id: "ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - key: { type: 'string' }, - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + key: { type: "string" }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, - required: ['key'], + required: ["key"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.key = :key', { key: ps.key }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.key = :key", { key: ps.key }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const item = await query.getOne(); diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts index ac209c06a..23698dc53 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,21 +8,25 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const items = await query.getMany(); @@ -31,13 +35,19 @@ export default define(meta, paramDef, async (ps, user) => { for (const item of items) { const type = typeof item.value; res[item.key] = - item.value === null ? 'null' : - Array.isArray(item.value) ? 'array' : - type === 'number' ? 'number' : - type === 'string' ? 'string' : - type === 'boolean' ? 'boolean' : - type === 'object' ? 'object' : - null as never; + item.value === null + ? "null" + : Array.isArray(item.value) + ? "array" + : type === "number" + ? "number" + : type === "string" + ? "string" + : type === "boolean" + ? "boolean" + : type === "object" + ? "object" + : (null as never); } return res; diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys.ts b/packages/backend/src/server/api/endpoints/i/registry/keys.ts index 5ea1a9d34..ad7d08c5a 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,24 +8,28 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .select('item.key') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .select("item.key") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const items = await query.getMany(); - return items.map(x => x.key); + return items.map((x) => x.key); }); diff --git a/packages/backend/src/server/api/endpoints/i/registry/remove.ts b/packages/backend/src/server/api/endpoints/i/registry/remove.ts index 92473654c..d3793b0e2 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/remove.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/remove.ts @@ -1,6 +1,6 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; -import { ApiError } from '../../../error.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; +import { ApiError } from "../../../error.js"; export const meta = { requireCredential: true, @@ -9,31 +9,35 @@ export const meta = { errors: { noSuchKey: { - message: 'No such key.', - code: 'NO_SUCH_KEY', - id: '1fac4e8a-a6cd-4e39-a4a5-3a7e11f1b019', + message: "No such key.", + code: "NO_SUCH_KEY", + id: "1fac4e8a-a6cd-4e39-a4a5-3a7e11f1b019", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - key: { type: 'string' }, - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + key: { type: "string" }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, - required: ['key'], + required: ["key"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.key = :key', { key: ps.key }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.key = :key", { key: ps.key }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const item = await query.getOne(); diff --git a/packages/backend/src/server/api/endpoints/i/registry/scopes.ts b/packages/backend/src/server/api/endpoints/i/registry/scopes.ts index de4b313e2..3d66359c1 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/scopes.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/scopes.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; export const meta = { requireCredential: true, @@ -8,24 +8,23 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .select('item.scope') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }); + const query = RegistryItems.createQueryBuilder("item") + .select("item.scope") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }); const items = await query.getMany(); const res = [] as string[][]; for (const item of items) { - if (res.some(scope => scope.join('.') === item.scope.join('.'))) continue; + if (res.some((scope) => scope.join(".") === item.scope.join("."))) continue; res.push(item.scope); } diff --git a/packages/backend/src/server/api/endpoints/i/registry/set.ts b/packages/backend/src/server/api/endpoints/i/registry/set.ts index d380b428a..7f9eebd5e 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/set.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/set.ts @@ -1,7 +1,7 @@ -import { publishMainStream } from '@/services/stream.js'; -import define from '../../../define.js'; -import { RegistryItems } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import { publishMainStream } from "@/services/stream.js"; +import define from "../../../define.js"; +import { RegistryItems } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; export const meta = { requireCredential: true, @@ -10,24 +10,28 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - key: { type: 'string', minLength: 1 }, + key: { type: "string", minLength: 1 }, value: {}, - scope: { type: 'array', default: [], items: { - type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), - } }, + scope: { + type: "array", + default: [], + items: { + type: "string", + pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + }, + }, }, - required: ['key', 'value'], + required: ["key", "value"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = RegistryItems.createQueryBuilder('item') - .where('item.domain IS NULL') - .andWhere('item.userId = :userId', { userId: user.id }) - .andWhere('item.key = :key', { key: ps.key }) - .andWhere('item.scope = :scope', { scope: ps.scope }); + const query = RegistryItems.createQueryBuilder("item") + .where("item.domain IS NULL") + .andWhere("item.userId = :userId", { userId: user.id }) + .andWhere("item.key = :key", { key: ps.key }) + .andWhere("item.scope = :scope", { scope: ps.scope }); const existingItem = await query.getOne(); @@ -50,7 +54,7 @@ export default define(meta, paramDef, async (ps, user) => { } // TODO: サードパーティアプリが傍受出来てしまうのでどうにかする - publishMainStream(user.id, 'registryUpdated', { + publishMainStream(user.id, "registryUpdated", { scope: ps.scope, key: ps.key, value: ps.value, diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts index c69245379..308442bf7 100644 --- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts +++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { AccessTokens } from '@/models/index.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { AccessTokens } from "@/models/index.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { requireCredential: true, @@ -9,14 +9,13 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - tokenId: { type: 'string', format: 'misskey:id' }, + tokenId: { type: "string", format: "misskey:id" }, }, - required: ['tokenId'], + required: ["tokenId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const token = await AccessTokens.findOneBy({ id: ps.tokenId }); @@ -27,6 +26,6 @@ export default define(meta, paramDef, async (ps, user) => { }); // Terminate streaming - publishUserEvent(user.id, 'terminate'); + publishUserEvent(user.id, "terminate"); } }); diff --git a/packages/backend/src/server/api/endpoints/i/signin-history.ts b/packages/backend/src/server/api/endpoints/i/signin-history.ts index ca3741166..288b750b7 100644 --- a/packages/backend/src/server/api/endpoints/i/signin-history.ts +++ b/packages/backend/src/server/api/endpoints/i/signin-history.ts @@ -1,6 +1,6 @@ -import define from '../../define.js'; -import { Signins } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { Signins } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { requireCredential: true, @@ -9,21 +9,23 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Signins.createQueryBuilder('signin'), ps.sinceId, ps.untilId) - .andWhere(`signin.userId = :meId`, { meId: user.id }); + const query = makePaginationQuery( + Signins.createQueryBuilder("signin"), + ps.sinceId, + ps.untilId, + ).andWhere("signin.userId = :meId", { meId: user.id }); const history = await query.take(ps.limit).getMany(); - return await Promise.all(history.map(record => Signins.pack(record))); + return await Promise.all(history.map((record) => Signins.pack(record))); }); diff --git a/packages/backend/src/server/api/endpoints/i/unpin.ts b/packages/backend/src/server/api/endpoints/i/unpin.ts index 9912689da..c248eb34e 100644 --- a/packages/backend/src/server/api/endpoints/i/unpin.ts +++ b/packages/backend/src/server/api/endpoints/i/unpin.ts @@ -1,42 +1,43 @@ -import { removePinned } from '@/services/i/pin.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { Users } from '@/models/index.js'; +import { removePinned } from "@/services/i/pin.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { Users } from "@/models/index.js"; export const meta = { - tags: ['account', 'notes'], + tags: ["account", "notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '454170ce-9d63-4a43-9da1-ea10afe81e21', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "454170ce-9d63-4a43-9da1-ea10afe81e21", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'MeDetailed', + type: "object", + optional: false, + nullable: false, + ref: "MeDetailed", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - await removePinned(user, ps.noteId).catch(e => { - if (e.id === 'b302d4cf-c050-400a-bbb3-be208681f40c') throw new ApiError(meta.errors.noSuchNote); + await removePinned(user, ps.noteId).catch((e) => { + if (e.id === "b302d4cf-c050-400a-bbb3-be208681f40c") + throw new ApiError(meta.errors.noSuchNote); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index 7cfb88978..c3c24d4d3 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -1,13 +1,13 @@ -import { publishMainStream } from '@/services/stream.js'; -import define from '../../define.js'; -import rndstr from 'rndstr'; -import config from '@/config/index.js'; -import bcrypt from 'bcryptjs'; -import { Users, UserProfiles } from '@/models/index.js'; -import { sendEmail } from '@/services/send-email.js'; -import { ApiError } from '../../error.js'; -import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; -import { HOUR } from '@/const.js'; +import { publishMainStream } from "@/services/stream.js"; +import define from "../../define.js"; +import rndstr from "rndstr"; +import config from "@/config/index.js"; +import bcrypt from "bcryptjs"; +import { Users, UserProfiles } from "@/models/index.js"; +import { sendEmail } from "@/services/send-email.js"; +import { ApiError } from "../../error.js"; +import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; +import { HOUR } from "@/const.js"; export const meta = { requireCredential: true, @@ -21,29 +21,28 @@ export const meta = { errors: { incorrectPassword: { - message: 'Incorrect password.', - code: 'INCORRECT_PASSWORD', - id: 'e54c1d7e-e7d6-4103-86b6-0a95069b4ad3', + message: "Incorrect password.", + code: "INCORRECT_PASSWORD", + id: "e54c1d7e-e7d6-4103-86b6-0a95069b4ad3", }, unavailable: { - message: 'Unavailable email address.', - code: 'UNAVAILABLE', - id: 'a2defefb-f220-8849-0af6-17f816099323', + message: "Unavailable email address.", + code: "UNAVAILABLE", + id: "a2defefb-f220-8849-0af6-17f816099323", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - password: { type: 'string' }, - email: { type: 'string', nullable: true }, + password: { type: "string" }, + email: { type: "string", nullable: true }, }, - required: ['password'], + required: ["password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -73,10 +72,10 @@ export default define(meta, paramDef, async (ps, user) => { }); // Publish meUpdated event - publishMainStream(user.id, 'meUpdated', iObj); + publishMainStream(user.id, "meUpdated", iObj); if (ps.email != null) { - const code = rndstr('a-z0-9', 16); + const code = rndstr("a-z0-9", 16); await UserProfiles.update(user.id, { emailVerifyCode: code, @@ -84,9 +83,12 @@ export default define(meta, paramDef, async (ps, user) => { const link = `${config.url}/verify-email/${code}`; - sendEmail(ps.email, 'Email verification', + sendEmail( + ps.email, + "Email verification", `To verify email, please click this link:
${link}`, - `To verify email, please click this link: ${link}`); + `To verify email, please click this link: ${link}`, + ); } return iObj; diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 3c2f1cea0..48868de37 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -1,127 +1,139 @@ -import RE2 from 're2'; -import * as mfm from 'mfm-js'; -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; -import acceptAllFollowRequests from '@/services/following/requests/accept-all.js'; -import { publishToFollowers } from '@/services/i/update.js'; -import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; -import { extractHashtags } from '@/misc/extract-hashtags.js'; -import { updateUsertags } from '@/services/update-hashtag.js'; -import { Users, DriveFiles, UserProfiles, Pages } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { notificationTypes } from '@/types.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { langmap } from '@/misc/langmap.js'; -import { ApiError } from '../../error.js'; -import define from '../../define.js'; +import RE2 from "re2"; +import * as mfm from "mfm-js"; +import { publishMainStream, publishUserEvent } from "@/services/stream.js"; +import acceptAllFollowRequests from "@/services/following/requests/accept-all.js"; +import { publishToFollowers } from "@/services/i/update.js"; +import { extractCustomEmojisFromMfm } from "@/misc/extract-custom-emojis-from-mfm.js"; +import { extractHashtags } from "@/misc/extract-hashtags.js"; +import { updateUsertags } from "@/services/update-hashtag.js"; +import { Users, DriveFiles, UserProfiles, Pages } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import type { UserProfile } from "@/models/entities/user-profile.js"; +import { notificationTypes } from "@/types.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; +import { langmap } from "@/misc/langmap.js"; +import { ApiError } from "../../error.js"; +import define from "../../define.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchAvatar: { - message: 'No such avatar file.', - code: 'NO_SUCH_AVATAR', - id: '539f3a45-f215-4f81-a9a8-31293640207f', + message: "No such avatar file.", + code: "NO_SUCH_AVATAR", + id: "539f3a45-f215-4f81-a9a8-31293640207f", }, noSuchBanner: { - message: 'No such banner file.', - code: 'NO_SUCH_BANNER', - id: '0d8f5629-f210-41c2-9433-735831a58595', + message: "No such banner file.", + code: "NO_SUCH_BANNER", + id: "0d8f5629-f210-41c2-9433-735831a58595", }, avatarNotAnImage: { - message: 'The file specified as an avatar is not an image.', - code: 'AVATAR_NOT_AN_IMAGE', - id: 'f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191', + message: "The file specified as an avatar is not an image.", + code: "AVATAR_NOT_AN_IMAGE", + id: "f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191", }, bannerNotAnImage: { - message: 'The file specified as a banner is not an image.', - code: 'BANNER_NOT_AN_IMAGE', - id: '75aedb19-2afd-4e6d-87fc-67941256fa60', + message: "The file specified as a banner is not an image.", + code: "BANNER_NOT_AN_IMAGE", + id: "75aedb19-2afd-4e6d-87fc-67941256fa60", }, noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: '8e01b590-7eb9-431b-a239-860e086c408e', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "8e01b590-7eb9-431b-a239-860e086c408e", }, invalidRegexp: { - message: 'Invalid Regular Expression.', - code: 'INVALID_REGEXP', - id: '0d786918-10df-41cd-8f33-8dec7d9a89a5', + message: "Invalid Regular Expression.", + code: "INVALID_REGEXP", + id: "0d786918-10df-41cd-8f33-8dec7d9a89a5", }, }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'MeDetailed', + type: "object", + optional: false, + nullable: false, + ref: "MeDetailed", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { name: { ...Users.nameSchema, nullable: true }, description: { ...Users.descriptionSchema, nullable: true }, location: { ...Users.locationSchema, nullable: true }, birthday: { ...Users.birthdaySchema, nullable: true }, - lang: { type: 'string', enum: [null, ...Object.keys(langmap)], nullable: true }, - avatarId: { type: 'string', format: 'misskey:id', nullable: true }, - bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + lang: { + type: "string", + enum: [null, ...Object.keys(langmap)], + nullable: true, + }, + avatarId: { type: "string", format: "misskey:id", nullable: true }, + bannerId: { type: "string", format: "misskey:id", nullable: true }, fields: { - type: 'array', + type: "array", minItems: 0, maxItems: 16, items: { - type: 'object', + type: "object", properties: { - name: { type: 'string' }, - value: { type: 'string' }, + name: { type: "string" }, + value: { type: "string" }, }, - required: ['name', 'value'], + required: ["name", "value"], + }, + }, + isLocked: { type: "boolean" }, + isExplorable: { type: "boolean" }, + hideOnlineStatus: { type: "boolean" }, + publicReactions: { type: "boolean" }, + carefulBot: { type: "boolean" }, + autoAcceptFollowed: { type: "boolean" }, + noCrawle: { type: "boolean" }, + isBot: { type: "boolean" }, + isCat: { type: "boolean" }, + showTimelineReplies: { type: "boolean" }, + injectFeaturedNote: { type: "boolean" }, + receiveAnnouncementEmail: { type: "boolean" }, + alwaysMarkNsfw: { type: "boolean" }, + autoSensitive: { type: "boolean" }, + ffVisibility: { type: "string", enum: ["public", "followers", "private"] }, + pinnedPageId: { type: "string", format: "misskey:id", nullable: true }, + mutedWords: { type: "array" }, + mutedInstances: { + type: "array", + items: { + type: "string", + }, + }, + mutingNotificationTypes: { + type: "array", + items: { + type: "string", + enum: notificationTypes, + }, + }, + emailNotificationTypes: { + type: "array", + items: { + type: "string", }, }, - isLocked: { type: 'boolean' }, - isExplorable: { type: 'boolean' }, - hideOnlineStatus: { type: 'boolean' }, - publicReactions: { type: 'boolean' }, - carefulBot: { type: 'boolean' }, - autoAcceptFollowed: { type: 'boolean' }, - noCrawle: { type: 'boolean' }, - isBot: { type: 'boolean' }, - isCat: { type: 'boolean' }, - showTimelineReplies: { type: 'boolean' }, - injectFeaturedNote: { type: 'boolean' }, - receiveAnnouncementEmail: { type: 'boolean' }, - alwaysMarkNsfw: { type: 'boolean' }, - autoSensitive: { type: 'boolean' }, - ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, - pinnedPageId: { type: 'array', items: { - type: 'string', format: 'misskey:id', - } }, - mutedWords: { type: 'array' }, - mutedInstances: { type: 'array', items: { - type: 'string', - } }, - mutingNotificationTypes: { type: 'array', items: { - type: 'string', enum: notificationTypes, - } }, - emailNotificationTypes: { type: 'array', items: { - type: 'string', - } }, }, } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, _user, token) => { const user = await Users.findOneByOrFail({ id: _user.id }); const isSecure = token == null; @@ -136,61 +148,83 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (ps.lang !== undefined) profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday; - if (ps.ffVisibility !== undefined) profileUpdates.ffVisibility = ps.ffVisibility; + if (ps.ffVisibility !== undefined) + profileUpdates.ffVisibility = ps.ffVisibility; if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId; if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId; if (ps.mutedWords !== undefined) { // validate regular expression syntax - ps.mutedWords.filter(x => !Array.isArray(x)).forEach(x => { - const regexp = x.match(/^\/(.+)\/(.*)$/); - if (!regexp) throw new ApiError(meta.errors.invalidRegexp); + ps.mutedWords + .filter((x) => !Array.isArray(x)) + .forEach((x) => { + const regexp = x.match(/^\/(.+)\/(.*)$/); + if (!regexp) throw new ApiError(meta.errors.invalidRegexp); - try { - new RE2(regexp[1], regexp[2]); - } catch (err) { - throw new ApiError(meta.errors.invalidRegexp); - } - }); + try { + new RE2(regexp[1], regexp[2]); + } catch (err) { + throw new ApiError(meta.errors.invalidRegexp); + } + }); profileUpdates.mutedWords = ps.mutedWords; profileUpdates.enableWordMute = ps.mutedWords.length > 0; } - if (ps.mutedInstances !== undefined) profileUpdates.mutedInstances = ps.mutedInstances; - if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes as typeof notificationTypes[number][]; - if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked; - if (typeof ps.isExplorable === 'boolean') updates.isExplorable = ps.isExplorable; - if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus; - if (typeof ps.publicReactions === 'boolean') profileUpdates.publicReactions = ps.publicReactions; - if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot; - if (typeof ps.showTimelineReplies === 'boolean') updates.showTimelineReplies = ps.showTimelineReplies; - if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot; - if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; - if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; - if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; - if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; - if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; - if (typeof ps.alwaysMarkNsfw === 'boolean') profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; - if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive; - if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; + if (ps.mutedInstances !== undefined) + profileUpdates.mutedInstances = ps.mutedInstances; + if (ps.mutingNotificationTypes !== undefined) + profileUpdates.mutingNotificationTypes = + ps.mutingNotificationTypes as typeof notificationTypes[number][]; + if (typeof ps.isLocked === "boolean") updates.isLocked = ps.isLocked; + if (typeof ps.isExplorable === "boolean") + updates.isExplorable = ps.isExplorable; + if (typeof ps.hideOnlineStatus === "boolean") + updates.hideOnlineStatus = ps.hideOnlineStatus; + if (typeof ps.publicReactions === "boolean") + profileUpdates.publicReactions = ps.publicReactions; + if (typeof ps.isBot === "boolean") updates.isBot = ps.isBot; + if (typeof ps.showTimelineReplies === "boolean") + updates.showTimelineReplies = ps.showTimelineReplies; + if (typeof ps.carefulBot === "boolean") + profileUpdates.carefulBot = ps.carefulBot; + if (typeof ps.autoAcceptFollowed === "boolean") + profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; + if (typeof ps.noCrawle === "boolean") profileUpdates.noCrawle = ps.noCrawle; + if (typeof ps.isCat === "boolean") updates.isCat = ps.isCat; + if (typeof ps.injectFeaturedNote === "boolean") + profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; + if (typeof ps.receiveAnnouncementEmail === "boolean") + profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; + if (typeof ps.alwaysMarkNsfw === "boolean") + profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; + if (typeof ps.autoSensitive === "boolean") + profileUpdates.autoSensitive = ps.autoSensitive; + if (ps.emailNotificationTypes !== undefined) + profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; if (ps.avatarId) { const avatar = await DriveFiles.findOneBy({ id: ps.avatarId }); - if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); - if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); + if (avatar == null || avatar.userId !== user.id) + throw new ApiError(meta.errors.noSuchAvatar); + if (!avatar.type.startsWith("image/")) + throw new ApiError(meta.errors.avatarNotAnImage); } if (ps.bannerId) { const banner = await DriveFiles.findOneBy({ id: ps.bannerId }); - if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); - if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); + if (banner == null || banner.userId !== user.id) + throw new ApiError(meta.errors.noSuchBanner); + if (!banner.type.startsWith("image/")) + throw new ApiError(meta.errors.bannerNotAnImage); } if (ps.pinnedPageId) { const page = await Pages.findOneBy({ id: ps.pinnedPageId }); - if (page == null || page.userId !== user.id) throw new ApiError(meta.errors.noSuchPage); + if (page == null || page.userId !== user.id) + throw new ApiError(meta.errors.noSuchPage); profileUpdates.pinnedPageId = page.id; } else if (ps.pinnedPageId === null) { @@ -199,8 +233,14 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (ps.fields) { profileUpdates.fields = ps.fields - .filter(x => typeof x.name === 'string' && x.name !== '' && typeof x.value === 'string' && x.value !== '') - .map(x => { + .filter( + (x) => + typeof x.name === "string" && + x.name !== "" && + typeof x.value === "string" && + x.value !== "", + ) + .map((x) => { return { name: x.name, value: x.value }; }); } @@ -211,7 +251,10 @@ export default define(meta, paramDef, async (ps, _user, token) => { let tags = [] as string[]; const newName = updates.name === undefined ? user.name : updates.name; - const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description; + const newDescription = + profileUpdates.description === undefined + ? profile.description + : profileUpdates.description; if (newName != null) { const tokens = mfm.parseSimple(newName); @@ -221,7 +264,9 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (newDescription != null) { const tokens = mfm.parse(newDescription); emojis = emojis.concat(extractCustomEmojisFromMfm(tokens!)); - tags = extractHashtags(tokens!).map(tag => normalizeForSearch(tag)).splice(0, 32); + tags = extractHashtags(tokens!) + .map((tag) => normalizeForSearch(tag)) + .splice(0, 32); } updates.emojis = emojis; @@ -232,7 +277,8 @@ export default define(meta, paramDef, async (ps, _user, token) => { //#endregion if (Object.keys(updates).length > 0) await Users.update(user.id, updates); - if (Object.keys(profileUpdates).length > 0) await UserProfiles.update(user.id, profileUpdates); + if (Object.keys(profileUpdates).length > 0) + await UserProfiles.update(user.id, profileUpdates); const iObj = await Users.pack(user.id, user, { detail: true, @@ -240,8 +286,12 @@ export default define(meta, paramDef, async (ps, _user, token) => { }); // Publish meUpdated event - publishMainStream(user.id, 'meUpdated', iObj); - publishUserEvent(user.id, 'updateUserProfile', await UserProfiles.findOneBy({ userId: user.id })); + publishMainStream(user.id, "meUpdated", iObj); + publishUserEvent( + user.id, + "updateUserProfile", + await UserProfiles.findOneBy({ userId: user.id }), + ); // 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認 if (user.isLocked && ps.isLocked === false) { diff --git a/packages/backend/src/server/api/endpoints/i/user-group-invites.ts b/packages/backend/src/server/api/endpoints/i/user-group-invites.ts index 1d7e4a16b..d0c6caf0e 100644 --- a/packages/backend/src/server/api/endpoints/i/user-group-invites.ts +++ b/packages/backend/src/server/api/endpoints/i/user-group-invites.ts @@ -1,30 +1,34 @@ -import define from '../../define.js'; -import { UserGroupInvitations } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import define from "../../define.js"; +import { UserGroupInvitations } from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['account', 'groups'], + tags: ["account", "groups"], requireCredential: true, - kind: 'read:user-groups', + kind: "read:user-groups", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, group: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, }, }, @@ -32,24 +36,25 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(UserGroupInvitations.createQueryBuilder('invitation'), ps.sinceId, ps.untilId) - .andWhere(`invitation.userId = :meId`, { meId: user.id }) - .leftJoinAndSelect('invitation.userGroup', 'user_group'); + const query = makePaginationQuery( + UserGroupInvitations.createQueryBuilder("invitation"), + ps.sinceId, + ps.untilId, + ) + .andWhere("invitation.userId = :meId", { meId: user.id }) + .leftJoinAndSelect("invitation.userGroup", "user_group"); - const invitations = await query - .take(ps.limit) - .getMany(); + const invitations = await query.take(ps.limit).getMany(); return await UserGroupInvitations.packMany(invitations); }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index 2e2fd00b8..2b0f1781e 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -1,31 +1,34 @@ -import define from '../../../define.js'; -import { genId } from '@/misc/gen-id.js'; -import { Webhooks } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; -import { webhookEventTypes } from '@/models/entities/webhook.js'; +import define from "../../../define.js"; +import { genId } from "@/misc/gen-id.js"; +import { Webhooks } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; +import { webhookEventTypes } from "@/models/entities/webhook.js"; export const meta = { - tags: ['webhooks'], + tags: ["webhooks"], requireCredential: true, - kind: 'write:account', + kind: "write:account", } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 100 }, - url: { type: 'string', minLength: 1, maxLength: 1024 }, - secret: { type: 'string', minLength: 1, maxLength: 1024 }, - on: { type: 'array', items: { - type: 'string', enum: webhookEventTypes, - } }, + name: { type: "string", minLength: 1, maxLength: 100 }, + url: { type: "string", minLength: 1, maxLength: 1024 }, + secret: { type: "string", minLength: 1, maxLength: 1024 }, + on: { + type: "array", + items: { + type: "string", + enum: webhookEventTypes, + }, + }, }, - required: ['name', 'url', 'secret', 'on'], + required: ["name", "url", "secret", "on"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const webhook = await Webhooks.insert({ id: genId(), @@ -35,9 +38,9 @@ export default define(meta, paramDef, async (ps, user) => { url: ps.url, secret: ps.secret, on: ps.on, - }).then(x => Webhooks.findOneByOrFail(x.identifiers[0])); + }).then((x) => Webhooks.findOneByOrFail(x.identifiers[0])); - publishInternalEvent('webhookCreated', webhook); + publishInternalEvent("webhookCreated", webhook); return webhook; }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts b/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts index 2821eaa5f..4a2c3d83b 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts @@ -1,33 +1,32 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { Webhooks } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { Webhooks } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; export const meta = { - tags: ['webhooks'], + tags: ["webhooks"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchWebhook: { - message: 'No such webhook.', - code: 'NO_SUCH_WEBHOOK', - id: 'bae73e5a-5522-4965-ae19-3a8688e71d82', + message: "No such webhook.", + code: "NO_SUCH_WEBHOOK", + id: "bae73e5a-5522-4965-ae19-3a8688e71d82", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - webhookId: { type: 'string', format: 'misskey:id' }, + webhookId: { type: "string", format: "misskey:id" }, }, - required: ['webhookId'], + required: ["webhookId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const webhook = await Webhooks.findOneBy({ id: ps.webhookId, @@ -40,5 +39,5 @@ export default define(meta, paramDef, async (ps, user) => { await Webhooks.delete(webhook.id); - publishInternalEvent('webhookDeleted', webhook); + publishInternalEvent("webhookDeleted", webhook); }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts index 54e456373..3afead599 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts @@ -1,21 +1,20 @@ -import define from '../../../define.js'; -import { Webhooks } from '@/models/index.js'; +import define from "../../../define.js"; +import { Webhooks } from "@/models/index.js"; export const meta = { - tags: ['webhooks', 'account'], + tags: ["webhooks", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const webhooks = await Webhooks.findBy({ userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts index 02fa1edb5..96c045747 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts @@ -1,32 +1,31 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { Webhooks } from '@/models/index.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { Webhooks } from "@/models/index.js"; export const meta = { - tags: ['webhooks'], + tags: ["webhooks"], requireCredential: true, - kind: 'read:account', + kind: "read:account", errors: { noSuchWebhook: { - message: 'No such webhook.', - code: 'NO_SUCH_WEBHOOK', - id: '50f614d9-3047-4f7e-90d8-ad6b2d5fb098', + message: "No such webhook.", + code: "NO_SUCH_WEBHOOK", + id: "50f614d9-3047-4f7e-90d8-ad6b2d5fb098", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - webhookId: { type: 'string', format: 'misskey:id' }, + webhookId: { type: "string", format: "misskey:id" }, }, - required: ['webhookId'], + required: ["webhookId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const webhook = await Webhooks.findOneBy({ id: ps.webhookId, diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts index f87b9753f..161d705e1 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts @@ -1,42 +1,44 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { Webhooks } from '@/models/index.js'; -import { publishInternalEvent } from '@/services/stream.js'; -import { webhookEventTypes } from '@/models/entities/webhook.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { Webhooks } from "@/models/index.js"; +import { publishInternalEvent } from "@/services/stream.js"; +import { webhookEventTypes } from "@/models/entities/webhook.js"; export const meta = { - tags: ['webhooks'], + tags: ["webhooks"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchWebhook: { - message: 'No such webhook.', - code: 'NO_SUCH_WEBHOOK', - id: 'fb0fea69-da18-45b1-828d-bd4fd1612518', + message: "No such webhook.", + code: "NO_SUCH_WEBHOOK", + id: "fb0fea69-da18-45b1-828d-bd4fd1612518", }, }, - } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - webhookId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 100 }, - url: { type: 'string', minLength: 1, maxLength: 1024 }, - secret: { type: 'string', minLength: 1, maxLength: 1024 }, - on: { type: 'array', items: { - type: 'string', enum: webhookEventTypes, - } }, - active: { type: 'boolean' }, + webhookId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 100 }, + url: { type: "string", minLength: 1, maxLength: 1024 }, + secret: { type: "string", minLength: 1, maxLength: 1024 }, + on: { + type: "array", + items: { + type: "string", + enum: webhookEventTypes, + }, + }, + active: { type: "boolean" }, }, - required: ['webhookId', 'name', 'url', 'secret', 'on', 'active'], + required: ["webhookId", "name", "url", "secret", "on", "active"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const webhook = await Webhooks.findOneBy({ id: ps.webhookId, @@ -55,5 +57,5 @@ export default define(meta, paramDef, async (ps, user) => { active: ps.active, }); - publishInternalEvent('webhookUpdated', webhook); + publishInternalEvent("webhookUpdated", webhook); }); diff --git a/packages/backend/src/server/api/endpoints/latest-version.ts b/packages/backend/src/server/api/endpoints/latest-version.ts index b319da9e3..72e84ae04 100644 --- a/packages/backend/src/server/api/endpoints/latest-version.ts +++ b/packages/backend/src/server/api/endpoints/latest-version.ts @@ -1,22 +1,23 @@ -import define from '../define.js'; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { let tag_name; - await fetch('https://codeberg.org/api/v1/repos/calckey/calckey/releases?draft=false&pre-release=false&page=1&limit=1') + await fetch( + "https://codeberg.org/api/v1/repos/calckey/calckey/releases?draft=false&pre-release=false&page=1&limit=1", + ) .then((response) => response.json()) .then((data) => { tag_name = data[0].tag_name; diff --git a/packages/backend/src/server/api/endpoints/messaging/history.ts b/packages/backend/src/server/api/endpoints/messaging/history.ts index 241cbbbc1..7d1df6985 100644 --- a/packages/backend/src/server/api/endpoints/messaging/history.ts +++ b/packages/backend/src/server/api/endpoints/messaging/history.ts @@ -1,44 +1,51 @@ -import { Brackets } from 'typeorm'; -import type { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { MessagingMessages, Mutings, UserGroupJoinings } from '@/models/index.js'; -import define from '../../define.js'; +import { Brackets } from "typeorm"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { + MessagingMessages, + Mutings, + UserGroupJoinings, +} from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['messaging'], + tags: ["messaging"], requireCredential: true, - kind: 'read:messaging', + kind: "read:messaging", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'MessagingMessage', + type: "object", + optional: false, + nullable: false, + ref: "MessagingMessage", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - group: { type: 'boolean', default: false }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + group: { type: "boolean", default: false }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const mute = await Mutings.findBy({ muterId: user.id, }); - const groups = ps.group ? await UserGroupJoinings.findBy({ - userId: user.id, - }).then(xs => xs.map(x => x.userGroupId)) : []; + const groups = ps.group + ? await UserGroupJoinings.findBy({ + userId: user.id, + }).then((xs) => xs.map((x) => x.userGroupId)) + : []; if (ps.group && groups.length === 0) { return []; @@ -48,33 +55,45 @@ export default define(meta, paramDef, async (ps, user) => { for (let i = 0; i < ps.limit; i++) { const found = ps.group - ? history.map(m => m.groupId!) - : history.map(m => (m.userId === user.id) ? m.recipientId! : m.userId!); + ? history.map((m) => m.groupId!) + : history.map((m) => (m.userId === user.id ? m.recipientId! : m.userId!)); - const query = MessagingMessages.createQueryBuilder('message') - .orderBy('message.createdAt', 'DESC'); + const query = MessagingMessages.createQueryBuilder("message").orderBy( + "message.createdAt", + "DESC", + ); if (ps.group) { - query.where('message.groupId IN (:...groups)', { groups: groups }); + query.where("message.groupId IN (:...groups)", { groups: groups }); if (found.length > 0) { - query.andWhere('message.groupId NOT IN (:...found)', { found: found }); + query.andWhere("message.groupId NOT IN (:...found)", { found: found }); } } else { - query.where(new Brackets(qb => { qb - .where('message.userId = :userId', { userId: user.id }) - .orWhere('message.recipientId = :userId', { userId: user.id }); - })); - query.andWhere('message.groupId IS NULL'); + query.where( + new Brackets((qb) => { + qb.where("message.userId = :userId", { userId: user.id }).orWhere( + "message.recipientId = :userId", + { userId: user.id }, + ); + }), + ); + query.andWhere("message.groupId IS NULL"); if (found.length > 0) { - query.andWhere('message.userId NOT IN (:...found)', { found: found }); - query.andWhere('message.recipientId NOT IN (:...found)', { found: found }); + query.andWhere("message.userId NOT IN (:...found)", { found: found }); + query.andWhere("message.recipientId NOT IN (:...found)", { + found: found, + }); } if (mute.length > 0) { - query.andWhere('message.userId NOT IN (:...mute)', { mute: mute.map(m => m.muteeId) }); - query.andWhere('message.recipientId NOT IN (:...mute)', { mute: mute.map(m => m.muteeId) }); + query.andWhere("message.userId NOT IN (:...mute)", { + mute: mute.map((m) => m.muteeId), + }); + query.andWhere("message.recipientId NOT IN (:...mute)", { + mute: mute.map((m) => m.muteeId), + }); } } @@ -87,5 +106,7 @@ export default define(meta, paramDef, async (ps, user) => { } } - return await Promise.all(history.map(h => MessagingMessages.pack(h.id, user))); + return await Promise.all( + history.map((h) => MessagingMessages.pack(h.id, user)), + ); }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages.ts b/packages/backend/src/server/api/endpoints/messaging/messages.ts index dbf1f6c86..4b5440383 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages.ts @@ -1,101 +1,127 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { MessagingMessages, UserGroups, UserGroupJoinings, Users } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { Brackets } from 'typeorm'; -import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { + MessagingMessages, + UserGroups, + UserGroupJoinings, + Users, +} from "@/models/index.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { Brackets } from "typeorm"; +import { + readUserMessagingMessage, + readGroupMessagingMessage, + deliverReadActivity, +} from "../../common/read-messaging-message.js"; export const meta = { - tags: ['messaging'], + tags: ["messaging"], requireCredential: true, - kind: 'read:messaging', + kind: "read:messaging", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'MessagingMessage', + type: "object", + optional: false, + nullable: false, + ref: "MessagingMessage", }, }, errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '11795c64-40ea-4198-b06e-3c873ed9039d', + message: "No such user.", + code: "NO_SUCH_USER", + id: "11795c64-40ea-4198-b06e-3c873ed9039d", }, noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: 'c4d9f88c-9270-4632-b032-6ed8cee36f7f', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "c4d9f88c-9270-4632-b032-6ed8cee36f7f", }, groupAccessDenied: { - message: 'You can not read messages of groups that you have not joined.', - code: 'GROUP_ACCESS_DENIED', - id: 'a053a8dd-a491-4718-8f87-50775aad9284', + message: "You can not read messages of groups that you have not joined.", + code: "GROUP_ACCESS_DENIED", + id: "a053a8dd-a491-4718-8f87-50775aad9284", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - markAsRead: { type: 'boolean', default: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + markAsRead: { type: "boolean", default: true }, }, anyOf: [ { properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], }, { properties: { - groupId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, }, - required: ['groupId'], + required: ["groupId"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { if (ps.userId != null) { // Fetch recipient (user) - const recipient = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const recipient = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); - const query = makePaginationQuery(MessagingMessages.createQueryBuilder('message'), ps.sinceId, ps.untilId) - .andWhere(new Brackets(qb => { qb - .where(new Brackets(qb => { qb - .where('message.userId = :meId') - .andWhere('message.recipientId = :recipientId'); - })) - .orWhere(new Brackets(qb => { qb - .where('message.userId = :recipientId') - .andWhere('message.recipientId = :meId'); - })); - })) - .setParameter('meId', user.id) - .setParameter('recipientId', recipient.id); + const query = makePaginationQuery( + MessagingMessages.createQueryBuilder("message"), + ps.sinceId, + ps.untilId, + ) + .andWhere( + new Brackets((qb) => { + qb.where( + new Brackets((qb) => { + qb.where("message.userId = :meId").andWhere( + "message.recipientId = :recipientId", + ); + }), + ).orWhere( + new Brackets((qb) => { + qb.where("message.userId = :recipientId").andWhere( + "message.recipientId = :meId", + ); + }), + ); + }), + ) + .setParameter("meId", user.id) + .setParameter("recipientId", recipient.id); const messages = await query.take(ps.limit).getMany(); // Mark all as read if (ps.markAsRead) { - readUserMessagingMessage(user.id, recipient.id, messages.filter(m => m.recipientId === user.id).map(x => x.id)); + readUserMessagingMessage( + user.id, + recipient.id, + messages.filter((m) => m.recipientId === user.id).map((x) => x.id), + ); // リモートユーザーとのメッセージだったら既読配信 if (Users.isLocalUser(user) && Users.isRemoteUser(recipient)) { @@ -103,9 +129,13 @@ export default define(meta, paramDef, async (ps, user) => { } } - return await Promise.all(messages.map(message => MessagingMessages.pack(message, user, { - populateRecipient: false, - }))); + return await Promise.all( + messages.map((message) => + MessagingMessages.pack(message, user, { + populateRecipient: false, + }), + ), + ); } else if (ps.groupId != null) { // Fetch recipient (group) const recipientGroup = await UserGroups.findOneBy({ id: ps.groupId }); @@ -124,18 +154,29 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.groupAccessDenied); } - const query = makePaginationQuery(MessagingMessages.createQueryBuilder('message'), ps.sinceId, ps.untilId) - .andWhere(`message.groupId = :groupId`, { groupId: recipientGroup.id }); + const query = makePaginationQuery( + MessagingMessages.createQueryBuilder("message"), + ps.sinceId, + ps.untilId, + ).andWhere("message.groupId = :groupId", { groupId: recipientGroup.id }); const messages = await query.take(ps.limit).getMany(); // Mark all as read if (ps.markAsRead) { - readGroupMessagingMessage(user.id, recipientGroup.id, messages.map(x => x.id)); + readGroupMessagingMessage( + user.id, + recipientGroup.id, + messages.map((x) => x.id), + ); } - return await Promise.all(messages.map(message => MessagingMessages.pack(message, user, { - populateGroup: false, - }))); + return await Promise.all( + messages.map((message) => + MessagingMessages.pack(message, user, { + populateGroup: false, + }), + ), + ); } }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts index 405af5ec1..99d392ce4 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts @@ -1,92 +1,99 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; -import { MessagingMessages, DriveFiles, UserGroups, UserGroupJoinings, Blockings } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { createMessage } from '@/services/messages/create.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; +import { + MessagingMessages, + DriveFiles, + UserGroups, + UserGroupJoinings, + Blockings, +} from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import { createMessage } from "@/services/messages/create.js"; export const meta = { - tags: ['messaging'], + tags: ["messaging"], requireCredential: true, - kind: 'write:messaging', + kind: "write:messaging", res: { - type: 'object', - optional: false, nullable: false, - ref: 'MessagingMessage', + type: "object", + optional: false, + nullable: false, + ref: "MessagingMessage", }, errors: { recipientIsYourself: { - message: 'You can not send a message to yourself.', - code: 'RECIPIENT_IS_YOURSELF', - id: '17e2ba79-e22a-4cbc-bf91-d327643f4a7e', + message: "You can not send a message to yourself.", + code: "RECIPIENT_IS_YOURSELF", + id: "17e2ba79-e22a-4cbc-bf91-d327643f4a7e", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '11795c64-40ea-4198-b06e-3c873ed9039d', + message: "No such user.", + code: "NO_SUCH_USER", + id: "11795c64-40ea-4198-b06e-3c873ed9039d", }, noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: 'c94e2a5d-06aa-4914-8fa6-6a42e73d6537', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "c94e2a5d-06aa-4914-8fa6-6a42e73d6537", }, groupAccessDenied: { - message: 'You can not send messages to groups that you have not joined.', - code: 'GROUP_ACCESS_DENIED', - id: 'd96b3cca-5ad1-438b-ad8b-02f931308fbd', + message: "You can not send messages to groups that you have not joined.", + code: "GROUP_ACCESS_DENIED", + id: "d96b3cca-5ad1-438b-ad8b-02f931308fbd", }, noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: '4372b8e2-185d-4146-8749-2f68864a3e5f', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "4372b8e2-185d-4146-8749-2f68864a3e5f", }, contentRequired: { - message: 'Content required. You need to set text or fileId.', - code: 'CONTENT_REQUIRED', - id: '25587321-b0e6-449c-9239-f8925092942c', + message: "Content required. You need to set text or fileId.", + code: "CONTENT_REQUIRED", + id: "25587321-b0e6-449c-9239-f8925092942c", }, youHaveBeenBlocked: { - message: 'You cannot send a message because you have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: 'c15a5199-7422-4968-941a-2a462c478f7d', + message: + "You cannot send a message because you have been blocked by this user.", + code: "YOU_HAVE_BEEN_BLOCKED", + id: "c15a5199-7422-4968-941a-2a462c478f7d", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - text: { type: 'string', nullable: true, maxLength: 3000 }, - fileId: { type: 'string', format: 'misskey:id' }, + text: { type: "string", nullable: true, maxLength: 3000 }, + fileId: { type: "string", format: "misskey:id" }, }, anyOf: [ { properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], }, { properties: { - groupId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, }, - required: ['groupId'], + required: ["groupId"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { let recipientUser: User | null; let recipientGroup: UserGroup | null; @@ -98,8 +105,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Fetch recipient (user) - recipientUser = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + recipientUser = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -147,5 +155,11 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.contentRequired); } - return await createMessage(user, recipientUser, recipientGroup, ps.text, file); + return await createMessage( + user, + recipientUser, + recipientGroup, + ps.text, + file, + ); }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts index 17d295700..42ff050d1 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts @@ -1,15 +1,15 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { MessagingMessages } from '@/models/index.js'; -import { deleteMessage } from '@/services/messages/delete.js'; -import { SECOND, HOUR } from '@/const.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { MessagingMessages } from "@/models/index.js"; +import { deleteMessage } from "@/services/messages/delete.js"; +import { SECOND, HOUR } from "@/const.js"; export const meta = { - tags: ['messaging'], + tags: ["messaging"], requireCredential: true, - kind: 'write:messaging', + kind: "write:messaging", limit: { duration: HOUR, @@ -19,22 +19,21 @@ export const meta = { errors: { noSuchMessage: { - message: 'No such message.', - code: 'NO_SUCH_MESSAGE', - id: '54b5b326-7925-42cf-8019-130fda8b56af', + message: "No such message.", + code: "NO_SUCH_MESSAGE", + id: "54b5b326-7925-42cf-8019-130fda8b56af", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - messageId: { type: 'string', format: 'misskey:id' }, + messageId: { type: "string", format: "misskey:id" }, }, - required: ['messageId'], + required: ["messageId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const message = await MessagingMessages.findOneBy({ id: ps.messageId, diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts index db12ae922..0ef013b79 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts @@ -1,33 +1,35 @@ -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { MessagingMessages } from '@/models/index.js'; -import { readUserMessagingMessage, readGroupMessagingMessage } from '../../../common/read-messaging-message.js'; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { MessagingMessages } from "@/models/index.js"; +import { + readUserMessagingMessage, + readGroupMessagingMessage, +} from "../../../common/read-messaging-message.js"; export const meta = { - tags: ['messaging'], + tags: ["messaging"], requireCredential: true, - kind: 'write:messaging', + kind: "write:messaging", errors: { noSuchMessage: { - message: 'No such message.', - code: 'NO_SUCH_MESSAGE', - id: '86d56a2f-a9c3-4afb-b13c-3e9bfef9aa14', + message: "No such message.", + code: "NO_SUCH_MESSAGE", + id: "86d56a2f-a9c3-4afb-b13c-3e9bfef9aa14", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - messageId: { type: 'string', format: 'misskey:id' }, + messageId: { type: "string", format: "misskey:id" }, }, - required: ['messageId'], + required: ["messageId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const message = await MessagingMessages.findOneBy({ id: ps.messageId }); @@ -36,13 +38,19 @@ export default define(meta, paramDef, async (ps, user) => { } if (message.recipientId) { - await readUserMessagingMessage(user.id, message.userId, [message.id]).catch(e => { - if (e.id === 'e140a4bf-49ce-4fb6-b67c-b78dadf6b52f') throw new ApiError(meta.errors.noSuchMessage); - throw e; - }); + await readUserMessagingMessage(user.id, message.userId, [message.id]).catch( + (e) => { + if (e.id === "e140a4bf-49ce-4fb6-b67c-b78dadf6b52f") + throw new ApiError(meta.errors.noSuchMessage); + throw e; + }, + ); } else if (message.groupId) { - await readGroupMessagingMessage(user.id, message.groupId, [message.id]).catch(e => { - if (e.id === '930a270c-714a-46b2-b776-ad27276dc569') throw new ApiError(meta.errors.noSuchMessage); + await readGroupMessagingMessage(user.id, message.groupId, [ + message.id, + ]).catch((e) => { + if (e.id === "930a270c-714a-46b2-b776-ad27276dc569") + throw new ApiError(meta.errors.noSuchMessage); throw e; }); } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index f61236fa0..005d0800a 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,327 +1,401 @@ -import { IsNull, MoreThan } from 'typeorm'; -import config from '@/config/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Ads, Emojis, Users } from '@/models/index.js'; -import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; -import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import define from '../define.js'; +import { IsNull, MoreThan } from "typeorm"; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Ads, Emojis, Users } from "@/models/index.js"; +import { DB_MAX_NOTE_TEXT_LENGTH } from "@/misc/hard-limits.js"; +import { MAX_NOTE_TEXT_LENGTH } from "@/const.js"; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { maintainerName: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, maintainerEmail: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, version: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, example: config.version, }, name: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, uri: { - type: 'string', - optional: false, nullable: false, - format: 'url', - example: 'https://calckey.example.com', + type: "string", + optional: false, + nullable: false, + format: "url", + example: "https://calckey.example.com", }, description: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, langs: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, tosUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, repositoryUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://codeberg.org/calckey/calckey', + type: "string", + optional: false, + nullable: false, + default: "https://codeberg.org/calckey/calckey", }, feedbackUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://codeberg.org/calckey/calckey/issues', + type: "string", + optional: false, + nullable: false, + default: "https://codeberg.org/calckey/calckey/issues", }, defaultDarkTheme: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, defaultLightTheme: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, disableRegistration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, disableLocalTimeline: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, disableRecommendedTimeline: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, disableGlobalTimeline: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, driveCapacityPerLocalUserMb: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, driveCapacityPerRemoteUserMb: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, cacheRemoteFiles: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, emailRequiredForSignup: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableHcaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hcaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, enableRecaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, recaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, swPublickey: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, mascotImageUrl: { - type: 'string', - optional: false, nullable: false, - default: '/assets/ai.png', + type: "string", + optional: false, + nullable: false, + default: "/assets/ai.png", }, bannerUrl: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, errorImageUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://xn--931a.moe/aiart/yubitun.png', + type: "string", + optional: false, + nullable: false, + default: "https://xn--931a.moe/aiart/yubitun.png", }, iconUrl: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, maxNoteTextLength: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, emojis: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, aliases: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, category: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, host: { - type: 'string', - optional: false, nullable: true, - description: 'The local host is represented with `null`.', + type: "string", + optional: false, + nullable: true, + description: "The local host is represented with `null`.", }, url: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, }, }, }, ads: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { place: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, url: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, imageUrl: { - type: 'string', - optional: false, nullable: false, - format: 'url', + type: "string", + optional: false, + nullable: false, + format: "url", }, }, }, }, requireSetup: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, example: false, }, enableEmail: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableTwitterIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableGithubIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableDiscordIntegration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, enableServiceWorker: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, translatorAvailable: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, proxyAccountName: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, features: { - type: 'object', - optional: true, nullable: false, + type: "object", + optional: true, + nullable: false, properties: { registration: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, localTimeLine: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, recommendedTimeLine: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, globalTimeLine: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, elasticsearch: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hcaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, recaptcha: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, objectStorage: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, twitter: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, github: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, discord: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, serviceWorker: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, miauth: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, default: true, }, }, }, secureMode: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, default: false, }, privateMode: { - type: 'boolean', - optional: true, nullable: false, + type: "boolean", + optional: true, + nullable: false, default: false, }, + defaultReaction: { + type: "string", + optional: "false", + nullable: false, + default: "⭐", + }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - detail: { type: 'boolean', default: true }, + detail: { type: "boolean", default: true }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const instance = await fetchMeta(true); @@ -330,12 +404,12 @@ export default define(meta, paramDef, async (ps, me) => { host: IsNull(), }, order: { - category: 'ASC', - name: 'ASC', + category: "ASC", + name: "ASC", }, cache: { - id: 'meta_emojis', - milliseconds: 3600000, // 1 hour + id: "meta_emojis", + milliseconds: 3600000, // 1 hour }, }); @@ -385,13 +459,16 @@ export default define(meta, paramDef, async (ps, me) => { emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis), defaultLightTheme: instance.defaultLightTheme, defaultDarkTheme: instance.defaultDarkTheme, - ads: instance.privateMode && !me ? [] : ads.map(ad => ({ - id: ad.id, - url: ad.url, - place: ad.place, - ratio: ad.ratio, - imageUrl: ad.imageUrl, - })), + ads: + instance.privateMode && !me + ? [] + : ads.map((ad) => ({ + id: ad.id, + url: ad.url, + place: ad.place, + ratio: ad.ratio, + imageUrl: ad.imageUrl, + })), enableEmail: instance.enableEmail, enableTwitterIntegration: instance.enableTwitterIntegration, @@ -401,20 +478,27 @@ export default define(meta, paramDef, async (ps, me) => { enableServiceWorker: instance.enableServiceWorker, translatorAvailable: instance.deeplAuthKey != null, + defaultReaction: instance.defaultReaction, - ...(ps.detail ? { - pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages, - pinnedClipId: instance.privateMode && !me ? [] : instance.pinnedClipId, - cacheRemoteFiles: instance.cacheRemoteFiles, - requireSetup: (await Users.countBy({ - host: IsNull(), - })) === 0, - } : {}), + ...(ps.detail + ? { + pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages, + pinnedClipId: + instance.privateMode && !me ? [] : instance.pinnedClipId, + cacheRemoteFiles: instance.cacheRemoteFiles, + requireSetup: + (await Users.countBy({ + host: IsNull(), + })) === 0, + } + : {}), }; if (ps.detail) { if (!instance.privateMode || me) { - const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null; + const proxyAccount = instance.proxyAccountId + ? await Users.pack(instance.proxyAccountId).catch(() => null) + : null; response.proxyAccountName = proxyAccount ? proxyAccount.username : null; } diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts index 73ecdaeb0..0525d79a7 100644 --- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts +++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts @@ -1,42 +1,47 @@ -import define from '../../define.js'; -import { AccessTokens } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { secureRndstr } from '@/misc/secure-rndstr.js'; +import define from "../../define.js"; +import { AccessTokens } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { secureRndstr } from "@/misc/secure-rndstr.js"; export const meta = { - tags: ['auth'], + tags: ["auth"], requireCredential: true, secure: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { token: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - session: { type: 'string', nullable: true }, - name: { type: 'string', nullable: true }, - description: { type: 'string', nullable: true }, - iconUrl: { type: 'string', nullable: true }, - permission: { type: 'array', uniqueItems: true, items: { - type: 'string', - } }, + session: { type: "string", nullable: true }, + name: { type: "string", nullable: true }, + description: { type: "string", nullable: true }, + iconUrl: { type: "string", nullable: true }, + permission: { + type: "array", + uniqueItems: true, + items: { + type: "string", + }, + }, }, - required: ['session', 'permission'], + required: ["session", "permission"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Generate access token const accessToken = secureRndstr(32, true); diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index 7e857e673..bacab9b45 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -1,53 +1,53 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { genId } from '@/misc/gen-id.js'; -import { Mutings, NoteWatchings } from '@/models/index.js'; -import { Muting } from '@/models/entities/muting.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { genId } from "@/misc/gen-id.js"; +import { Mutings, NoteWatchings } from "@/models/index.js"; +import type { Muting } from "@/models/entities/muting.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'write:mutes', + kind: "write:mutes", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '6fef56f3-e765-4957-88e5-c6f65329b8a5', + message: "No such user.", + code: "NO_SUCH_USER", + id: "6fef56f3-e765-4957-88e5-c6f65329b8a5", }, muteeIsYourself: { - message: 'Mutee is yourself.', - code: 'MUTEE_IS_YOURSELF', - id: 'a4619cb2-5f23-484b-9301-94c903074e10', + message: "Mutee is yourself.", + code: "MUTEE_IS_YOURSELF", + id: "a4619cb2-5f23-484b-9301-94c903074e10", }, alreadyMuting: { - message: 'You are already muting that user.', - code: 'ALREADY_MUTING', - id: '7e7359cb-160c-4956-b08f-4d1c653cd007', + message: "You are already muting that user.", + code: "ALREADY_MUTING", + id: "7e7359cb-160c-4956-b08f-4d1c653cd007", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, expiresAt: { - type: 'integer', + type: "integer", nullable: true, - description: 'A Unix Epoch timestamp that must lie in the future. `null` means an indefinite mute.', + description: + "A Unix Epoch timestamp that must lie in the future. `null` means an indefinite mute.", }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const muter = user; @@ -57,8 +57,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get mutee - const mutee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const mutee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -85,7 +86,7 @@ export default define(meta, paramDef, async (ps, user) => { muteeId: mutee.id, } as Muting); - publishUserEvent(user.id, 'mute', mutee); + publishUserEvent(user.id, "mute", mutee); NoteWatchings.delete({ userId: muter.id, diff --git a/packages/backend/src/server/api/endpoints/mute/delete.ts b/packages/backend/src/server/api/endpoints/mute/delete.ts index 0b173dbe2..cc67a44c2 100644 --- a/packages/backend/src/server/api/endpoints/mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/mute/delete.ts @@ -1,46 +1,45 @@ -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { Mutings } from '@/models/index.js'; -import { publishUserEvent } from '@/services/stream.js'; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { Mutings } from "@/models/index.js"; +import { publishUserEvent } from "@/services/stream.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'write:mutes', + kind: "write:mutes", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'b851d00b-8ab1-4a56-8b1b-e24187cb48ef', + message: "No such user.", + code: "NO_SUCH_USER", + id: "b851d00b-8ab1-4a56-8b1b-e24187cb48ef", }, muteeIsYourself: { - message: 'Mutee is yourself.', - code: 'MUTEE_IS_YOURSELF', - id: 'f428b029-6b39-4d48-a1d2-cc1ae6dd5cf9', + message: "Mutee is yourself.", + code: "MUTEE_IS_YOURSELF", + id: "f428b029-6b39-4d48-a1d2-cc1ae6dd5cf9", }, notMuting: { - message: 'You are not muting that user.', - code: 'NOT_MUTING', - id: '5467d020-daa9-4553-81e1-135c0c35a96d', + message: "You are not muting that user.", + code: "NOT_MUTING", + id: "5467d020-daa9-4553-81e1-135c0c35a96d", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const muter = user; @@ -50,8 +49,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Get mutee - const mutee = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const mutee = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -70,5 +70,5 @@ export default define(meta, paramDef, async (ps, user) => { id: exist.id, }); - publishUserEvent(user.id, 'unmute', mutee); + publishUserEvent(user.id, "unmute", mutee); }); diff --git a/packages/backend/src/server/api/endpoints/mute/list.ts b/packages/backend/src/server/api/endpoints/mute/list.ts index 31283cf4c..7bbe29a4c 100644 --- a/packages/backend/src/server/api/endpoints/mute/list.ts +++ b/packages/backend/src/server/api/endpoints/mute/list.ts @@ -1,43 +1,45 @@ -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { Mutings } from '@/models/index.js'; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { Mutings } from "@/models/index.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - kind: 'read:mutes', + kind: "read:mutes", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Muting', + type: "object", + optional: false, + nullable: false, + ref: "Muting", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 30 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Mutings.createQueryBuilder('muting'), ps.sinceId, ps.untilId) - .andWhere(`muting.muterId = :meId`, { meId: me.id }); + const query = makePaginationQuery( + Mutings.createQueryBuilder("muting"), + ps.sinceId, + ps.untilId, + ).andWhere("muting.muterId = :meId", { meId: me.id }); - const mutings = await query - .take(ps.limit) - .getMany(); + const mutings = await query.take(ps.limit).getMany(); return await Mutings.packMany(mutings, me); }); diff --git a/packages/backend/src/server/api/endpoints/my/apps.ts b/packages/backend/src/server/api/endpoints/my/apps.ts index 85b75c15d..8a097c8a0 100644 --- a/packages/backend/src/server/api/endpoints/my/apps.ts +++ b/packages/backend/src/server/api/endpoints/my/apps.ts @@ -1,32 +1,33 @@ -import define from '../../define.js'; -import { Apps } from '@/models/index.js'; +import define from "../../define.js"; +import { Apps } from "@/models/index.js"; export const meta = { - tags: ['account', 'app'], + tags: ["account", "app"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'App', + type: "object", + optional: false, + nullable: false, + ref: "App", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const query = { userId: user.id, @@ -38,7 +39,11 @@ export default define(meta, paramDef, async (ps, user) => { skip: ps.offset, }); - return await Promise.all(apps.map(app => Apps.pack(app, user, { - detail: true, - }))); + return await Promise.all( + apps.map((app) => + Apps.pack(app, user, { + detail: true, + }), + ), + ); }); diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts index fc2bc3741..9787740ab 100644 --- a/packages/backend/src/server/api/endpoints/notes.ts +++ b/packages/backend/src/server/api/endpoints/notes.ts @@ -1,72 +1,83 @@ -import { Notes } from '@/models/index.js'; -import define from '../define.js'; -import { makePaginationQuery } from '../common/make-pagination-query.js'; +import { Notes } from "@/models/index.js"; +import define from "../define.js"; +import { makePaginationQuery } from "../common/make-pagination-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - local: { type: 'boolean', default: false }, - reply: { type: 'boolean' }, - renote: { type: 'boolean' }, - withFiles: { type: 'boolean' }, - poll: { type: 'boolean' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + local: { type: "boolean", default: false }, + reply: { type: "boolean" }, + renote: { type: "boolean" }, + withFiles: { type: "boolean" }, + poll: { type: "boolean" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere('note.visibility = \'public\'') - .andWhere('note.localOnly = FALSE') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .andWhere("note.visibility = 'public'") + .andWhere("note.localOnly = FALSE") + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); if (ps.local) { - query.andWhere('note.userHost IS NULL'); + query.andWhere("note.userHost IS NULL"); } if (ps.reply !== undefined) { - query.andWhere(ps.reply ? 'note.replyId IS NOT NULL' : 'note.replyId IS NULL'); + query.andWhere( + ps.reply ? "note.replyId IS NOT NULL" : "note.replyId IS NULL", + ); } if (ps.renote !== undefined) { - query.andWhere(ps.renote ? 'note.renoteId IS NOT NULL' : 'note.renoteId IS NULL'); + query.andWhere( + ps.renote ? "note.renoteId IS NOT NULL" : "note.renoteId IS NULL", + ); } if (ps.withFiles !== undefined) { - query.andWhere(ps.withFiles ? 'note.fileIds != \'{}\'' : 'note.fileIds = \'{}\''); + query.andWhere( + ps.withFiles ? "note.fileIds != '{}'" : "note.fileIds = '{}'", + ); } if (ps.poll !== undefined) { - query.andWhere(ps.poll ? 'note.hasPoll = TRUE' : 'note.hasPoll = FALSE'); + query.andWhere(ps.poll ? "note.hasPoll = TRUE" : "note.hasPoll = FALSE"); } // TODO diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 72282b3de..9047fcce1 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -1,46 +1,54 @@ -import { Brackets } from 'typeorm'; -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, }; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere('note.id IN (SELECT id FROM note_replies(:noteId, :depth, :limit))', { noteId: ps.noteId, depth: ps.depth, limit: ps.limit }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .andWhere( + "note.id IN (SELECT id FROM note_replies(:noteId, :depth, :limit))", + { noteId: ps.noteId, depth: ps.depth, limit: ps.limit }, + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner"); generateVisibilityQuery(query, user); if (user) { diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index 514386d73..34b035add 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -1,46 +1,48 @@ -import { In } from 'typeorm'; -import { ClipNotes, Clips } from '@/models/index.js'; -import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; +import { In } from "typeorm"; +import { ClipNotes, Clips } from "@/models/index.js"; +import define from "../../define.js"; +import { getNote } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['clips', 'notes'], + tags: ["clips", "notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '47db1a1c-b0af-458d-8fb4-986e4efafe1e', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "47db1a1c-b0af-458d-8fb4-986e4efafe1e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const note = await getNote(ps.noteId, me).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, me).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); @@ -49,9 +51,9 @@ export default define(meta, paramDef, async (ps, me) => { }); const clips = await Clips.findBy({ - id: In(clipNotes.map(x => x.clipId)), + id: In(clipNotes.map((x) => x.clipId)), isPublic: true, }); - return await Promise.all(clips.map(x => Clips.pack(x))); + return await Promise.all(clips.map((x) => Clips.pack(x))); }); diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index fa9b58848..2e8f5ef73 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -1,48 +1,50 @@ -import { Note } from '@/models/entities/note.js'; -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getNote } from '../../common/getters.js'; +import type { Note } from "@/models/entities/note.js"; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getNote } from "../../common/getters.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'e1035875-9551-45ec-afa8-1ded1fcb53c8', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "e1035875-9551-45ec-afa8-1ded1fcb53c8", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + noteId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); @@ -51,8 +53,8 @@ export default define(meta, paramDef, async (ps, user) => { async function get(id: any) { i++; - const p = await getNote(id, user).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') return null; + const p = await getNote(id, user).catch((e) => { + if (e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") return null; throw e; }); diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 1dc8b42b2..41b8ab979 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -1,19 +1,25 @@ -import { In } from 'typeorm'; -import create from '@/services/note/create.js'; -import { User } from '@/models/entities/user.js'; -import { Users, DriveFiles, Notes, Channels, Blockings } from '@/models/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { Note } from '@/models/entities/note.js'; -import { Channel } from '@/models/entities/channel.js'; -import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import { noteVisibilities } from '../../../../types.js'; -import { ApiError } from '../../error.js'; -import define from '../../define.js'; -import { HOUR } from '@/const.js'; -import { getNote } from '../../common/getters.js'; +import { In } from "typeorm"; +import create from "@/services/note/create.js"; +import type { User } from "@/models/entities/user.js"; +import { + Users, + DriveFiles, + Notes, + Channels, + Blockings, +} from "@/models/index.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { Note } from "@/models/entities/note.js"; +import type { Channel } from "@/models/entities/channel.js"; +import { MAX_NOTE_TEXT_LENGTH } from "@/const.js"; +import { noteVisibilities } from "../../../../types.js"; +import { ApiError } from "../../error.js"; +import define from "../../define.js"; +import { HOUR } from "@/const.js"; +import { getNote } from "../../common/getters.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, @@ -22,154 +28,166 @@ export const meta = { max: 300, }, - kind: 'write:notes', + kind: "write:notes", res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { createdNote: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, }, errors: { noSuchRenoteTarget: { - message: 'No such renote target.', - code: 'NO_SUCH_RENOTE_TARGET', - id: 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4', + message: "No such renote target.", + code: "NO_SUCH_RENOTE_TARGET", + id: "b5c90186-4ab0-49c8-9bba-a1f76c282ba4", }, cannotReRenote: { - message: 'You can not Renote a pure Renote.', - code: 'CANNOT_RENOTE_TO_A_PURE_RENOTE', - id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a', + message: "You can not Renote a pure Renote.", + code: "CANNOT_RENOTE_TO_A_PURE_RENOTE", + id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a", }, noSuchReplyTarget: { - message: 'No such reply target.', - code: 'NO_SUCH_REPLY_TARGET', - id: '749ee0f6-d3da-459a-bf02-282e2da4292c', + message: "No such reply target.", + code: "NO_SUCH_REPLY_TARGET", + id: "749ee0f6-d3da-459a-bf02-282e2da4292c", }, cannotReplyToPureRenote: { - message: 'You can not reply to a pure Renote.', - code: 'CANNOT_REPLY_TO_A_PURE_RENOTE', - id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15', + message: "You can not reply to a pure Renote.", + code: "CANNOT_REPLY_TO_A_PURE_RENOTE", + id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15", }, cannotCreateAlreadyExpiredPoll: { - message: 'Poll is already expired.', - code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL', - id: '04da457d-b083-4055-9082-955525eda5a5', + message: "Poll is already expired.", + code: "CANNOT_CREATE_ALREADY_EXPIRED_POLL", + id: "04da457d-b083-4055-9082-955525eda5a5", }, noSuchChannel: { - message: 'No such channel.', - code: 'NO_SUCH_CHANNEL', - id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb', + message: "No such channel.", + code: "NO_SUCH_CHANNEL", + id: "b1653923-5453-4edc-b786-7c4f39bb0bbb", }, youHaveBeenBlocked: { - message: 'You have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3', + message: "You have been blocked by this user.", + code: "YOU_HAVE_BEEN_BLOCKED", + id: "b390d7e1-8a5e-46ed-b625-06271cafd3d3", }, accountLocked: { - message: 'You migrated. Your account is now locked.', - code: 'ACCOUNT_LOCKED', - id: 'd390d7e1-8a5e-46ed-b625-06271cafd3d3', + message: "You migrated. Your account is now locked.", + code: "ACCOUNT_LOCKED", + id: "d390d7e1-8a5e-46ed-b625-06271cafd3d3", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - visibility: { type: 'string', enum: noteVisibilities, default: 'public' }, - visibleUserIds: { type: 'array', uniqueItems: true, items: { - type: 'string', format: 'misskey:id', - } }, - text: { type: 'string', maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true }, - cw: { type: 'string', nullable: true, maxLength: 100 }, - localOnly: { type: 'boolean', default: false }, - noExtractMentions: { type: 'boolean', default: false }, - noExtractHashtags: { type: 'boolean', default: false }, - noExtractEmojis: { type: 'boolean', default: false }, + visibility: { type: "string", enum: noteVisibilities, default: "public" }, + visibleUserIds: { + type: "array", + uniqueItems: true, + items: { + type: "string", + format: "misskey:id", + }, + }, + text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true }, + cw: { type: "string", nullable: true, maxLength: 100 }, + localOnly: { type: "boolean", default: false }, + noExtractMentions: { type: "boolean", default: false }, + noExtractHashtags: { type: "boolean", default: false }, + noExtractEmojis: { type: "boolean", default: false }, fileIds: { - type: 'array', + type: "array", uniqueItems: true, minItems: 1, maxItems: 16, - items: { type: 'string', format: 'misskey:id' }, + items: { type: "string", format: "misskey:id" }, }, mediaIds: { deprecated: true, - description: 'Use `fileIds` instead. If both are specified, this property is discarded.', - type: 'array', + description: + "Use `fileIds` instead. If both are specified, this property is discarded.", + type: "array", uniqueItems: true, minItems: 1, maxItems: 16, - items: { type: 'string', format: 'misskey:id' }, + items: { type: "string", format: "misskey:id" }, }, - replyId: { type: 'string', format: 'misskey:id', nullable: true }, - renoteId: { type: 'string', format: 'misskey:id', nullable: true }, - channelId: { type: 'string', format: 'misskey:id', nullable: true }, + replyId: { type: "string", format: "misskey:id", nullable: true }, + renoteId: { type: "string", format: "misskey:id", nullable: true }, + channelId: { type: "string", format: "misskey:id", nullable: true }, poll: { - type: 'object', + type: "object", nullable: true, properties: { choices: { - type: 'array', + type: "array", uniqueItems: true, minItems: 2, maxItems: 10, - items: { type: 'string', minLength: 1, maxLength: 50 }, + items: { type: "string", minLength: 1, maxLength: 50 }, }, - multiple: { type: 'boolean', default: false }, - expiresAt: { type: 'integer', nullable: true }, - expiredAfter: { type: 'integer', nullable: true, minimum: 1 }, + multiple: { type: "boolean", default: false }, + expiresAt: { type: "integer", nullable: true }, + expiredAfter: { type: "integer", nullable: true, minimum: 1 }, }, - required: ['choices'], + required: ["choices"], }, }, anyOf: [ { // (re)note with text, files and poll are optional properties: { - text: { type: 'string', minLength: 1, maxLength: MAX_NOTE_TEXT_LENGTH, nullable: false }, + text: { + type: "string", + minLength: 1, + maxLength: MAX_NOTE_TEXT_LENGTH, + nullable: false, + }, }, - required: ['text'], + required: ["text"], }, { // (re)note with files, text and poll are optional - required: ['fileIds'], + required: ["fileIds"], }, { // (re)note with files, text and poll are optional - required: ['mediaIds'], + required: ["mediaIds"], }, { // (re)note with poll, text and files are optional properties: { - poll: { type: 'object', nullable: false }, + poll: { type: "object", nullable: false }, }, - required: ['poll'], + required: ["poll"], }, { // pure renote - required: ['renoteId'], + required: ["renoteId"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if(user.movedToUri != null) throw new ApiError(meta.errors.accountLocked); + if (user.movedToUri != null) throw new ApiError(meta.errors.accountLocked); let visibleUsers: User[] = []; if (ps.visibleUserIds) { visibleUsers = await Users.findBy({ @@ -178,10 +196,11 @@ export default define(meta, paramDef, async (ps, user) => { } let files: DriveFile[] = []; - const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null; + const fileIds = + ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null; if (fileIds != null) { - files = await DriveFiles.createQueryBuilder('file') - .where('file.userId = :userId AND file.id IN (:...fileIds)', { + files = await DriveFiles.createQueryBuilder("file") + .where("file.userId = :userId AND file.id IN (:...fileIds)", { userId: user.id, fileIds, }) @@ -193,8 +212,9 @@ export default define(meta, paramDef, async (ps, user) => { let renote: Note | null = null; if (ps.renoteId != null) { // Fetch renote to note - renote = await getNote(ps.renoteId, user).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchRenoteTarget); + renote = await getNote(ps.renoteId, user).catch((e) => { + if (e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchRenoteTarget); throw e; }); @@ -217,8 +237,9 @@ export default define(meta, paramDef, async (ps, user) => { let reply: Note | null = null; if (ps.replyId != null) { // Fetch reply - reply = await getNote(ps.replyId, user).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchReplyTarget); + reply = await getNote(ps.replyId, user).catch((e) => { + if (e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchReplyTarget); throw e; }); @@ -239,11 +260,11 @@ export default define(meta, paramDef, async (ps, user) => { } if (ps.poll) { - if (typeof ps.poll.expiresAt === 'number') { + if (typeof ps.poll.expiresAt === "number") { if (ps.poll.expiresAt < Date.now()) { throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll); } - } else if (typeof ps.poll.expiredAfter === 'number') { + } else if (typeof ps.poll.expiredAfter === "number") { ps.poll.expiresAt = Date.now() + ps.poll.expiredAfter; } } @@ -261,11 +282,13 @@ export default define(meta, paramDef, async (ps, user) => { const note = await create(user, { createdAt: new Date(), files: files, - poll: ps.poll ? { - choices: ps.poll.choices, - multiple: ps.poll.multiple || false, - expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null, - } : undefined, + poll: ps.poll + ? { + choices: ps.poll.choices, + multiple: ps.poll.multiple, + expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null, + } + : undefined, text: ps.text || undefined, reply, renote, diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 34d23448e..5fc79db7d 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -1,16 +1,16 @@ -import deleteNote from '@/services/note/delete.js'; -import { Users } from '@/models/index.js'; -import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; -import { SECOND, HOUR } from '@/const.js'; +import deleteNote from "@/services/note/delete.js"; +import { Users } from "@/models/index.js"; +import define from "../../define.js"; +import { getNote } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; +import { SECOND, HOUR } from "@/const.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:notes', + kind: "write:notes", limit: { duration: HOUR, @@ -20,35 +20,35 @@ export const meta = { errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '490be23f-8c1f-4796-819f-94cb4f9d1630', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "490be23f-8c1f-4796-819f-94cb4f9d1630", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: 'fe8d7103-0ea8-4ec3-814d-f8b401dc69e9', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "fe8d7103-0ea8-4ec3-814d-f8b401dc69e9", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); - if ((!user.isAdmin && !user.isModerator) && (note.userId !== user.id)) { + if (!(user.isAdmin || user.isModerator) && note.userId !== user.id) { throw new ApiError(meta.errors.accessDenied); } diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index b5dd88a4e..835594f03 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -1,44 +1,44 @@ -import { NoteFavorites } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getNote } from "../../../common/getters.js"; export const meta = { - tags: ['notes', 'favorites'], + tags: ["notes", "favorites"], requireCredential: true, - kind: 'write:favorites', + kind: "write:favorites", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '6dd26674-e060-4816-909a-45ba3f4da458', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "6dd26674-e060-4816-909a-45ba3f4da458", }, alreadyFavorited: { - message: 'The note has already been marked as a favorite.', - code: 'ALREADY_FAVORITED', - id: 'a402c12b-34dd-41d2-97d8-4d2ffd96a1a6', + message: "The note has already been marked as a favorite.", + code: "ALREADY_FAVORITED", + id: "a402c12b-34dd-41d2-97d8-4d2ffd96a1a6", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get favoritee - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 3f4d39254..9a0976748 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -1,43 +1,43 @@ -import { NoteFavorites } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getNote } from "../../../common/getters.js"; export const meta = { - tags: ['notes', 'favorites'], + tags: ["notes", "favorites"], requireCredential: true, - kind: 'write:favorites', + kind: "write:favorites", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '80848a2c-398f-4343-baa9-df1d57696c56', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "80848a2c-398f-4343-baa9-df1d57696c56", }, notFavorited: { - message: 'You have not marked that note a favorite.', - code: 'NOT_FAVORITED', - id: 'b625fc69-635e-45e9-86f4-dbefbef35af5', + message: "You have not marked that note a favorite.", + code: "NOT_FAVORITED", + id: "b625fc69-635e-45e9-86f4-dbefbef35af5", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get favoritee - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 0e4a454d7..cd7e44296 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -1,66 +1,66 @@ -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const max = 30; const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで - const query = Notes.createQueryBuilder('note') - .addSelect('note.score') - .where('note.userHost IS NULL') - .andWhere('note.score > 0') - .andWhere('note.createdAt > :date', { date: new Date(Date.now() - day) }) - .andWhere('note.visibility = \'public\'') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = Notes.createQueryBuilder("note") + .addSelect("note.score") + .where("note.userHost IS NULL") + .andWhere("note.score > 0") + .andWhere("note.createdAt > :date", { date: new Date(Date.now() - day) }) + .andWhere("note.visibility = 'public'") + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); - let notes = await query - .orderBy('note.score', 'DESC') - .take(max) - .getMany(); + let notes = await query.orderBy("note.score", "DESC").take(max).getMany(); - notes.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); + notes.sort( + (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); notes = notes.slice(ps.offset, ps.offset + ps.limit); diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 6a468f198..e4a38cffb 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,79 +1,85 @@ -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateRepliesQuery } from '../../common/generate-replies-query.js'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Notes } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateRepliesQuery } from "../../common/generate-replies-query.js"; +import { generateMutedNoteQuery } from "../../common/generate-muted-note-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { gtlDisabled: { - message: 'Global timeline has been disabled.', - code: 'GTL_DISABLED', - id: '0332fc13-6ab2-4427-ae80-a9fadffd1a6b', + message: "Global timeline has been disabled.", + code: "GTL_DISABLED", + id: "0332fc13-6ab2-4427-ae80-a9fadffd1a6b", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableGlobalTimeline) { - if (user == null || (!user.isAdmin && !user.isModerator)) { + if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.gtlDisabled); } } //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('note.visibility = \'public\'') - .andWhere('note.channelId IS NULL') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere("note.visibility = 'public'") + .andWhere("note.channelId IS NULL") + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateRepliesQuery(query, user); if (user) { @@ -83,7 +89,7 @@ export default define(meta, paramDef, async (ps, user) => { } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 2dc98c4c9..3d6103da8 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,90 +1,100 @@ -import { Brackets } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Followings, Notes } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateRepliesQuery } from '../../common/generate-replies-query.js'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; -import { generateChannelQuery } from '../../common/generate-channel-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Followings, Notes } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateRepliesQuery } from "../../common/generate-replies-query.js"; +import { generateMutedNoteQuery } from "../../common/generate-muted-note-query.js"; +import { generateChannelQuery } from "../../common/generate-channel-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { stlDisabled: { - message: 'Hybrid timeline has been disabled.', - code: 'STL_DISABLED', - id: '620763f4-f621-4533-ab33-0577a1a3c342', + message: "Hybrid timeline has been disabled.", + code: "STL_DISABLED", + id: "620763f4-f621-4533-ab33-0577a1a3c342", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, - includeMyRenotes: { type: 'boolean', default: true }, - includeRenotedMyNotes: { type: 'boolean', default: true }, - includeLocalRenotes: { type: 'boolean', default: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, + includeMyRenotes: { type: "boolean", default: true }, + includeRenotedMyNotes: { type: "boolean", default: true }, + includeLocalRenotes: { type: "boolean", default: true }, withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); - if (m.disableLocalTimeline && (!user.isAdmin && !user.isModerator)) { + if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { throw new ApiError(meta.errors.stlDisabled); } //#region Construct query - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: user.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: user.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(new Brackets(qb => { - qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) - .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); - })) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere( + new Brackets((qb) => { + qb.where( + `((note.userId IN (${followingQuery.getQuery()})) OR (note.userId = :meId))`, + { meId: user.id }, + ).orWhere("(note.visibility = 'public') AND (note.userHost IS NULL)"); + }), + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -95,37 +105,49 @@ export default define(meta, paramDef, async (ps, user) => { generateBlockedUserQuery(query, user); if (ps.includeMyRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.userId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.userId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeRenotedMyNotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeLocalRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserHost IS NOT NULL'); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserHost IS NOT NULL"); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 3a5c458a0..22e5965fc 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,85 +1,94 @@ -import { Brackets } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes, Users } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateRepliesQuery } from '../../common/generate-replies-query.js'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; -import { generateChannelQuery } from '../../common/generate-channel-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Notes, Users } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateRepliesQuery } from "../../common/generate-replies-query.js"; +import { generateMutedNoteQuery } from "../../common/generate-muted-note-query.js"; +import { generateChannelQuery } from "../../common/generate-channel-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { ltlDisabled: { - message: 'Local timeline has been disabled.', - code: 'LTL_DISABLED', - id: '45a6eb02-7695-4393-b023-dd3be9aaaefd', + message: "Local timeline has been disabled.", + code: "LTL_DISABLED", + id: "45a6eb02-7695-4393-b023-dd3be9aaaefd", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, - fileType: { type: 'array', items: { - type: 'string', - } }, - excludeNsfw: { type: 'boolean', default: false }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + fileType: { + type: "array", + items: { + type: "string", + }, + }, + excludeNsfw: { type: "boolean", default: false }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableLocalTimeline) { - if (user == null || (!user.isAdmin && !user.isModerator)) { + if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.ltlDisabled); } } //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere("(note.visibility = 'public') AND (note.userHost IS NULL)") + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateChannelQuery(query, user); generateRepliesQuery(query, user); @@ -89,21 +98,27 @@ export default define(meta, paramDef, async (ps, user) => { if (user) generateBlockedUserQuery(query, user); if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } if (ps.fileType != null) { - query.andWhere('note.fileIds != \'{}\''); - query.andWhere(new Brackets(qb => { - for (const type of ps.fileType!) { - const i = ps.fileType!.indexOf(type); - qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type }); - } - })); + query.andWhere("note.fileIds != '{}'"); + query.andWhere( + new Brackets((qb) => { + for (const type of ps.fileType!) { + const i = ps.fileType!.indexOf(type); + qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { + [`type${i}`]: type, + }); + } + }), + ); if (ps.excludeNsfw) { - query.andWhere('note.cw IS NULL'); - query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)'); + query.andWhere("note.cw IS NULL"); + query.andWhere( + '0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)', + ); } } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index 9b4154452..3e5c4f18b 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -1,63 +1,71 @@ -import { Brackets } from 'typeorm'; -import read from '@/services/note/read.js'; -import { Notes, Followings } from '@/models/index.js'; -import define from '../../define.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; -import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query.js'; +import { Brackets } from "typeorm"; +import read from "@/services/note/read.js"; +import { Notes, Followings } from "@/models/index.js"; +import define from "../../define.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; +import { generateMutedNoteThreadQuery } from "../../common/generate-muted-note-thread-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - following: { type: 'boolean', default: false }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - visibility: { type: 'string' }, + following: { type: "boolean", default: false }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + visibility: { type: "string" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: user.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: user.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere(new Brackets(qb => { qb - .where(`'{"${user.id}"}' <@ note.mentions`) - .orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`); - })) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .andWhere( + new Brackets((qb) => { + qb.where(`'{"${user.id}"}' <@ note.mentions`).orWhere( + `'{"${user.id}"}' <@ note.visibleUserIds`, + ); + }), + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); @@ -65,11 +73,16 @@ export default define(meta, paramDef, async (ps, user) => { generateBlockedUserQuery(query, user); if (ps.visibility) { - query.andWhere('note.visibility = :visibility', { visibility: ps.visibility }); + query.andWhere("note.visibility = :visibility", { + visibility: ps.visibility, + }); } if (ps.following) { - query.andWhere(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }); + query.andWhere( + `((note.userId IN (${followingQuery.getQuery()})) OR (note.userId = :meId))`, + { meId: user.id }, + ); query.setParameters(followingQuery.getParameters()); } diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index 5a04d68f3..fcd24db99 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -1,67 +1,69 @@ -import { Brackets, In } from 'typeorm'; -import { Polls, Mutings, Notes, PollVotes } from '@/models/index.js'; -import define from '../../../define.js'; +import { Brackets, In } from "typeorm"; +import { Polls, Mutings, Notes, PollVotes } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = Polls.createQueryBuilder('poll') - .where('poll.userHost IS NULL') - .andWhere('poll.userId != :meId', { meId: user.id }) - .andWhere('poll.noteVisibility = \'public\'') - .andWhere(new Brackets(qb => { qb - .where('poll.expiresAt IS NULL') - .orWhere('poll.expiresAt > :now', { now: new Date() }); - })); + const query = Polls.createQueryBuilder("poll") + .where("poll.userHost IS NULL") + .andWhere("poll.userId != :meId", { meId: user.id }) + .andWhere("poll.noteVisibility = 'public'") + .andWhere( + new Brackets((qb) => { + qb.where("poll.expiresAt IS NULL").orWhere("poll.expiresAt > :now", { + now: new Date(), + }); + }), + ); //#region exclude arleady voted polls - const votedQuery = PollVotes.createQueryBuilder('vote') - .select('vote.noteId') - .where('vote.userId = :meId', { meId: user.id }); + const votedQuery = PollVotes.createQueryBuilder("vote") + .select("vote.noteId") + .where("vote.userId = :meId", { meId: user.id }); - query - .andWhere(`poll.noteId NOT IN (${ votedQuery.getQuery() })`); + query.andWhere(`poll.noteId NOT IN (${votedQuery.getQuery()})`); query.setParameters(votedQuery.getParameters()); //#endregion //#region mute - const mutingQuery = Mutings.createQueryBuilder('muting') - .select('muting.muteeId') - .where('muting.muterId = :muterId', { muterId: user.id }); + const mutingQuery = Mutings.createQueryBuilder("muting") + .select("muting.muteeId") + .where("muting.muterId = :muterId", { muterId: user.id }); - query - .andWhere(`poll.userId NOT IN (${ mutingQuery.getQuery() })`); + query.andWhere(`poll.userId NOT IN (${mutingQuery.getQuery()})`); query.setParameters(mutingQuery.getParameters()); //#endregion const polls = await query - .orderBy('poll.noteId', 'DESC') + .orderBy("poll.noteId", "DESC") .take(ps.limit) .skip(ps.offset) .getMany(); @@ -70,10 +72,10 @@ export default define(meta, paramDef, async (ps, user) => { const notes = await Notes.find({ where: { - id: In(polls.map(poll => poll.noteId)), + id: In(polls.map((poll) => poll.noteId)), }, order: { - createdAt: 'DESC', + createdAt: "DESC", }, }); diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 6dd5ddf9e..0558aa1b8 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -1,79 +1,86 @@ -import { Not } from 'typeorm'; -import { publishNoteStream } from '@/services/stream.js'; -import { createNotification } from '@/services/create-notification.js'; -import { deliver } from '@/queue/index.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderVote from '@/remote/activitypub/renderer/vote.js'; -import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; -import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '@/models/index.js'; -import { IRemoteUser } from '@/models/entities/user.js'; -import { genId } from '@/misc/gen-id.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; -import define from '../../../define.js'; +import { Not } from "typeorm"; +import { publishNoteStream } from "@/services/stream.js"; +import { createNotification } from "@/services/create-notification.js"; +import { deliver } from "@/queue/index.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderVote from "@/remote/activitypub/renderer/vote.js"; +import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; +import { + PollVotes, + NoteWatchings, + Users, + Polls, + Blockings, +} from "@/models/index.js"; +import type { IRemoteUser } from "@/models/entities/user.js"; +import { genId } from "@/misc/gen-id.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; +import define from "../../../define.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:votes', + kind: "write:votes", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'ecafbd2e-c283-4d6d-aecb-1a0a33b75396', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "ecafbd2e-c283-4d6d-aecb-1a0a33b75396", }, noPoll: { - message: 'The note does not attach a poll.', - code: 'NO_POLL', - id: '5f979967-52d9-4314-a911-1c673727f92f', + message: "The note does not attach a poll.", + code: "NO_POLL", + id: "5f979967-52d9-4314-a911-1c673727f92f", }, invalidChoice: { - message: 'Choice ID is invalid.', - code: 'INVALID_CHOICE', - id: 'e0cc9a04-f2e8-41e4-a5f1-4127293260cc', + message: "Choice ID is invalid.", + code: "INVALID_CHOICE", + id: "e0cc9a04-f2e8-41e4-a5f1-4127293260cc", }, alreadyVoted: { - message: 'You have already voted.', - code: 'ALREADY_VOTED', - id: '0963fc77-efac-419b-9424-b391608dc6d8', + message: "You have already voted.", + code: "ALREADY_VOTED", + id: "0963fc77-efac-419b-9424-b391608dc6d8", }, alreadyExpired: { - message: 'The poll is already expired.', - code: 'ALREADY_EXPIRED', - id: '1022a357-b085-4054-9083-8f8de358337e', + message: "The poll is already expired.", + code: "ALREADY_EXPIRED", + id: "1022a357-b085-4054-9083-8f8de358337e", }, youHaveBeenBlocked: { - message: 'You cannot vote this poll because you have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: '85a5377e-b1e9-4617-b0b9-5bea73331e49', + message: + "You cannot vote this poll because you have been blocked by this user.", + code: "YOU_HAVE_BEEN_BLOCKED", + id: "85a5377e-b1e9-4617-b0b9-5bea73331e49", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - choice: { type: 'integer' }, + noteId: { type: "string", format: "misskey:id" }, + choice: { type: "integer" }, }, - required: ['noteId', 'choice'], + required: ["noteId", "choice"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const createdAt = new Date(); // Get votee - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); @@ -110,7 +117,7 @@ export default define(meta, paramDef, async (ps, user) => { if (exist.length) { if (poll.multiple) { - if (exist.some(x => x.choice === ps.choice)) { + if (exist.some((x) => x.choice === ps.choice)) { throw new ApiError(meta.errors.alreadyVoted); } } else { @@ -125,19 +132,21 @@ export default define(meta, paramDef, async (ps, user) => { noteId: note.id, userId: user.id, choice: ps.choice, - }).then(x => PollVotes.findOneByOrFail(x.identifiers[0])); + }).then((x) => PollVotes.findOneByOrFail(x.identifiers[0])); // Increment votes count const index = ps.choice + 1; // In SQL, array index is 1 based - await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`); + await Polls.query( + `UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`, + ); - publishNoteStream(note.id, 'pollVoted', { + publishNoteStream(note.id, "pollVoted", { choice: ps.choice, userId: user.id, }); // Notify - createNotification(note.userId, 'pollVote', { + createNotification(note.userId, "pollVote", { notifierId: user.id, noteId: note.id, choice: ps.choice, @@ -147,9 +156,9 @@ export default define(meta, paramDef, async (ps, user) => { NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), - }).then(watchers => { + }).then((watchers) => { for (const watcher of watchers) { - createNotification(watcher.userId, 'pollVote', { + createNotification(watcher.userId, "pollVote", { notifierId: user.id, noteId: note.id, choice: ps.choice, @@ -159,9 +168,15 @@ export default define(meta, paramDef, async (ps, user) => { // リモート投票の場合リプライ送信 if (note.userHost != null) { - const pollOwner = await Users.findOneByOrFail({ id: note.userId }) as IRemoteUser; + const pollOwner = (await Users.findOneByOrFail({ + id: note.userId, + })) as IRemoteUser; - deliver(user, renderActivity(await renderVote(user, vote, note, poll, pollOwner)), pollOwner.inbox); + deliver( + user, + renderActivity(await renderVote(user, vote, note, poll, pollOwner)), + pollOwner.inbox, + ); } // リモートフォロワーにUpdate配信 diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 00a89b3f2..3c8af119a 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -1,12 +1,13 @@ -import { DeepPartial, FindOptionsWhere } from 'typeorm'; -import { NoteReactions } from '@/models/index.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getNote } from '../../common/getters.js'; +import type { FindOptionsWhere } from "typeorm"; +import { DeepPartial } from "typeorm"; +import { NoteReactions } from "@/models/index.js"; +import type { NoteReaction } from "@/models/entities/note-reaction.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getNote } from "../../common/getters.js"; export const meta = { - tags: ['notes', 'reactions'], + tags: ["notes", "reactions"], requireCredential: false, requireCredentialPrivateMode: true, @@ -15,42 +16,44 @@ export const meta = { cacheSec: 60, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'NoteReaction', + type: "object", + optional: false, + nullable: false, + ref: "NoteReaction", }, }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '263fff3d-d0e1-4af4-bea7-8408059b451a', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "263fff3d-d0e1-4af4-bea7-8408059b451a", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - type: { type: 'string', nullable: true }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, + type: { type: "string", nullable: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // check note visibility - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); @@ -61,8 +64,10 @@ export default define(meta, paramDef, async (ps, user) => { if (ps.type) { // ローカルリアクションはホスト名が . とされているが // DB 上ではそうではないので、必要に応じて変換 - const suffix = '@.:'; - const type = ps.type.endsWith(suffix) ? ps.type.slice(0, ps.type.length - suffix.length) + ':' : ps.type; + const suffix = "@.:"; + const type = ps.type.endsWith(suffix) + ? `${ps.type.slice(0, ps.type.length - suffix.length)}:` + : ps.type; query.reaction = type; } @@ -73,7 +78,7 @@ export default define(meta, paramDef, async (ps, user) => { order: { id: -1, }, - relations: ['user', 'user.avatar', 'user.banner', 'note'], + relations: ["user", "user.avatar", "user.banner", "note"], }); return await NoteReactions.packMany(reactions, user); diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index 4c767b489..2c8671070 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -1,60 +1,63 @@ -import createReaction from '@/services/note/reaction/create.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; +import createReaction from "@/services/note/reaction/create.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['reactions', 'notes'], + tags: ["reactions", "notes"], requireCredential: true, - kind: 'write:reactions', + kind: "write:reactions", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '033d0620-5bfe-4027-965d-980b0c85a3ea', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "033d0620-5bfe-4027-965d-980b0c85a3ea", }, alreadyReacted: { - message: 'You are already reacting to that note.', - code: 'ALREADY_REACTED', - id: '71efcf98-86d6-4e2b-b2ad-9d032369366b', + message: "You are already reacting to that note.", + code: "ALREADY_REACTED", + id: "71efcf98-86d6-4e2b-b2ad-9d032369366b", }, youHaveBeenBlocked: { - message: 'You cannot react this note because you have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: '20ef5475-9f38-4e4c-bd33-de6d979498ec', + message: + "You cannot react this note because you have been blocked by this user.", + code: "YOU_HAVE_BEEN_BLOCKED", + id: "20ef5475-9f38-4e4c-bd33-de6d979498ec", }, accountLocked: { - message: 'You migrated. Your account is now locked.', - code: 'ACCOUNT_LOCKED', - id: 'd390d7e1-8a5e-46ed-b625-06271cafd3d3', + message: "You migrated. Your account is now locked.", + code: "ACCOUNT_LOCKED", + id: "d390d7e1-8a5e-46ed-b625-06271cafd3d3", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - reaction: { type: 'string' }, + noteId: { type: "string", format: "misskey:id" }, + reaction: { type: "string" }, }, - required: ['noteId', 'reaction'], + required: ["noteId", "reaction"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if(user.movedToUri != null) throw new ApiError(meta.errors.accountLocked); - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + if (user.movedToUri != null) throw new ApiError(meta.errors.accountLocked); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); - await createReaction(user, note, ps.reaction).catch(e => { - if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted); - if (e.id === 'e70412a4-7197-4726-8e74-f3e0deb92aa7') throw new ApiError(meta.errors.youHaveBeenBlocked); + await createReaction(user, note, ps.reaction).catch((e) => { + if (e.id === "51c42bb4-931a-456b-bff7-e5a8a70dd298") + throw new ApiError(meta.errors.alreadyReacted); + if (e.id === "e70412a4-7197-4726-8e74-f3e0deb92aa7") + throw new ApiError(meta.errors.youHaveBeenBlocked); throw e; }); return; diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts index c25d88d1b..59096c4c8 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts @@ -1,15 +1,15 @@ -import deleteReaction from '@/services/note/reaction/delete.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; -import { SECOND, HOUR } from '@/const.js'; +import deleteReaction from "@/services/note/reaction/delete.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; +import { SECOND, HOUR } from "@/const.js"; export const meta = { - tags: ['reactions', 'notes'], + tags: ["reactions", "notes"], requireCredential: true, - kind: 'write:reactions', + kind: "write:reactions", limit: { duration: HOUR, @@ -19,35 +19,36 @@ export const meta = { errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '764d9fce-f9f2-4a0e-92b1-6ceac9a7ad37', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "764d9fce-f9f2-4a0e-92b1-6ceac9a7ad37", }, notReacted: { - message: 'You are not reacting to that note.', - code: 'NOT_REACTED', - id: '92f4426d-4196-4125-aa5b-02943e2ec8fc', + message: "You are not reacting to that note.", + code: "NOT_REACTED", + id: "92f4426d-4196-4125-aa5b-02943e2ec8fc", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); - await deleteReaction(user, note).catch(e => { - if (e.id === '60527ec9-b4cb-4a88-a6bd-32d3ad26817d') throw new ApiError(meta.errors.notReacted); + await deleteReaction(user, note).catch((e) => { + if (e.id === "60527ec9-b4cb-4a88-a6bd-32d3ad26817d") + throw new ApiError(meta.errors.notReacted); throw e; }); }); diff --git a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts index ae2d58274..6dacadec2 100644 --- a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts @@ -1,86 +1,97 @@ -import { Brackets } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateRepliesQuery } from '../../common/generate-replies-query.js'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; -import { generateChannelQuery } from '../../common/generate-channel-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Notes } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateRepliesQuery } from "../../common/generate-replies-query.js"; +import { generateMutedNoteQuery } from "../../common/generate-muted-note-query.js"; +import { generateChannelQuery } from "../../common/generate-channel-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { rtlDisabled: { - message: 'Recommended timeline has been disabled.', - code: 'RTL_DISABLED', - id: '45a6eb02-7695-4393-b023-dd3be9aaaefe', + message: "Recommended timeline has been disabled.", + code: "RTL_DISABLED", + id: "45a6eb02-7695-4393-b023-dd3be9aaaefe", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, - fileType: { type: 'array', items: { - type: 'string', - } }, - excludeNsfw: { type: 'boolean', default: false }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + fileType: { + type: "array", + items: { + type: "string", + }, + }, + excludeNsfw: { type: "boolean", default: false }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableRecommendedTimeline) { - if (user == null || (!user.isAdmin && !user.isModerator)) { + if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.rtlDisabled); } } //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(`(note.userHost = ANY ('{"${m.recommendedInstances.join('","')}"}'))`) - .andWhere('(note.visibility = \'public\')') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere( + `(note.userHost = ANY ('{"${m.recommendedInstances.join('","')}"}'))`, + ) + .andWhere("(note.visibility = 'public')") + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateChannelQuery(query, user); generateRepliesQuery(query, user); @@ -90,21 +101,27 @@ export default define(meta, paramDef, async (ps, user) => { if (user) generateBlockedUserQuery(query, user); if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } if (ps.fileType != null) { - query.andWhere('note.fileIds != \'{}\''); - query.andWhere(new Brackets(qb => { - for (const type of ps.fileType!) { - const i = ps.fileType!.indexOf(type); - qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type }); - } - })); + query.andWhere("note.fileIds != '{}'"); + query.andWhere( + new Brackets((qb) => { + for (const type of ps.fileType!) { + const i = ps.fileType!.indexOf(type); + qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { + [`type${i}`]: type, + }); + } + }), + ); if (ps.excludeNsfw) { - query.andWhere('note.cw IS NULL'); - query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)'); + query.andWhere("note.cw IS NULL"); + query.andWhere( + '0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)', + ); } } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index 2f662f355..b09243e7e 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -1,68 +1,74 @@ -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { getNote } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '12908022-2e21-46cd-ba6a-3edaf6093f46', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "12908022-2e21-46cd-ba6a-3edaf6093f46", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere('note.renoteId = :renoteId', { renoteId: note.id }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .andWhere("note.renoteId = :renoteId", { renoteId: note.id }) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index b05ef5914..0a8e90949 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -1,53 +1,58 @@ -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + noteId: { type: "string", format: "misskey:id" }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .andWhere("note.replyId = :replyId", { replyId: ps.noteId }) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 99670ae2f..8cf9ce8fb 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,59 +1,62 @@ -import { Brackets } from 'typeorm'; -import { Notes } from '@/models/index.js'; -import { safeForSql } from '@/misc/safe-for-sql.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { Notes } from "@/models/index.js"; +import { safeForSql } from "@/misc/safe-for-sql.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes', 'hashtags'], + tags: ["notes", "hashtags"], requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - reply: { type: 'boolean', nullable: true, default: null }, - renote: { type: 'boolean', nullable: true, default: null }, + reply: { type: "boolean", nullable: true, default: null }, + renote: { type: "boolean", nullable: true, default: null }, withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, - poll: { type: 'boolean', nullable: true, default: null }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + poll: { type: "boolean", nullable: true, default: null }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, anyOf: [ { properties: { - tag: { type: 'string', minLength: 1 }, + tag: { type: "string", minLength: 1 }, }, - required: ['tag'], + required: ["tag"], }, { properties: { query: { - type: 'array', - description: 'The outer arrays are chained with OR, the inner arrays are chained with AND.', + type: "array", + description: + "The outer arrays are chained with OR, the inner arrays are chained with AND.", items: { - type: 'array', + type: "array", items: { - type: 'string', + type: "string", minLength: 1, }, minItems: 1, @@ -61,25 +64,28 @@ export const paramDef = { minItems: 1, }, }, - required: ['query'], + required: ["query"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); @@ -87,50 +93,54 @@ export default define(meta, paramDef, async (ps, me) => { try { if (ps.tag) { - if (!safeForSql(ps.tag)) throw new Error('Injection'); + if (!safeForSql(ps.tag)) throw new Error("Injection"); query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); } else { - query.andWhere(new Brackets(qb => { - for (const tags of ps.query!) { - qb.orWhere(new Brackets(qb => { - for (const tag of tags) { - if (!safeForSql(tag)) throw new Error('Injection'); - qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`); - } - })); - } - })); + query.andWhere( + new Brackets((qb) => { + for (const tags of ps.query!) { + qb.orWhere( + new Brackets((qb) => { + for (const tag of tags) { + if (!safeForSql(tag)) throw new Error("Injection"); + qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`); + } + }), + ); + } + }), + ); } } catch (e) { - if (e.message === 'Injection') return []; + if (e.message === "Injection") return []; throw e; } if (ps.reply != null) { if (ps.reply) { - query.andWhere('note.replyId IS NOT NULL'); + query.andWhere("note.replyId IS NOT NULL"); } else { - query.andWhere('note.replyId IS NULL'); + query.andWhere("note.replyId IS NULL"); } } if (ps.renote != null) { if (ps.renote) { - query.andWhere('note.renoteId IS NOT NULL'); + query.andWhere("note.renoteId IS NOT NULL"); } else { - query.andWhere('note.renoteId IS NULL'); + query.andWhere("note.renoteId IS NULL"); } } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } if (ps.poll != null) { if (ps.poll) { - query.andWhere('note.hasPoll = TRUE'); + query.andWhere("note.hasPoll = TRUE"); } else { - query.andWhere('note.hasPoll = FALSE'); + query.andWhere("note.hasPoll = FALSE"); } } diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index cf3de47a3..ce60436db 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,76 +1,92 @@ -import { In } from 'typeorm'; -import { Notes } from '@/models/index.js'; -import config from '@/config/index.js'; -import es from '../../../../db/elasticsearch.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { In } from "typeorm"; +import { Notes } from "@/models/index.js"; +import config from "@/config/index.js"; +import es from "../../../../db/elasticsearch.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, - errors: { - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - query: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + query: { type: "string" }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, host: { - type: 'string', + type: "string", nullable: true, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", + }, + userId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, + }, + channelId: { + type: "string", + format: "misskey:id", + nullable: true, + default: null, }, - userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - channelId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, }, - required: ['query'], + required: ["query"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { if (es == null) { - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ); if (ps.userId) { - query.andWhere('note.userId = :userId', { userId: ps.userId }); + query.andWhere("note.userId = :userId", { userId: ps.userId }); } else if (ps.channelId) { - query.andWhere('note.channelId = :channelId', { channelId: ps.channelId }); + query.andWhere("note.channelId = :channelId", { + channelId: ps.channelId, + }); } query - .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + .andWhere("note.text ILIKE :q", { q: `%${ps.query}%` }) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); @@ -80,47 +96,67 @@ export default define(meta, paramDef, async (ps, me) => { return await Notes.packMany(notes, me); } else { - const userQuery = ps.userId != null ? [{ - term: { - userId: ps.userId, - }, - }] : []; - - const hostQuery = ps.userId == null ? - ps.host === null ? [{ - bool: { - must_not: { - exists: { - field: 'userHost', + const userQuery = + ps.userId != null + ? [ + { + term: { + userId: ps.userId, + }, }, - }, - }, - }] : ps.host !== undefined ? [{ - term: { - userHost: ps.host, - }, - }] : [] - : []; + ] + : []; + + const hostQuery = + ps.userId == null + ? ps.host === null + ? [ + { + bool: { + must_not: { + exists: { + field: "userHost", + }, + }, + }, + }, + ] + : ps.host !== undefined + ? [ + { + term: { + userHost: ps.host, + }, + }, + ] + : [] + : []; const result = await es.search({ - index: config.elasticsearch.index || 'misskey_note', + index: config.elasticsearch.index || "misskey_note", body: { size: ps.limit, from: ps.offset, query: { bool: { - must: [{ - simple_query_string: { - fields: ['text'], - query: ps.query.toLowerCase(), - default_operator: 'and', + must: [ + { + simple_query_string: { + fields: ["text"], + query: ps.query.toLowerCase(), + default_operator: "and", + }, }, - }, ...hostQuery, ...userQuery], + ...hostQuery, + ...userQuery, + ], }, }, - sort: [{ - _doc: 'desc', - }], + sort: [ + { + _doc: "desc", + }, + ], }, }); diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 83a39a855..39d128134 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -1,49 +1,51 @@ -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { getNote } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "24fcbfc6-2e37-42b6-8388-c29b3861a08d", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); return await Notes.pack(note, user, { // FIXME: packing with detail may throw an error if the reply or renote is not visible (#8774) detail: true, - }).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + }).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); }); diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index 67579b2a6..630b2a800 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -1,41 +1,49 @@ -import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js'; -import { getNote } from '../../common/getters.js'; -import define from '../../define.js'; +import { + NoteFavorites, + Notes, + NoteThreadMutings, + NoteWatchings, +} from "@/models/index.js"; +import { getNote } from "../../common/getters.js"; +import define from "../../define.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { isFavorited: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isWatching: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isMutedThread: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId, user); diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index 4154b5dc5..e4803cc29 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -1,47 +1,50 @@ -import { Notes, NoteThreadMutings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import readNote from '@/services/note/read.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; +import { Notes, NoteThreadMutings } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import readNote from "@/services/note/read.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '5ff67ada-ed3b-2e71-8e87-a1a421e177d2', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "5ff67ada-ed3b-2e71-8e87-a1a421e177d2", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); const mutedNotes = await Notes.find({ - where: [{ - id: note.threadId || note.id, - }, { - threadId: note.threadId || note.id, - }], + where: [ + { + id: note.threadId || note.id, + }, + { + threadId: note.threadId || note.id, + }, + ], }); await readNote(user.id, mutedNotes); diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts index cbc0e5ce5..c06fd59ba 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts @@ -1,36 +1,36 @@ -import { NoteThreadMutings } from '@/models/index.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; +import { NoteThreadMutings } from "@/models/index.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'bddd57ac-ceb3-b29d-4334-86ea5fae481a', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "bddd57ac-ceb3-b29d-4334-86ea5fae481a", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 22f492517..083f41365 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -1,82 +1,92 @@ -import { Brackets } from 'typeorm'; -import { Notes, Followings } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateRepliesQuery } from '../../common/generate-replies-query.js'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; -import { generateChannelQuery } from '../../common/generate-channel-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { Notes, Followings } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateRepliesQuery } from "../../common/generate-replies-query.js"; +import { generateMutedNoteQuery } from "../../common/generate-muted-note-query.js"; +import { generateChannelQuery } from "../../common/generate-channel-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, - includeMyRenotes: { type: 'boolean', default: true }, - includeRenotedMyNotes: { type: 'boolean', default: true }, - includeLocalRenotes: { type: 'boolean', default: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, + includeMyRenotes: { type: "boolean", default: true }, + includeRenotedMyNotes: { type: "boolean", default: true }, + includeLocalRenotes: { type: "boolean", default: true }, withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const hasFollowing = (await Followings.count({ - where: { - followerId: user.id, - }, - take: 1, - })) !== 0; + const hasFollowing = + (await Followings.count({ + where: { + followerId: user.id, + }, + take: 1, + })) !== 0; //#region Construct query - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: user.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: user.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(new Brackets(qb => { qb - .where('note.userId = :meId', { meId: user.id }); - if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); - })) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere( + new Brackets((qb) => { + qb.where("note.userId = :meId", { meId: user.id }); + if (hasFollowing) + qb.orWhere(`note.userId IN (${followingQuery.getQuery()})`); + }), + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -87,37 +97,49 @@ export default define(meta, paramDef, async (ps, user) => { generateBlockedUserQuery(query, user); if (ps.includeMyRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.userId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.userId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeRenotedMyNotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeLocalRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserHost IS NOT NULL'); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserHost IS NOT NULL"); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index a01dcfa48..c6415ceef 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -1,46 +1,47 @@ -import { URLSearchParams } from 'node:url'; -import fetch from 'node-fetch'; -import config from '@/config/index.js'; -import { getAgentByUrl } from '@/misc/fetch.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; -import { ApiError } from '../../error.js'; -import { getNote } from '../../common/getters.js'; -import define from '../../define.js'; +import { URLSearchParams } from "node:url"; +import fetch from "node-fetch"; +import config from "@/config/index.js"; +import { getAgentByUrl } from "@/misc/fetch.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Notes } from "@/models/index.js"; +import { ApiError } from "../../error.js"; +import { getNote } from "../../common/getters.js"; +import define from "../../define.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, }, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'bea9b03f-36e0-49c5-a4db-627a029f8971', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "bea9b03f-36e0-49c5-a4db-627a029f8971", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, - targetLang: { type: 'string' }, + noteId: { type: "string", format: "misskey:id" }, + targetLang: { type: "string" }, }, - required: ['noteId', 'targetLang'], + required: ["noteId", "targetLang"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); @@ -55,21 +56,23 @@ export default define(meta, paramDef, async (ps, user) => { } let targetLang = ps.targetLang; - if (targetLang.includes('-')) targetLang = targetLang.split('-')[0]; + if (targetLang.includes("-")) targetLang = targetLang.split("-")[0]; const params = new URLSearchParams(); - params.append('auth_key', instance.deeplAuthKey); - params.append('text', note.text); - params.append('target_lang', targetLang); + params.append("auth_key", instance.deeplAuthKey); + params.append("text", note.text); + params.append("target_lang", targetLang); - const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate'; + const endpoint = instance.deeplIsPro + ? "https://api.deepl.com/v2/translate" + : "https://api-free.deepl.com/v2/translate"; const res = await fetch(endpoint, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'User-Agent': config.userAgent, - Accept: 'application/json, */*', + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": config.userAgent, + Accept: "application/json, */*", }, body: params, // TODO diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index 1089a9e37..a30a19f19 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -1,16 +1,16 @@ -import deleteNote from '@/services/note/delete.js'; -import { Notes, Users } from '@/models/index.js'; -import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; -import { SECOND, HOUR } from '@/const.js'; +import deleteNote from "@/services/note/delete.js"; +import { Notes, Users } from "@/models/index.js"; +import define from "../../define.js"; +import { getNote } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; +import { SECOND, HOUR } from "@/const.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:notes', + kind: "write:notes", limit: { duration: HOUR, @@ -20,25 +20,25 @@ export const meta = { errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'efd4a259-2442-496b-8dd7-b255aa1a160f', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "efd4a259-2442-496b-8dd7-b255aa1a160f", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index e603a8f62..c1e535722 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -1,57 +1,58 @@ -import { Brackets } from 'typeorm'; -import { UserLists, UserListJoinings, Notes } from '@/models/index.js'; -import { activeUsersChart } from '@/services/chart/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { Brackets } from "typeorm"; +import { UserLists, UserListJoinings, Notes } from "@/models/index.js"; +import { activeUsersChart } from "@/services/chart/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; export const meta = { - tags: ['notes', 'lists'], + tags: ["notes", "lists"], requireCredential: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '8fb1fbd5-e476-4c37-9fb0-43d55b63a2ff', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "8fb1fbd5-e476-4c37-9fb0-43d55b63a2ff", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, - includeMyRenotes: { type: 'boolean', default: true }, - includeRenotedMyNotes: { type: 'boolean', default: true }, - includeLocalRenotes: { type: 'boolean', default: true }, + listId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, + includeMyRenotes: { type: "boolean", default: true }, + includeRenotedMyNotes: { type: "boolean", default: true }, + includeLocalRenotes: { type: "boolean", default: true }, withFiles: { - type: 'boolean', + type: "boolean", default: false, - description: 'Only show notes that have attached files.', + description: "Only show notes that have attached files.", }, }, - required: ['listId'], + required: ["listId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const list = await UserLists.findOneBy({ id: ps.listId, @@ -63,55 +64,77 @@ export default define(meta, paramDef, async (ps, user) => { } //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .innerJoin(UserListJoinings.metadata.targetName, 'userListJoining', 'userListJoining.userId = note.userId') - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .andWhere('userListJoining.userListId = :userListId', { userListId: list.id }); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ) + .innerJoin( + UserListJoinings.metadata.targetName, + "userListJoining", + "userListJoining.userId = note.userId", + ) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") + .andWhere("userListJoining.userListId = :userListId", { + userListId: list.id, + }); generateVisibilityQuery(query, user); if (ps.includeMyRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.userId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.userId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeRenotedMyNotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserId != :meId', { meId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserId != :meId", { meId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.includeLocalRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.renoteUserHost IS NOT NULL'); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.renoteUserHost IS NOT NULL"); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/notes/watching/create.ts b/packages/backend/src/server/api/endpoints/notes/watching/create.ts index 6025799fa..f8921099a 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/create.ts @@ -1,36 +1,36 @@ -import watch from '@/services/note/watch.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; +import watch from "@/services/note/watch.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'ea0e37a6-90a3-4f58-ba6b-c328ca206fc7', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "ea0e37a6-90a3-4f58-ba6b-c328ca206fc7", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts index 7021c7970..b441ad74b 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts @@ -1,36 +1,36 @@ -import unwatch from '@/services/note/unwatch.js'; -import define from '../../../define.js'; -import { getNote } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; +import unwatch from "@/services/note/unwatch.js"; +import define from "../../../define.js"; +import { getNote } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, - kind: 'write:account', + kind: "write:account", errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: '09b3695c-f72c-4731-a428-7cff825fc82e', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "09b3695c-f72c-4731-a428-7cff825fc82e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/notifications/create.ts b/packages/backend/src/server/api/endpoints/notifications/create.ts index 80d513d8d..bc5723369 100644 --- a/packages/backend/src/server/api/endpoints/notifications/create.ts +++ b/packages/backend/src/server/api/endpoints/notifications/create.ts @@ -1,30 +1,28 @@ -import { createNotification } from '@/services/create-notification.js'; -import define from '../../define.js'; +import { createNotification } from "@/services/create-notification.js"; +import define from "../../define.js"; export const meta = { - tags: ['notifications'], + tags: ["notifications"], requireCredential: true, - kind: 'write:notifications', + kind: "write:notifications", - errors: { - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - body: { type: 'string' }, - header: { type: 'string', nullable: true }, - icon: { type: 'string', nullable: true }, + body: { type: "string" }, + header: { type: "string", nullable: true }, + icon: { type: "string", nullable: true }, }, - required: ['body'], + required: ["body"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user, token) => { - createNotification(user.id, 'app', { + createNotification(user.id, "app", { appAccessTokenId: token ? token.id : null, customBody: ps.body, customHeader: ps.header, diff --git a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts index d169afbb3..e0888ad75 100644 --- a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts +++ b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts @@ -1,33 +1,35 @@ -import { publishMainStream } from '@/services/stream.js'; -import { pushNotification } from '@/services/push-notification.js'; -import { Notifications } from '@/models/index.js'; -import define from '../../define.js'; +import { publishMainStream } from "@/services/stream.js"; +import { pushNotification } from "@/services/push-notification.js"; +import { Notifications } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['notifications', 'account'], + tags: ["notifications", "account"], requireCredential: true, - kind: 'write:notifications', + kind: "write:notifications", } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Update documents - await Notifications.update({ - notifieeId: user.id, - isRead: false, - }, { - isRead: true, - }); + await Notifications.update( + { + notifieeId: user.id, + isRead: false, + }, + { + isRead: true, + }, + ); // 全ての通知を読みましたよというイベントを発行 - publishMainStream(user.id, 'readAllNotifications'); - pushNotification(user.id, 'readAllNotifications', undefined); + publishMainStream(user.id, "readAllNotifications"); + pushNotification(user.id, "readAllNotifications", undefined); }); diff --git a/packages/backend/src/server/api/endpoints/notifications/read.ts b/packages/backend/src/server/api/endpoints/notifications/read.ts index 7bce525a5..9efb2fcc0 100644 --- a/packages/backend/src/server/api/endpoints/notifications/read.ts +++ b/packages/backend/src/server/api/endpoints/notifications/read.ts @@ -1,20 +1,20 @@ -import define from '../../define.js'; -import { readNotification } from '../../common/read-notification.js'; +import define from "../../define.js"; +import { readNotification } from "../../common/read-notification.js"; export const meta = { - tags: ['notifications', 'account'], + tags: ["notifications", "account"], requireCredential: true, - kind: 'write:notifications', + kind: "write:notifications", - description: 'Mark a notification as read.', + description: "Mark a notification as read.", errors: { noSuchNotification: { - message: 'No such notification.', - code: 'NO_SUCH_NOTIFICATION', - id: 'efa929d5-05b5-47d1-beec-e6a4dbed011e', + message: "No such notification.", + code: "NO_SUCH_NOTIFICATION", + id: "efa929d5-05b5-47d1-beec-e6a4dbed011e", }, }, } as const; @@ -22,28 +22,28 @@ export const meta = { export const paramDef = { oneOf: [ { - type: 'object', + type: "object", properties: { - notificationId: { type: 'string', format: 'misskey:id' }, + notificationId: { type: "string", format: "misskey:id" }, }, - required: ['notificationId'], + required: ["notificationId"], }, { - type: 'object', + type: "object", properties: { notificationIds: { - type: 'array', - items: { type: 'string', format: 'misskey:id' }, + type: "array", + items: { type: "string", format: "misskey:id" }, maxItems: 100, }, }, - required: ['notificationIds'], + required: ["notificationIds"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if ('notificationId' in ps) return readNotification(user.id, [ps.notificationId]); + if ("notificationId" in ps) + return readNotification(user.id, [ps.notificationId]); return readNotification(user.id, ps.notificationIds); }); diff --git a/packages/backend/src/server/api/endpoints/page-push.ts b/packages/backend/src/server/api/endpoints/page-push.ts index 6dd3ede85..a0f1e912f 100644 --- a/packages/backend/src/server/api/endpoints/page-push.ts +++ b/packages/backend/src/server/api/endpoints/page-push.ts @@ -1,7 +1,7 @@ -import { publishMainStream } from '@/services/stream.js'; -import { Users, Pages } from '@/models/index.js'; -import define from '../define.js'; -import { ApiError } from '../error.js'; +import { publishMainStream } from "@/services/stream.js"; +import { Users, Pages } from "@/models/index.js"; +import define from "../define.js"; +import { ApiError } from "../error.js"; export const meta = { requireCredential: true, @@ -9,37 +9,40 @@ export const meta = { errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: '4a13ad31-6729-46b4-b9af-e86b265c2e74', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "4a13ad31-6729-46b4-b9af-e86b265c2e74", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - pageId: { type: 'string', format: 'misskey:id' }, - event: { type: 'string' }, + pageId: { type: "string", format: "misskey:id" }, + event: { type: "string" }, var: {}, }, - required: ['pageId', 'event'], + required: ["pageId", "event"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } - publishMainStream(page.userId, 'pageEvent', { + publishMainStream(page.userId, "pageEvent", { pageId: ps.pageId, event: ps.event, var: ps.var, userId: user.id, - user: await Users.pack(user.id, { id: page.userId }, { - detail: true, - }), + user: await Users.pack( + user.id, + { id: page.userId }, + { + detail: true, + }, + ), }); }); diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts index 063faf6ec..716d3265c 100644 --- a/packages/backend/src/server/api/endpoints/pages/create.ts +++ b/packages/backend/src/server/api/endpoints/pages/create.ts @@ -1,16 +1,16 @@ -import { Pages, DriveFiles } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { Page } from '@/models/entities/page.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { HOUR } from '@/const.js'; +import { Pages, DriveFiles } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { Page } from "@/models/entities/page.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: true, - kind: 'write:pages', + kind: "write:pages", limit: { duration: HOUR, @@ -18,48 +18,64 @@ export const meta = { }, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, errors: { noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'b7b97489-0f66-4b12-a5ff-b21bd63f6e1c', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "b7b97489-0f66-4b12-a5ff-b21bd63f6e1c", }, nameAlreadyExists: { - message: 'Specified name already exists.', - code: 'NAME_ALREADY_EXISTS', - id: '4650348e-301c-499a-83c9-6aa988c66bc1', + message: "Specified name already exists.", + code: "NAME_ALREADY_EXISTS", + id: "4650348e-301c-499a-83c9-6aa988c66bc1", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - title: { type: 'string' }, - name: { type: 'string', minLength: 1 }, - summary: { type: 'string', nullable: true }, - content: { type: 'array', items: { - type: 'object', additionalProperties: true, - } }, - variables: { type: 'array', items: { - type: 'object', additionalProperties: true, - } }, - script: { type: 'string' }, - eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true }, - font: { type: 'string', enum: ['serif', 'sans-serif'], default: 'sans-serif' }, - alignCenter: { type: 'boolean', default: false }, - isPublic: { type: 'boolean', default: true }, - hideTitleWhenPinned: { type: 'boolean', default: false }, + title: { type: "string" }, + name: { type: "string", minLength: 1 }, + summary: { type: "string", nullable: true }, + content: { + type: "array", + items: { + type: "object", + additionalProperties: true, + }, + }, + variables: { + type: "array", + items: { + type: "object", + additionalProperties: true, + }, + }, + script: { type: "string" }, + eyeCatchingImageId: { + type: "string", + format: "misskey:id", + nullable: true, + }, + font: { + type: "string", + enum: ["serif", "sans-serif"], + default: "sans-serif", + }, + alignCenter: { type: "boolean", default: false }, + isPublic: { type: "boolean", default: true }, + hideTitleWhenPinned: { type: "boolean", default: false }, }, - required: ['title', 'name', 'content', 'variables', 'script'], + required: ["title", "name", "content", "variables", "script"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { let eyeCatchingImage = null; if (ps.eyeCatchingImageId != null) { @@ -76,30 +92,32 @@ export default define(meta, paramDef, async (ps, user) => { await Pages.findBy({ userId: user.id, name: ps.name, - }).then(result => { + }).then((result) => { if (result.length > 0) { throw new ApiError(meta.errors.nameAlreadyExists); } }); - const page = await Pages.insert(new Page({ - id: genId(), - createdAt: new Date(), - updatedAt: new Date(), - title: ps.title, - name: ps.name, - summary: ps.summary, - content: ps.content, - variables: ps.variables, - script: ps.script, - eyeCatchingImageId: eyeCatchingImage ? eyeCatchingImage.id : null, - userId: user.id, - visibility: 'public', - alignCenter: ps.alignCenter, - hideTitleWhenPinned: ps.hideTitleWhenPinned, - font: ps.font, - isPublic: ps.isPublic, - })).then(x => Pages.findOneByOrFail(x.identifiers[0])); + const page = await Pages.insert( + new Page({ + id: genId(), + createdAt: new Date(), + updatedAt: new Date(), + title: ps.title, + name: ps.name, + summary: ps.summary, + content: ps.content, + variables: ps.variables, + script: ps.script, + eyeCatchingImageId: eyeCatchingImage ? eyeCatchingImage.id : null, + userId: user.id, + visibility: "public", + alignCenter: ps.alignCenter, + hideTitleWhenPinned: ps.hideTitleWhenPinned, + font: ps.font, + isPublic: ps.isPublic, + }), + ).then((x) => Pages.findOneByOrFail(x.identifiers[0])); return await Pages.pack(page); }); diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts index a7708e658..98b035f7c 100644 --- a/packages/backend/src/server/api/endpoints/pages/delete.ts +++ b/packages/backend/src/server/api/endpoints/pages/delete.ts @@ -1,38 +1,37 @@ -import { Pages } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; +import { Pages } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: true, - kind: 'write:pages', + kind: "write:pages", errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: 'eb0c6e1d-d519-4764-9486-52a7e1c6392a', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "eb0c6e1d-d519-4764-9486-52a7e1c6392a", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '8b741b3e-2c22-44b3-a15f-29949aa1601e', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "8b741b3e-2c22-44b3-a15f-29949aa1601e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - pageId: { type: 'string', format: 'misskey:id' }, + pageId: { type: "string", format: "misskey:id" }, }, - required: ['pageId'], + required: ["pageId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { diff --git a/packages/backend/src/server/api/endpoints/pages/featured.ts b/packages/backend/src/server/api/endpoints/pages/featured.ts index 75580778b..a76346589 100644 --- a/packages/backend/src/server/api/endpoints/pages/featured.ts +++ b/packages/backend/src/server/api/endpoints/pages/featured.ts @@ -1,35 +1,36 @@ -import { Pages } from '@/models/index.js'; -import define from '../../define.js'; +import { Pages } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Pages.createQueryBuilder('page') - .where('page.visibility = \'public\'') - .andWhere('page.likedCount > 0') - .orderBy('page.likedCount', 'DESC'); + const query = Pages.createQueryBuilder("page") + .where("page.visibility = 'public'") + .andWhere("page.likedCount > 0") + .orderBy("page.likedCount", "DESC"); const pages = await query.take(10).getMany(); diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index b4aab40d3..f14ed39eb 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -1,39 +1,38 @@ -import { Pages, PageLikes } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; +import { Pages, PageLikes } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: true, - kind: 'write:page-likes', + kind: "write:page-likes", errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: 'cc98a8a2-0dc3-4123-b198-62c71df18ed3', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "cc98a8a2-0dc3-4123-b198-62c71df18ed3", }, alreadyLiked: { - message: 'The page has already been liked.', - code: 'ALREADY_LIKED', - id: 'cc98a8a2-0dc3-4123-b198-62c71df18ed3', + message: "The page has already been liked.", + code: "ALREADY_LIKED", + id: "cc98a8a2-0dc3-4123-b198-62c71df18ed3", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - pageId: { type: 'string', format: 'misskey:id' }, + pageId: { type: "string", format: "misskey:id" }, }, - required: ['pageId'], + required: ["pageId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { @@ -58,5 +57,5 @@ export default define(meta, paramDef, async (ps, user) => { userId: user.id, }); - Pages.increment({ id: page.id }, 'likedCount', 1); + Pages.increment({ id: page.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/pages/show.ts b/packages/backend/src/server/api/endpoints/pages/show.ts index 384975af7..a25eb30b6 100644 --- a/packages/backend/src/server/api/endpoints/pages/show.ts +++ b/packages/backend/src/server/api/endpoints/pages/show.ts @@ -1,50 +1,50 @@ -import { IsNull } from 'typeorm'; -import { Pages, Users } from '@/models/index.js'; -import { Page } from '@/models/entities/page.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; +import { IsNull } from "typeorm"; +import { Pages, Users } from "@/models/index.js"; +import type { Page } from "@/models/entities/page.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: '222120c0-3ead-4528-811b-b96f233388d7', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "222120c0-3ead-4528-811b-b96f233388d7", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", anyOf: [ { properties: { - pageId: { type: 'string', format: 'misskey:id' }, + pageId: { type: "string", format: "misskey:id" }, }, - required: ['pageId'], + required: ["pageId"], }, { properties: { - name: { type: 'string' }, - username: { type: 'string' }, + name: { type: "string" }, + username: { type: "string" }, }, - required: ['name', 'username'], + required: ["name", "username"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { let page: Page | null = null; @@ -67,7 +67,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchPage); } - if (!page.isPublic && (user == null || (page.userId !== user.id))) { + if (!page.isPublic && (user == null || page.userId !== user.id)) { throw new ApiError(meta.errors.noSuchPage); } diff --git a/packages/backend/src/server/api/endpoints/pages/unlike.ts b/packages/backend/src/server/api/endpoints/pages/unlike.ts index 6b3a2bec1..07bf3fbf4 100644 --- a/packages/backend/src/server/api/endpoints/pages/unlike.ts +++ b/packages/backend/src/server/api/endpoints/pages/unlike.ts @@ -1,38 +1,37 @@ -import { Pages, PageLikes } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; +import { Pages, PageLikes } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: true, - kind: 'write:page-likes', + kind: "write:page-likes", errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: 'a0d41e20-1993-40bd-890e-f6e560ae648e', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "a0d41e20-1993-40bd-890e-f6e560ae648e", }, notLiked: { - message: 'You have not liked that page.', - code: 'NOT_LIKED', - id: 'f5e586b0-ce93-4050-b0e3-7f31af5259ee', + message: "You have not liked that page.", + code: "NOT_LIKED", + id: "f5e586b0-ce93-4050-b0e3-7f31af5259ee", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - pageId: { type: 'string', format: 'misskey:id' }, + pageId: { type: "string", format: "misskey:id" }, }, - required: ['pageId'], + required: ["pageId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { @@ -51,5 +50,5 @@ export default define(meta, paramDef, async (ps, user) => { // Delete like await PageLikes.delete(exist.id); - Pages.decrement({ id: page.id }, 'likedCount', 1); + Pages.decrement({ id: page.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index 585e9e73e..65e1b3b2d 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -1,15 +1,15 @@ -import { Not } from 'typeorm'; -import { Pages, DriveFiles } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { HOUR } from '@/const.js'; +import { Not } from "typeorm"; +import { Pages, DriveFiles } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['pages'], + tags: ["pages"], requireCredential: true, - kind: 'write:pages', + kind: "write:pages", limit: { duration: HOUR, @@ -18,54 +18,65 @@ export const meta = { errors: { noSuchPage: { - message: 'No such page.', - code: 'NO_SUCH_PAGE', - id: '21149b9e-3616-4778-9592-c4ce89f5a864', + message: "No such page.", + code: "NO_SUCH_PAGE", + id: "21149b9e-3616-4778-9592-c4ce89f5a864", }, accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '3c15cd52-3b4b-4274-967d-6456fc4f792b', + message: "Access denied.", + code: "ACCESS_DENIED", + id: "3c15cd52-3b4b-4274-967d-6456fc4f792b", }, noSuchFile: { - message: 'No such file.', - code: 'NO_SUCH_FILE', - id: 'cfc23c7c-3887-490e-af30-0ed576703c82', + message: "No such file.", + code: "NO_SUCH_FILE", + id: "cfc23c7c-3887-490e-af30-0ed576703c82", }, nameAlreadyExists: { - message: 'Specified name already exists.', - code: 'NAME_ALREADY_EXISTS', - id: '2298a392-d4a1-44c5-9ebb-ac1aeaa5a9ab', + message: "Specified name already exists.", + code: "NAME_ALREADY_EXISTS", + id: "2298a392-d4a1-44c5-9ebb-ac1aeaa5a9ab", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - pageId: { type: 'string', format: 'misskey:id' }, - title: { type: 'string' }, - name: { type: 'string', minLength: 1 }, - summary: { type: 'string', nullable: true }, - content: { type: 'array', items: { - type: 'object', additionalProperties: true, - } }, - variables: { type: 'array', items: { - type: 'object', additionalProperties: true, - } }, - script: { type: 'string' }, - eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true }, - font: { type: 'string', enum: ['serif', 'sans-serif'] }, - alignCenter: { type: 'boolean' }, - hideTitleWhenPinned: { type: 'boolean' }, - isPublic: { type: 'boolean' }, + pageId: { type: "string", format: "misskey:id" }, + title: { type: "string" }, + name: { type: "string", minLength: 1 }, + summary: { type: "string", nullable: true }, + content: { + type: "array", + items: { + type: "object", + additionalProperties: true, + }, + }, + variables: { + type: "array", + items: { + type: "object", + additionalProperties: true, + }, + }, + script: { type: "string" }, + eyeCatchingImageId: { + type: "string", + format: "misskey:id", + nullable: true, + }, + font: { type: "string", enum: ["serif", "sans-serif"] }, + alignCenter: { type: "boolean" }, + hideTitleWhenPinned: { type: "boolean" }, + isPublic: { type: "boolean" }, }, - required: ['pageId', 'title', 'name', 'content', 'variables', 'script'], + required: ["pageId", "title", "name", "content", "variables", "script"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { @@ -91,7 +102,7 @@ export default define(meta, paramDef, async (ps, user) => { id: Not(ps.pageId), userId: user.id, name: ps.name, - }).then(result => { + }).then((result) => { if (result.length > 0) { throw new ApiError(meta.errors.nameAlreadyExists); } @@ -106,12 +117,17 @@ export default define(meta, paramDef, async (ps, user) => { variables: ps.variables, script: ps.script, isPublic: ps.isPublic, - alignCenter: ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter, - hideTitleWhenPinned: ps.hideTitleWhenPinned === undefined ? page.hideTitleWhenPinned : ps.hideTitleWhenPinned, + alignCenter: + ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter, + hideTitleWhenPinned: + ps.hideTitleWhenPinned === undefined + ? page.hideTitleWhenPinned + : ps.hideTitleWhenPinned, font: ps.font === undefined ? page.font : ps.font, - eyeCatchingImageId: ps.eyeCatchingImageId === null - ? null - : ps.eyeCatchingImageId === undefined + eyeCatchingImageId: + ps.eyeCatchingImageId === null + ? null + : ps.eyeCatchingImageId === undefined ? page.eyeCatchingImageId : eyeCatchingImage!.id, }); diff --git a/packages/backend/src/server/api/endpoints/patrons.ts b/packages/backend/src/server/api/endpoints/patrons.ts index bc1fcc5c9..d6ac6c397 100644 --- a/packages/backend/src/server/api/endpoints/patrons.ts +++ b/packages/backend/src/server/api/endpoints/patrons.ts @@ -1,26 +1,27 @@ -import define from '../define.js'; +import define from "../define.js"; export const meta = { - tags: ['meta'], - description: 'Get list of Calckey patrons from Codeberg', + tags: ["meta"], + description: "Get list of Calckey patrons from Codeberg", requireCredential: false, requireCredentialPrivateMode: false, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { let patrons; - await fetch('https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json') + await fetch( + "https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json", + ) .then((response) => response.json()) .then((data) => { - patrons = data['patrons']; + patrons = data["patrons"]; }); return patrons; diff --git a/packages/backend/src/server/api/endpoints/ping.ts b/packages/backend/src/server/api/endpoints/ping.ts index 2891a0860..c1f7e110b 100644 --- a/packages/backend/src/server/api/endpoints/ping.ts +++ b/packages/backend/src/server/api/endpoints/ping.ts @@ -1,29 +1,30 @@ -import define from '../define.js'; +import define from "../define.js"; export const meta = { requireCredential: false, - tags: ['meta'], + tags: ["meta"], res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { pong: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { return { pong: Date.now(), diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 251482648..22020068c 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -1,41 +1,52 @@ -import { IsNull } from 'typeorm'; -import { Users } from '@/models/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import * as Acct from '@/misc/acct.js'; -import type { User } from '@/models/entities/user.js'; -import define from '../define.js'; +import { IsNull } from "typeorm"; +import { Users } from "@/models/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import * as Acct from "@/misc/acct.js"; +import type { User } from "@/models/entities/user.js"; +import define from "../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: false, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const meta = await fetchMeta(); - const users = await Promise.all(meta.pinnedUsers.map(acct => Acct.parse(acct)).map(acct => Users.findOneBy({ - usernameLower: acct.username.toLowerCase(), - host: acct.host ?? IsNull(), - }))); + const users = await Promise.all( + meta.pinnedUsers + .map((acct) => Acct.parse(acct)) + .map((acct) => + Users.findOneBy({ + usernameLower: acct.username.toLowerCase(), + host: acct.host ?? IsNull(), + }), + ), + ); - return await Users.packMany(users.filter(x => x !== undefined) as User[], me, { detail: true }); + return await Users.packMany( + users.filter((x) => x !== undefined) as User[], + me, + { detail: true }, + ); }); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index 7c37fcbf7..09c8cb6fa 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -1,35 +1,35 @@ -import { PromoReads } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getNote } from '../../common/getters.js'; +import { PromoReads } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getNote } from "../../common/getters.js"; export const meta = { - tags: ['notes'], + tags: ["notes"], requireCredential: true, errors: { noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'd785b897-fcd3-4fe9-8fc3-b85c26e6c932', + message: "No such note.", + code: "NO_SUCH_NOTE", + id: "d785b897-fcd3-4fe9-8fc3-b85c26e6c932", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - noteId: { type: 'string', format: 'misskey:id' }, + noteId: { type: "string", format: "misskey:id" }, }, - required: ['noteId'], + required: ["noteId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId, user).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + const note = await getNote(ps.noteId, user).catch((err) => { + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") + throw new ApiError(meta.errors.noSuchNote); throw err; }); diff --git a/packages/backend/src/server/api/endpoints/recommended-instances.ts b/packages/backend/src/server/api/endpoints/recommended-instances.ts index 844177b1d..8407afb1d 100644 --- a/packages/backend/src/server/api/endpoints/recommended-instances.ts +++ b/packages/backend/src/server/api/endpoints/recommended-instances.ts @@ -1,32 +1,33 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import define from '../define.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import define from "../define.js"; export const meta = { - tags: ['meta'], + tags: ["meta"], requireCredential: false, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'string', - optional: false, nullable: false, + type: "string", + optional: false, + nullable: false, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const meta = await fetchMeta(); - const instances = await Promise.all(meta.recommendedInstances.map(x => x)); + const instances = await Promise.all(meta.recommendedInstances.map((x) => x)); return instances; }); diff --git a/packages/backend/src/server/api/endpoints/release.ts b/packages/backend/src/server/api/endpoints/release.ts new file mode 100644 index 000000000..e5ebbb79a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/release.ts @@ -0,0 +1,28 @@ +import define from "../define.js"; + +export const meta = { + tags: ["meta"], + description: "Get release notes from Codeberg", + + requireCredential: false, + requireCredentialPrivateMode: false, +} as const; + +export const paramDef = { + type: "object", + properties: {}, + required: [], +} as const; + +export default define(meta, paramDef, async () => { + let release; + + await fetch( + "https://codeberg.org/calckey/calckey/raw/branch/develop/release.json", + ) + .then((response) => response.json()) + .then((data) => { + release = data; + }); + return release; +}); diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts index ddf193903..bac564c1d 100644 --- a/packages/backend/src/server/api/endpoints/request-reset-password.ts +++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts @@ -1,41 +1,38 @@ -import rndstr from 'rndstr'; -import { IsNull } from 'typeorm'; -import { publishMainStream } from '@/services/stream.js'; -import config from '@/config/index.js'; -import { Users, UserProfiles, PasswordResetRequests } from '@/models/index.js'; -import { sendEmail } from '@/services/send-email.js'; -import { genId } from '@/misc/gen-id.js'; -import { ApiError } from '../error.js'; -import define from '../define.js'; -import { HOUR } from '@/const.js'; +import rndstr from "rndstr"; +import { IsNull } from "typeorm"; +import { publishMainStream } from "@/services/stream.js"; +import config from "@/config/index.js"; +import { Users, UserProfiles, PasswordResetRequests } from "@/models/index.js"; +import { sendEmail } from "@/services/send-email.js"; +import { genId } from "@/misc/gen-id.js"; +import { ApiError } from "../error.js"; +import define from "../define.js"; +import { HOUR } from "@/const.js"; export const meta = { - tags: ['reset password'], + tags: ["reset password"], requireCredential: false, - description: 'Request a users password to be reset.', + description: "Request a users password to be reset.", limit: { duration: HOUR, max: 3, }, - errors: { - - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - username: { type: 'string' }, - email: { type: 'string' }, + username: { type: "string" }, + email: { type: "string" }, }, - required: ['username', 'email'], + required: ["username", "email"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { const user = await Users.findOneBy({ usernameLower: ps.username.toLowerCase(), @@ -59,7 +56,7 @@ export default define(meta, paramDef, async (ps) => { return; } - const token = rndstr('a-z0-9', 64); + const token = rndstr("a-z0-9", 64); await PasswordResetRequests.insert({ id: genId(), @@ -70,7 +67,10 @@ export default define(meta, paramDef, async (ps) => { const link = `${config.url}/reset-password/${token}`; - sendEmail(ps.email, 'Password reset requested', + sendEmail( + ps.email, + "Password reset requested", `To reset password, please click this link:
${link}`, - `To reset password, please click this link: ${link}`); + `To reset password, please click this link: ${link}`, + ); }); diff --git a/packages/backend/src/server/api/endpoints/reset-db.ts b/packages/backend/src/server/api/endpoints/reset-db.ts index cf5710f82..c64db7bca 100644 --- a/packages/backend/src/server/api/endpoints/reset-db.ts +++ b/packages/backend/src/server/api/endpoints/reset-db.ts @@ -1,30 +1,29 @@ -import { resetDb } from '@/db/postgre.js'; -import define from '../define.js'; -import { ApiError } from '../error.js'; +import { resetDb } from "@/db/postgre.js"; +import define from "../define.js"; +import { ApiError } from "../error.js"; export const meta = { - tags: ['non-productive'], + tags: ["non-productive"], requireCredential: false, - description: 'Only available when running with NODE_ENV=testing. Reset the database and flush Redis.', + description: + "Only available when running with NODE_ENV=testing. Reset the database and flush Redis.", - errors: { - - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - if (process.env.NODE_ENV !== 'test') throw new Error('NODE_ENV is not a test'); + if (process.env.NODE_ENV !== "test") + throw new Error("NODE_ENV is not a test"); await resetDb(); - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 1000)); }); diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index 797169c2c..51755727a 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -1,31 +1,28 @@ -import bcrypt from 'bcryptjs'; -import { publishMainStream } from '@/services/stream.js'; -import { Users, UserProfiles, PasswordResetRequests } from '@/models/index.js'; -import define from '../define.js'; -import { ApiError } from '../error.js'; +import bcrypt from "bcryptjs"; +import { publishMainStream } from "@/services/stream.js"; +import { Users, UserProfiles, PasswordResetRequests } from "@/models/index.js"; +import define from "../define.js"; +import { ApiError } from "../error.js"; export const meta = { - tags: ['reset password'], + tags: ["reset password"], requireCredential: false, - description: 'Complete the password reset that was previously requested.', + description: "Complete the password reset that was previously requested.", - errors: { - - }, + errors: {}, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - token: { type: 'string' }, - password: { type: 'string' }, + token: { type: "string" }, + password: { type: "string" }, }, - required: ['token', 'password'], + required: ["token", "password"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const req = await PasswordResetRequests.findOneByOrFail({ token: ps.token, diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index fdfbc8a6f..1ce27e262 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -1,21 +1,20 @@ -import * as os from 'node:os'; -import si from 'systeminformation'; -import define from '../define.js'; +import * as os from "node:os"; +import si from "systeminformation"; +import define from "../define.js"; export const meta = { requireCredential: false, requireCredentialPrivateMode: true, - tags: ['meta'], + tags: ["meta"], } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const memStats = await si.mem(); const fsStats = await si.fsSize(); diff --git a/packages/backend/src/server/api/endpoints/stats.ts b/packages/backend/src/server/api/endpoints/stats.ts index 0f2fb1f41..8bd559768 100644 --- a/packages/backend/src/server/api/endpoints/stats.ts +++ b/packages/backend/src/server/api/endpoints/stats.ts @@ -1,57 +1,64 @@ -import { Instances, NoteReactions, Notes, Users } from '@/models/index.js'; -import define from '../define.js'; -import { } from '@/services/chart/index.js'; -import { IsNull } from 'typeorm'; +import { Instances, NoteReactions, Notes, Users } from "@/models/index.js"; +import define from "../define.js"; +import {} from "@/services/chart/index.js"; +import { IsNull } from "typeorm"; export const meta = { requireCredential: false, requireCredentialPrivateMode: true, - tags: ['meta'], + tags: ["meta"], res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { notesCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, originalNotesCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, usersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, originalUsersCount: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, instances: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, driveUsageLocal: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, driveUsageRemote: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const [ notesCount, diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index 437f8874f..7218b0d50 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -1,43 +1,45 @@ -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { genId } from '@/misc/gen-id.js'; -import { SwSubscriptions } from '@/models/index.js'; -import define from '../../define.js'; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { genId } from "@/misc/gen-id.js"; +import { SwSubscriptions } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - description: 'Register to receive push notifications.', + description: "Register to receive push notifications.", res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { state: { - type: 'string', - optional: true, nullable: false, - enum: ['already-subscribed', 'subscribed'], + type: "string", + optional: true, + nullable: false, + enum: ["already-subscribed", "subscribed"], }, key: { - type: 'string', - optional: false, nullable: true, + type: "string", + optional: false, + nullable: true, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - endpoint: { type: 'string' }, - auth: { type: 'string' }, - publickey: { type: 'string' }, + endpoint: { type: "string" }, + auth: { type: "string" }, + publickey: { type: "string" }, }, - required: ['endpoint', 'auth', 'publickey'], + required: ["endpoint", "auth", "publickey"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // if already subscribed const exist = await SwSubscriptions.findOneBy({ @@ -51,7 +53,7 @@ export default define(meta, paramDef, async (ps, user) => { if (exist != null) { return { - state: 'already-subscribed' as const, + state: "already-subscribed" as const, key: instance.swPublicKey, }; } @@ -66,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { }); return { - state: 'subscribed' as const, + state: "subscribed" as const, key: instance.swPublicKey, }; }); diff --git a/packages/backend/src/server/api/endpoints/sw/unregister.ts b/packages/backend/src/server/api/endpoints/sw/unregister.ts index c19e06b87..b025630e4 100644 --- a/packages/backend/src/server/api/endpoints/sw/unregister.ts +++ b/packages/backend/src/server/api/endpoints/sw/unregister.ts @@ -1,23 +1,22 @@ -import { SwSubscriptions } from '@/models/index.js'; -import define from '../../define.js'; +import { SwSubscriptions } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['account'], + tags: ["account"], requireCredential: true, - description: 'Unregister from receiving push notifications.', + description: "Unregister from receiving push notifications.", } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - endpoint: { type: 'string' }, + endpoint: { type: "string" }, }, - required: ['endpoint'], + required: ["endpoint"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { await SwSubscriptions.delete({ userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/test.ts b/packages/backend/src/server/api/endpoints/test.ts index 9949237a7..2c43c6115 100644 --- a/packages/backend/src/server/api/endpoints/test.ts +++ b/packages/backend/src/server/api/endpoints/test.ts @@ -1,26 +1,25 @@ -import define from '../define.js'; +import define from "../define.js"; export const meta = { - tags: ['non-productive'], + tags: ["non-productive"], - description: 'Endpoint for testing input validation.', + description: "Endpoint for testing input validation.", requireCredential: false, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - required: { type: 'boolean' }, - string: { type: 'string' }, - default: { type: 'string', default: 'hello' }, - nullableDefault: { type: 'string', nullable: true, default: 'hello' }, - id: { type: 'string', format: 'misskey:id' }, + required: { type: "boolean" }, + string: { type: "string" }, + default: { type: "string", default: "hello" }, + nullableDefault: { type: "string", nullable: true, default: "hello" }, + id: { type: "string", format: "misskey:id" }, }, - required: ['required'], + required: ["required"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { return ps; }); diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index 3e41aeaed..f5aa4ed1e 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,33 +1,34 @@ -import { IsNull } from 'typeorm'; -import { Users, UsedUsernames } from '@/models/index.js'; -import define from '../../define.js'; +import { IsNull } from "typeorm"; +import { Users, UsedUsernames } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { available: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { username: Users.localUsernameSchema, }, - required: ['username'], + required: ["username"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Get exist const exist = await Users.countBy({ @@ -35,7 +36,9 @@ export default define(meta, paramDef, async (ps) => { usernameLower: ps.username.toLowerCase(), }); - const exist2 = await UsedUsernames.countBy({ username: ps.username.toLowerCase() }); + const exist2 = await UsedUsernames.countBy({ + username: ps.username.toLowerCase(), + }); return { available: exist === 0 && exist2 === 0, diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts index 7ee9bb8c0..f0a867090 100644 --- a/packages/backend/src/server/api/endpoints/users.ts +++ b/packages/backend/src/server/api/endpoints/users.ts @@ -1,72 +1,125 @@ -import { Users } from '@/models/index.js'; -import define from '../define.js'; -import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query.js'; -import { generateBlockQueryForUsers } from '../common/generate-block-query.js'; +import { Users } from "@/models/index.js"; +import define from "../define.js"; +import { generateMutedUserQueryForUsers } from "../common/generate-muted-user-query.js"; +import { generateBlockQueryForUsers } from "../common/generate-block-query.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: true, requireCredentialPrivateMode: true, res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, - sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, - state: { type: 'string', enum: ['all', 'admin', 'moderator', 'adminOrModerator', 'alive'], default: 'all' }, - origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, + sort: { + type: "string", + enum: [ + "+follower", + "-follower", + "+createdAt", + "-createdAt", + "+updatedAt", + "-updatedAt", + ], + }, + state: { + type: "string", + enum: ["all", "admin", "moderator", "adminOrModerator", "alive"], + default: "all", + }, + origin: { + type: "string", + enum: ["combined", "local", "remote"], + default: "local", + }, hostname: { - type: 'string', + type: "string", nullable: true, default: null, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Users.createQueryBuilder('user'); - query.where('user.isExplorable = TRUE'); + const query = Users.createQueryBuilder("user"); + query.where("user.isExplorable = TRUE"); switch (ps.state) { - case 'admin': query.andWhere('user.isAdmin = TRUE'); break; - case 'moderator': query.andWhere('user.isModerator = TRUE'); break; - case 'adminOrModerator': query.andWhere('user.isAdmin = TRUE OR user.isModerator = TRUE'); break; - case 'alive': query.andWhere('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break; + case "admin": + query.andWhere("user.isAdmin = TRUE"); + break; + case "moderator": + query.andWhere("user.isModerator = TRUE"); + break; + case "adminOrModerator": + query.andWhere("user.isAdmin = TRUE OR user.isModerator = TRUE"); + break; + case "alive": + query.andWhere("user.updatedAt > :date", { + date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5), + }); + break; } switch (ps.origin) { - case 'local': query.andWhere('user.host IS NULL'); break; - case 'remote': query.andWhere('user.host IS NOT NULL'); break; + case "local": + query.andWhere("user.host IS NULL"); + break; + case "remote": + query.andWhere("user.host IS NOT NULL"); + break; } if (ps.hostname) { - query.andWhere('user.host = :hostname', { hostname: ps.hostname.toLowerCase() }); + query.andWhere("user.host = :hostname", { + hostname: ps.hostname.toLowerCase(), + }); } switch (ps.sort) { - case '+follower': query.orderBy('user.followersCount', 'DESC'); break; - case '-follower': query.orderBy('user.followersCount', 'ASC'); break; - case '+createdAt': query.orderBy('user.createdAt', 'DESC'); break; - case '-createdAt': query.orderBy('user.createdAt', 'ASC'); break; - case '+updatedAt': query.andWhere('user.updatedAt IS NOT NULL').orderBy('user.updatedAt', 'DESC'); break; - case '-updatedAt': query.andWhere('user.updatedAt IS NOT NULL').orderBy('user.updatedAt', 'ASC'); break; - default: query.orderBy('user.id', 'ASC'); break; + case "+follower": + query.orderBy("user.followersCount", "DESC"); + break; + case "-follower": + query.orderBy("user.followersCount", "ASC"); + break; + case "+createdAt": + query.orderBy("user.createdAt", "DESC"); + break; + case "-createdAt": + query.orderBy("user.createdAt", "ASC"); + break; + case "+updatedAt": + query + .andWhere("user.updatedAt IS NOT NULL") + .orderBy("user.updatedAt", "DESC"); + break; + case "-updatedAt": + query + .andWhere("user.updatedAt IS NOT NULL") + .orderBy("user.updatedAt", "ASC"); + break; + default: + query.orderBy("user.id", "ASC"); + break; } if (me) generateMutedUserQueryForUsers(query, me); diff --git a/packages/backend/src/server/api/endpoints/users/clips.ts b/packages/backend/src/server/api/endpoints/users/clips.ts index becfad52d..0dc90b8f9 100644 --- a/packages/backend/src/server/api/endpoints/users/clips.ts +++ b/packages/backend/src/server/api/endpoints/users/clips.ts @@ -1,44 +1,47 @@ -import { Clips } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Clips } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['users', 'clips'], + tags: ["users", "clips"], requireCredentialPrivateMode: true, - description: 'Show all clips this user owns.', + description: "Show all clips this user owns.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Clip', + type: "object", + optional: false, + nullable: false, + ref: "Clip", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Clips.createQueryBuilder('clip'), ps.sinceId, ps.untilId) - .andWhere('clip.userId = :userId', { userId: ps.userId }) - .andWhere('clip.isPublic = true'); + const query = makePaginationQuery( + Clips.createQueryBuilder("clip"), + ps.sinceId, + ps.untilId, + ) + .andWhere("clip.userId = :userId", { userId: ps.userId }) + .andWhere("clip.isPublic = true"); - const clips = await query - .take(ps.limit) - .getMany(); + const clips = await query.take(ps.limit).getMany(); return await Clips.packMany(clips); }); diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 4971d21b0..138343d9f 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -1,76 +1,82 @@ -import { IsNull } from 'typeorm'; -import { Users, Followings, UserProfiles } from '@/models/index.js'; -import { toPunyNullable } from '@/misc/convert-host.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { IsNull } from "typeorm"; +import { Users, Followings, UserProfiles } from "@/models/index.js"; +import { toPunyNullable } from "@/misc/convert-host.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Show everyone that follows this user.', + description: "Show everyone that follows this user.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', + type: "object", + optional: false, + nullable: false, + ref: "Following", }, }, errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '27fa5435-88ab-43de-9360-387de88727cd', + message: "No such user.", + code: "NO_SUCH_USER", + id: "27fa5435-88ab-43de-9360-387de88727cd", }, forbidden: { - message: 'Forbidden.', - code: 'FORBIDDEN', - id: '3c6a84db-d619-26af-ca14-06232a21df8a', + message: "Forbidden.", + code: "FORBIDDEN", + id: "3c6a84db-d619-26af-ca14-06232a21df8a", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, anyOf: [ { properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], }, { properties: { - username: { type: 'string' }, + username: { type: "string" }, host: { - type: 'string', + type: "string", nullable: true, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", }, }, - required: ['username', 'host'], + required: ["username", "host"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOneBy(ps.userId != null - ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) ?? IsNull() }); + const user = await Users.findOneBy( + ps.userId != null + ? { id: ps.userId } + : { + usernameLower: ps.username!.toLowerCase(), + host: toPunyNullable(ps.host) ?? IsNull(), + }, + ); if (user == null) { throw new ApiError(meta.errors.noSuchUser); @@ -78,11 +84,11 @@ export default define(meta, paramDef, async (ps, me) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { - if (me == null || (me.id !== user.id)) { + if (profile.ffVisibility === "private") { + if (me == null || me.id !== user.id) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.ffVisibility === "followers") { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { @@ -96,13 +102,15 @@ export default define(meta, paramDef, async (ps, me) => { } } - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere('following.followeeId = :userId', { userId: user.id }) - .innerJoinAndSelect('following.follower', 'follower'); + const query = makePaginationQuery( + Followings.createQueryBuilder("following"), + ps.sinceId, + ps.untilId, + ) + .andWhere("following.followeeId = :userId", { userId: user.id }) + .innerJoinAndSelect("following.follower", "follower"); - const followings = await query - .take(ps.limit) - .getMany(); + const followings = await query.take(ps.limit).getMany(); return await Followings.packMany(followings, me, { populateFollower: true }); }); diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 043841aa4..967379d0c 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -1,76 +1,82 @@ -import { IsNull } from 'typeorm'; -import { Users, Followings, UserProfiles } from '@/models/index.js'; -import { toPunyNullable } from '@/misc/convert-host.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { IsNull } from "typeorm"; +import { Users, Followings, UserProfiles } from "@/models/index.js"; +import { toPunyNullable } from "@/misc/convert-host.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Show everyone that this user is following.', + description: "Show everyone that this user is following.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', + type: "object", + optional: false, + nullable: false, + ref: "Following", }, }, errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '63e4aba4-4156-4e53-be25-c9559e42d71b', + message: "No such user.", + code: "NO_SUCH_USER", + id: "63e4aba4-4156-4e53-be25-c9559e42d71b", }, forbidden: { - message: 'Forbidden.', - code: 'FORBIDDEN', - id: 'f6cdb0df-c19f-ec5c-7dbb-0ba84a1f92ba', + message: "Forbidden.", + code: "FORBIDDEN", + id: "f6cdb0df-c19f-ec5c-7dbb-0ba84a1f92ba", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, anyOf: [ { properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], }, { properties: { - username: { type: 'string' }, + username: { type: "string" }, host: { - type: 'string', + type: "string", nullable: true, - description: 'The local host is represented with `null`.', + description: "The local host is represented with `null`.", }, }, - required: ['username', 'host'], + required: ["username", "host"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOneBy(ps.userId != null - ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) ?? IsNull() }); + const user = await Users.findOneBy( + ps.userId != null + ? { id: ps.userId } + : { + usernameLower: ps.username!.toLowerCase(), + host: toPunyNullable(ps.host) ?? IsNull(), + }, + ); if (user == null) { throw new ApiError(meta.errors.noSuchUser); @@ -78,11 +84,11 @@ export default define(meta, paramDef, async (ps, me) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { - if (me == null || (me.id !== user.id)) { + if (profile.ffVisibility === "private") { + if (me == null || me.id !== user.id) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.ffVisibility === "followers") { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { @@ -96,13 +102,15 @@ export default define(meta, paramDef, async (ps, me) => { } } - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere('following.followerId = :userId', { userId: user.id }) - .innerJoinAndSelect('following.followee', 'followee'); + const query = makePaginationQuery( + Followings.createQueryBuilder("following"), + ps.sinceId, + ps.untilId, + ) + .andWhere("following.followerId = :userId", { userId: user.id }) + .innerJoinAndSelect("following.followee", "followee"); - const followings = await query - .take(ps.limit) - .getMany(); + const followings = await query.take(ps.limit).getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); }); diff --git a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts index 95ca77825..5d64fb472 100644 --- a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts @@ -1,43 +1,45 @@ -import define from '../../../define.js'; -import { GalleryPosts } from '@/models/index.js'; -import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import define from "../../../define.js"; +import { GalleryPosts } from "@/models/index.js"; +import { makePaginationQuery } from "../../../common/make-pagination-query.js"; export const meta = { - tags: ['users', 'gallery'], + tags: ["users", "gallery"], requireCredentialPrivateMode: true, - description: 'Show all gallery posts by the given user.', + description: "Show all gallery posts by the given user.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', + type: "object", + optional: false, + nullable: false, + ref: "GalleryPost", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) - .andWhere(`post.userId = :userId`, { userId: ps.userId }); + const query = makePaginationQuery( + GalleryPosts.createQueryBuilder("post"), + ps.sinceId, + ps.untilId, + ).andWhere("post.userId = :userId", { userId: ps.userId }); - const posts = await query - .take(ps.limit) - .getMany(); + const posts = await query.take(ps.limit).getMany(); return await GalleryPosts.packMany(posts, user); }); diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts index 8cf3ea040..9722804c8 100644 --- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -1,33 +1,38 @@ -import { Not, In, IsNull } from 'typeorm'; -import { maximum } from '@/prelude/array.js'; -import { Notes, Users } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; +import { Not, In, IsNull } from "typeorm"; +import { maximum } from "@/prelude/array.js"; +import { Notes, Users } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Get a list of other users that the specified user frequently replies to.', + description: + "Get a list of other users that the specified user frequently replies to.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { user: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, weight: { - type: 'number', - optional: false, nullable: false, + type: "number", + optional: false, + nullable: false, }, }, }, @@ -35,27 +40,27 @@ export const meta = { errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'e6965129-7b2a-40a4-bae2-cd84cd434822', + message: "No such user.", + code: "NO_SUCH_USER", + id: "e6965129-7b2a-40a4-bae2-cd84cd434822", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + userId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -69,7 +74,7 @@ export default define(meta, paramDef, async (ps, me) => { id: -1, }, take: 1000, - select: ['replyId'], + select: ["replyId"], }); // 投稿が少なかったら中断 @@ -80,15 +85,15 @@ export default define(meta, paramDef, async (ps, me) => { // TODO ミュートを考慮 const replyTargetNotes = await Notes.find({ where: { - id: In(recentNotes.map(p => p.replyId)), + id: In(recentNotes.map((p) => p.replyId)), }, - select: ['userId'], + select: ["userId"], }); const repliedUsers: any = {}; // Extract replies from recent notes - for (const userId of replyTargetNotes.map(x => x.userId.toString())) { + for (const userId of replyTargetNotes.map((x) => x.userId.toString())) { if (repliedUsers[userId]) { repliedUsers[userId]++; } else { @@ -100,16 +105,20 @@ export default define(meta, paramDef, async (ps, me) => { const peak = maximum(Object.values(repliedUsers)); // Sort replies by frequency - const repliedUsersSorted = Object.keys(repliedUsers).sort((a, b) => repliedUsers[b] - repliedUsers[a]); + const repliedUsersSorted = Object.keys(repliedUsers).sort( + (a, b) => repliedUsers[b] - repliedUsers[a], + ); // Extract top replied users const topRepliedUsers = repliedUsersSorted.slice(0, ps.limit); // Make replies object (includes weights) - const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ - user: await Users.pack(user, me, { detail: true }), - weight: repliedUsers[user] / peak, - }))); + const repliesObj = await Promise.all( + topRepliedUsers.map(async (user) => ({ + user: await Users.pack(user, me, { detail: true }), + weight: repliedUsers[user] / peak, + })), + ); return repliesObj; }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/create.ts b/packages/backend/src/server/api/endpoints/users/groups/create.ts index 4a6362a3c..76bd78c49 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/create.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/create.ts @@ -1,41 +1,41 @@ -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; -import define from '../../../define.js'; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import type { UserGroupJoining } from "@/models/entities/user-group-joining.js"; +import define from "../../../define.js"; export const meta = { - tags: ['groups'], + tags: ["groups"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Create a new group.', + description: "Create a new group.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 100 }, + name: { type: "string", minLength: 1, maxLength: 100 }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const userGroup = await UserGroups.insert({ id: genId(), createdAt: new Date(), userId: user.id, name: ps.name, - } as UserGroup).then(x => UserGroups.findOneByOrFail(x.identifiers[0])); + } as UserGroup).then((x) => UserGroups.findOneByOrFail(x.identifiers[0])); // Push the owner await UserGroupJoinings.insert({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/delete.ts b/packages/backend/src/server/api/endpoints/users/groups/delete.ts index 2ff1f9aec..81c15ad38 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/delete.ts @@ -1,34 +1,33 @@ -import { UserGroups } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserGroups } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['groups'], + tags: ["groups"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Delete an existing group.', + description: "Delete an existing group.", errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '63dbd64c-cd77-413f-8e08-61781e210b38', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "63dbd64c-cd77-413f-8e08-61781e210b38", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, }, - required: ['groupId'], + required: ["groupId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const userGroup = await UserGroups.findOneBy({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts index 220fff5f3..5cb3a7bad 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts @@ -1,36 +1,35 @@ -import { UserGroupJoinings, UserGroupInvitations } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; -import { ApiError } from '../../../../error.js'; -import define from '../../../../define.js'; +import { UserGroupJoinings, UserGroupInvitations } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { UserGroupJoining } from "@/models/entities/user-group-joining.js"; +import { ApiError } from "../../../../error.js"; +import define from "../../../../define.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Join a group the authenticated user has been invited to.', + description: "Join a group the authenticated user has been invited to.", errors: { noSuchInvitation: { - message: 'No such invitation.', - code: 'NO_SUCH_INVITATION', - id: '98c11eca-c890-4f42-9806-c8c8303ebb5e', + message: "No such invitation.", + code: "NO_SUCH_INVITATION", + id: "98c11eca-c890-4f42-9806-c8c8303ebb5e", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - invitationId: { type: 'string', format: 'misskey:id' }, + invitationId: { type: "string", format: "misskey:id" }, }, - required: ['invitationId'], + required: ["invitationId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation const invitation = await UserGroupInvitations.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts index 8d1d3db73..c04ebed23 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts @@ -1,34 +1,34 @@ -import { UserGroupInvitations } from '@/models/index.js'; -import define from '../../../../define.js'; -import { ApiError } from '../../../../error.js'; +import { UserGroupInvitations } from "@/models/index.js"; +import define from "../../../../define.js"; +import { ApiError } from "../../../../error.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Delete an existing group invitation for the authenticated user without joining the group.', + description: + "Delete an existing group invitation for the authenticated user without joining the group.", errors: { noSuchInvitation: { - message: 'No such invitation.', - code: 'NO_SUCH_INVITATION', - id: 'ad7471d4-2cd9-44b4-ac68-e7136b4ce656', + message: "No such invitation.", + code: "NO_SUCH_INVITATION", + id: "ad7471d4-2cd9-44b4-ac68-e7136b4ce656", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - invitationId: { type: 'string', format: 'misskey:id' }, + invitationId: { type: "string", format: "misskey:id" }, }, - required: ['invitationId'], + required: ["invitationId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation const invitation = await UserGroupInvitations.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/invite.ts b/packages/backend/src/server/api/endpoints/users/groups/invite.ts index 1a8d320f3..10cc21586 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invite.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invite.ts @@ -1,57 +1,60 @@ -import { UserGroups, UserGroupJoinings, UserGroupInvitations } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; -import { createNotification } from '@/services/create-notification.js'; -import { getUser } from '../../../common/getters.js'; -import { ApiError } from '../../../error.js'; -import define from '../../../define.js'; +import { + UserGroups, + UserGroupJoinings, + UserGroupInvitations, +} from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { UserGroupInvitation } from "@/models/entities/user-group-invitation.js"; +import { createNotification } from "@/services/create-notification.js"; +import { getUser } from "../../../common/getters.js"; +import { ApiError } from "../../../error.js"; +import define from "../../../define.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Invite a user to an existing group.', + description: "Invite a user to an existing group.", errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '583f8bc0-8eee-4b78-9299-1e14fc91e409', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "583f8bc0-8eee-4b78-9299-1e14fc91e409", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'da52de61-002c-475b-90e1-ba64f9cf13a8', + message: "No such user.", + code: "NO_SUCH_USER", + id: "da52de61-002c-475b-90e1-ba64f9cf13a8", }, alreadyAdded: { - message: 'That user has already been added to that group.', - code: 'ALREADY_ADDED', - id: '7e35c6a0-39b2-4488-aea6-6ee20bd5da2c', + message: "That user has already been added to that group.", + code: "ALREADY_ADDED", + id: "7e35c6a0-39b2-4488-aea6-6ee20bd5da2c", }, alreadyInvited: { - message: 'That user has already been invited to that group.', - code: 'ALREADY_INVITED', - id: 'ee0f58b4-b529-4d13-b761-b9a3e69f97e6', + message: "That user has already been invited to that group.", + code: "ALREADY_INVITED", + id: "ee0f58b4-b529-4d13-b761-b9a3e69f97e6", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['groupId', 'userId'], + required: ["groupId", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ @@ -64,8 +67,9 @@ export default define(meta, paramDef, async (ps, me) => { } // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -92,10 +96,12 @@ export default define(meta, paramDef, async (ps, me) => { createdAt: new Date(), userId: user.id, userGroupId: userGroup.id, - } as UserGroupInvitation).then(x => UserGroupInvitations.findOneByOrFail(x.identifiers[0])); + } as UserGroupInvitation).then((x) => + UserGroupInvitations.findOneByOrFail(x.identifiers[0]), + ); // 通知を作成 - createNotification(user.id, 'groupInvited', { + createNotification(user.id, "groupInvited", { notifierId: me.id, userGroupInvitationId: invitation.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/joined.ts b/packages/backend/src/server/api/endpoints/users/groups/joined.ts index 16c6e544e..8422cf586 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/joined.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/joined.ts @@ -1,34 +1,35 @@ -import { Not, In } from 'typeorm'; -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import define from '../../../define.js'; +import { Not, In } from "typeorm"; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['groups', 'account'], + tags: ["groups", "account"], requireCredential: true, - kind: 'read:user-groups', + kind: "read:user-groups", - description: 'List the groups that the authenticated user is a member of.', + description: "List the groups that the authenticated user is a member of.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const ownedGroups = await UserGroups.findBy({ userId: me.id, @@ -36,10 +37,12 @@ export default define(meta, paramDef, async (ps, me) => { const joinings = await UserGroupJoinings.findBy({ userId: me.id, - ...(ownedGroups.length > 0 ? { - userGroupId: Not(In(ownedGroups.map(x => x.id))), - } : {}), + ...(ownedGroups.length > 0 + ? { + userGroupId: Not(In(ownedGroups.map((x) => x.id))), + } + : {}), }); - return await Promise.all(joinings.map(x => UserGroups.pack(x.userGroupId))); + return await Promise.all(joinings.map((x) => UserGroups.pack(x.userGroupId))); }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/leave.ts b/packages/backend/src/server/api/endpoints/users/groups/leave.ts index 83dc757db..d963b1826 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/leave.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/leave.ts @@ -1,40 +1,40 @@ -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead.', + description: + "Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead.", errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '62780270-1f67-5dc0-daca-3eb510612e31', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "62780270-1f67-5dc0-daca-3eb510612e31", }, youAreOwner: { - message: 'Your are the owner.', - code: 'YOU_ARE_OWNER', - id: 'b6d6e0c2-ef8a-9bb8-653d-79f4a3107c69', + message: "Your are the owner.", + code: "YOU_ARE_OWNER", + id: "b6d6e0c2-ef8a-9bb8-653d-79f4a3107c69", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, }, - required: ['groupId'], + required: ["groupId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/owned.ts b/packages/backend/src/server/api/endpoints/users/groups/owned.ts index d77cf1a52..d86185ff0 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/owned.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/owned.ts @@ -1,37 +1,38 @@ -import { UserGroups } from '@/models/index.js'; -import define from '../../../define.js'; +import { UserGroups } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['groups', 'account'], + tags: ["groups", "account"], requireCredential: true, - kind: 'read:user-groups', + kind: "read:user-groups", - description: 'List the groups that the authenticated user is the owner of.', + description: "List the groups that the authenticated user is the owner of.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const userGroups = await UserGroups.findBy({ userId: me.id, }); - return await Promise.all(userGroups.map(x => UserGroups.pack(x))); + return await Promise.all(userGroups.map((x) => UserGroups.pack(x))); }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/pull.ts b/packages/backend/src/server/api/endpoints/users/groups/pull.ts index ba67a1e5c..1f79a2d2b 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/pull.ts @@ -1,48 +1,48 @@ -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Removes a specified user from a group. The owner can not be removed.', + description: + "Removes a specified user from a group. The owner can not be removed.", errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '4662487c-05b1-4b78-86e5-fd46998aba74', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "4662487c-05b1-4b78-86e5-fd46998aba74", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '0b5cc374-3681-41da-861e-8bc1146f7a55', + message: "No such user.", + code: "NO_SUCH_USER", + id: "0b5cc374-3681-41da-861e-8bc1146f7a55", }, isOwner: { - message: 'The user is the owner.', - code: 'IS_OWNER', - id: '1546eed5-4414-4dea-81c1-b0aec4f6d2af', + message: "The user is the owner.", + code: "IS_OWNER", + id: "1546eed5-4414-4dea-81c1-b0aec4f6d2af", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['groupId', 'userId'], + required: ["groupId", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ @@ -55,8 +55,9 @@ export default define(meta, paramDef, async (ps, me) => { } // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -65,5 +66,8 @@ export default define(meta, paramDef, async (ps, me) => { } // Pull the user - await UserGroupJoinings.delete({ userGroupId: userGroup.id, userId: user.id }); + await UserGroupJoinings.delete({ + userGroupId: userGroup.id, + userId: user.id, + }); }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/show.ts b/packages/backend/src/server/api/endpoints/users/groups/show.ts index 21e3d9da2..46f4410c8 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/show.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/show.ts @@ -1,40 +1,40 @@ -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['groups', 'account'], + tags: ["groups", "account"], requireCredential: true, - kind: 'read:user-groups', + kind: "read:user-groups", - description: 'Show the properties of a group.', + description: "Show the properties of a group.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: 'ea04751e-9b7e-487b-a509-330fb6bd6b9b', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "ea04751e-9b7e-487b-a509-330fb6bd6b9b", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, }, - required: ['groupId'], + required: ["groupId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts index 6456e70dd..032244157 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts @@ -1,54 +1,55 @@ -import { UserGroups, UserGroupJoinings } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import { UserGroups, UserGroupJoinings } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['groups', 'users'], + tags: ["groups", "users"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Transfer ownership of a group from the authenticated user to another user.', + description: + "Transfer ownership of a group from the authenticated user to another user.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '8e31d36b-2f88-4ccd-a438-e2d78a9162db', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "8e31d36b-2f88-4ccd-a438-e2d78a9162db", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '711f7ebb-bbb9-4dfa-b540-b27809fed5e9', + message: "No such user.", + code: "NO_SUCH_USER", + id: "711f7ebb-bbb9-4dfa-b540-b27809fed5e9", }, noSuchGroupMember: { - message: 'No such group member.', - code: 'NO_SUCH_GROUP_MEMBER', - id: 'd31bebee-196d-42c2-9a3e-9474d4be6cc4', + message: "No such group member.", + code: "NO_SUCH_GROUP_MEMBER", + id: "d31bebee-196d-42c2-9a3e-9474d4be6cc4", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, + groupId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['groupId', 'userId'], + required: ["groupId", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ @@ -61,8 +62,9 @@ export default define(meta, paramDef, async (ps, me) => { } // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/update.ts b/packages/backend/src/server/api/endpoints/users/groups/update.ts index 0a96165fc..fa720c9c4 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/update.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/update.ts @@ -1,41 +1,41 @@ -import { UserGroups } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserGroups } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['groups'], + tags: ["groups"], requireCredential: true, - kind: 'write:user-groups', + kind: "write:user-groups", - description: 'Update the properties of a group.', + description: "Update the properties of a group.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserGroup', + type: "object", + optional: false, + nullable: false, + ref: "UserGroup", }, errors: { noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '9081cda3-7a9e-4fac-a6ce-908d70f282f6', + message: "No such group.", + code: "NO_SUCH_GROUP", + id: "9081cda3-7a9e-4fac-a6ce-908d70f282f6", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - groupId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 100 }, + groupId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 100 }, }, - required: ['groupId', 'name'], + required: ["groupId", "name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index 783e63f5d..6bbbf603e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -1,40 +1,40 @@ -import { UserLists } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { UserList } from '@/models/entities/user-list.js'; -import define from '../../../define.js'; +import { UserLists } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { UserList } from "@/models/entities/user-list.js"; +import define from "../../../define.js"; export const meta = { - tags: ['lists'], + tags: ["lists"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Create a new list of users.', + description: "Create a new list of users.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserList', + type: "object", + optional: false, + nullable: false, + ref: "UserList", }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - name: { type: 'string', minLength: 1, maxLength: 100 }, + name: { type: "string", minLength: 1, maxLength: 100 }, }, - required: ['name'], + required: ["name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const userList = await UserLists.insert({ id: genId(), createdAt: new Date(), userId: user.id, name: ps.name, - } as UserList).then(x => UserLists.findOneByOrFail(x.identifiers[0])); + } as UserList).then((x) => UserLists.findOneByOrFail(x.identifiers[0])); return await UserLists.pack(userList); }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/delete-all.ts b/packages/backend/src/server/api/endpoints/users/lists/delete-all.ts index 9bea5c164..49c4cf6f6 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/delete-all.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/delete-all.ts @@ -1,32 +1,31 @@ -import { UserLists } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserLists } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['lists'], + tags: ["lists"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Delete all lists of users.', + description: "Delete all lists of users.", errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '78436795-db79-42f5-b1e2-55ea2cf19166', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "78436795-db79-42f5-b1e2-55ea2cf19166", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - while (await UserLists.findOneBy({ userId: user.id }) != null) { + while ((await UserLists.findOneBy({ userId: user.id })) != null) { const userList = await UserLists.findOneBy({ userId: user.id }); if (userList == null) { throw new ApiError(meta.errors.noSuchList); diff --git a/packages/backend/src/server/api/endpoints/users/lists/delete.ts b/packages/backend/src/server/api/endpoints/users/lists/delete.ts index 5a7613c98..456629567 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/delete.ts @@ -1,34 +1,33 @@ -import { UserLists } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserLists } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['lists'], + tags: ["lists"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Delete an existing list of users.', + description: "Delete an existing list of users.", errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '78436795-db79-42f5-b1e2-55ea2cf19166', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "78436795-db79-42f5-b1e2-55ea2cf19166", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, + listId: { type: "string", format: "misskey:id" }, }, - required: ['listId'], + required: ["listId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const userList = await UserLists.findOneBy({ id: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/list.ts b/packages/backend/src/server/api/endpoints/users/lists/list.ts index 889052fa3..5d590ee0e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/list.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/list.ts @@ -1,37 +1,38 @@ -import { UserLists } from '@/models/index.js'; -import define from '../../../define.js'; +import { UserLists } from "@/models/index.js"; +import define from "../../../define.js"; export const meta = { - tags: ['lists', 'account'], + tags: ["lists", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", - description: 'Show all lists that the authenticated user has created.', + description: "Show all lists that the authenticated user has created.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserList', + type: "object", + optional: false, + nullable: false, + ref: "UserList", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: {}, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const userLists = await UserLists.findBy({ userId: me.id, }); - return await Promise.all(userLists.map(x => UserLists.pack(x))); + return await Promise.all(userLists.map((x) => UserLists.pack(x))); }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/pull.ts b/packages/backend/src/server/api/endpoints/users/lists/pull.ts index d3d1d6555..07fae2067 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/pull.ts @@ -1,43 +1,42 @@ -import { publishUserListStream } from '@/services/stream.js'; -import { UserLists, UserListJoinings, Users } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import { publishUserListStream } from "@/services/stream.js"; +import { UserLists, UserListJoinings, Users } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['lists', 'users'], + tags: ["lists", "users"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Remove a user from a list.', + description: "Remove a user from a list.", errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '7f44670e-ab16-43b8-b4c1-ccd2ee89cc02', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "7f44670e-ab16-43b8-b4c1-ccd2ee89cc02", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '588e7f72-c744-4a61-b180-d354e912bda2', + message: "No such user.", + code: "NO_SUCH_USER", + id: "588e7f72-c744-4a61-b180-d354e912bda2", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, + listId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['listId', 'userId'], + required: ["listId", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOneBy({ @@ -50,13 +49,14 @@ export default define(meta, paramDef, async (ps, me) => { } // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); // Pull the user await UserListJoinings.delete({ userListId: userList.id, userId: user.id }); - publishUserListStream(userList.id, 'userRemoved', await Users.pack(user)); + publishUserListStream(userList.id, "userRemoved", await Users.pack(user)); }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts index 12b7b8634..a14195bbc 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/push.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts @@ -1,55 +1,55 @@ -import { pushUserToUserList } from '@/services/user-list/push.js'; -import { UserLists, UserListJoinings, Blockings } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; -import { getUser } from '../../../common/getters.js'; +import { pushUserToUserList } from "@/services/user-list/push.js"; +import { UserLists, UserListJoinings, Blockings } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; +import { getUser } from "../../../common/getters.js"; export const meta = { - tags: ['lists', 'users'], + tags: ["lists", "users"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Add a user to an existing list.', + description: "Add a user to an existing list.", errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '2214501d-ac96-4049-b717-91e42272a711', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "2214501d-ac96-4049-b717-91e42272a711", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'a89abd3d-f0bc-4cce-beb1-2f446f4f1e6a', + message: "No such user.", + code: "NO_SUCH_USER", + id: "a89abd3d-f0bc-4cce-beb1-2f446f4f1e6a", }, alreadyAdded: { - message: 'That user has already been added to that list.', - code: 'ALREADY_ADDED', - id: '1de7c884-1595-49e9-857e-61f12f4d4fc5', + message: "That user has already been added to that list.", + code: "ALREADY_ADDED", + id: "1de7c884-1595-49e9-857e-61f12f4d4fc5", }, youHaveBeenBlocked: { - message: 'You cannot push this user because you have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: '990232c5-3f9d-4d83-9f3f-ef27b6332a4b', + message: + "You cannot push this user because you have been blocked by this user.", + code: "YOU_HAVE_BEEN_BLOCKED", + id: "990232c5-3f9d-4d83-9f3f-ef27b6332a4b", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, + listId: { type: "string", format: "misskey:id" }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['listId', 'userId'], + required: ["listId", "userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOneBy({ @@ -62,8 +62,9 @@ export default define(meta, paramDef, async (ps, me) => { } // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index fd0612f73..716fd405d 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -1,40 +1,40 @@ -import { UserLists } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserLists } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['lists', 'account'], + tags: ["lists", "account"], requireCredential: true, - kind: 'read:account', + kind: "read:account", - description: 'Show the properties of a list.', + description: "Show the properties of a list.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserList', + type: "object", + optional: false, + nullable: false, + ref: "UserList", }, errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '7bc05c21-1d7a-41ae-88f1-66820f4dc686', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "7bc05c21-1d7a-41ae-88f1-66820f4dc686", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, + listId: { type: "string", format: "misskey:id" }, }, - required: ['listId'], + required: ["listId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/lists/update.ts b/packages/backend/src/server/api/endpoints/users/lists/update.ts index 65e708b95..0ac788fd3 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update.ts @@ -1,41 +1,41 @@ -import { UserLists } from '@/models/index.js'; -import define from '../../../define.js'; -import { ApiError } from '../../../error.js'; +import { UserLists } from "@/models/index.js"; +import define from "../../../define.js"; +import { ApiError } from "../../../error.js"; export const meta = { - tags: ['lists'], + tags: ["lists"], requireCredential: true, - kind: 'write:account', + kind: "write:account", - description: 'Update the properties of a list.', + description: "Update the properties of a list.", res: { - type: 'object', - optional: false, nullable: false, - ref: 'UserList', + type: "object", + optional: false, + nullable: false, + ref: "UserList", }, errors: { noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '796666fe-3dff-4d39-becb-8a5932c1d5b7', + message: "No such list.", + code: "NO_SUCH_LIST", + id: "796666fe-3dff-4d39-becb-8a5932c1d5b7", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - listId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string', minLength: 1, maxLength: 100 }, + listId: { type: "string", format: "misskey:id" }, + name: { type: "string", minLength: 1, maxLength: 100 }, }, - required: ['listId', 'name'], + required: ["listId", "name"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the list const userList = await UserLists.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 1e205eec3..724cfc9af 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -1,80 +1,91 @@ -import { Brackets } from 'typeorm'; -import { Notes } from '@/models/index.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; -import { getUser } from '../../common/getters.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { Brackets } from "typeorm"; +import { Notes } from "@/models/index.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; +import { getUser } from "../../common/getters.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; +import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; export const meta = { - tags: ['users', 'notes'], + tags: ["users", "notes"], requireCredentialPrivateMode: true, - description: 'Show all notes that this user created.', + description: "Show all notes that this user created.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', + type: "object", + optional: false, + nullable: false, + ref: "Note", }, }, errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '27e494ba-2ac2-48e8-893b-10d4d8c2387b', + message: "No such user.", + code: "NO_SUCH_USER", + id: "27e494ba-2ac2-48e8-893b-10d4d8c2387b", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - includeReplies: { type: 'boolean', default: true }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, - includeMyRenotes: { type: 'boolean', default: true }, - withFiles: { type: 'boolean', default: false }, - fileType: { type: 'array', items: { - type: 'string', - } }, - excludeNsfw: { type: 'boolean', default: false }, + userId: { type: "string", format: "misskey:id" }, + includeReplies: { type: "boolean", default: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, + includeMyRenotes: { type: "boolean", default: true }, + withFiles: { type: "boolean", default: false }, + fileType: { + type: "array", + items: { + type: "string", + }, + }, + excludeNsfw: { type: "boolean", default: false }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('note.userId = :userId', { userId: user.id }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere("note.userId = :userId", { userId: user.id }) + .innerJoinAndSelect("note.user", "user") + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); generateVisibilityQuery(query, me); if (me) { @@ -83,36 +94,46 @@ export default define(meta, paramDef, async (ps, me) => { } if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); + query.andWhere("note.fileIds != '{}'"); } if (ps.fileType != null) { - query.andWhere('note.fileIds != \'{}\''); - query.andWhere(new Brackets(qb => { - for (const type of ps.fileType!) { - const i = ps.fileType!.indexOf(type); - qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type }); - } - })); + query.andWhere("note.fileIds != '{}'"); + query.andWhere( + new Brackets((qb) => { + for (const type of ps.fileType!) { + const i = ps.fileType!.indexOf(type); + qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { + [`type${i}`]: type, + }); + } + }), + ); if (ps.excludeNsfw) { - query.andWhere('note.cw IS NULL'); - query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)'); + query.andWhere("note.cw IS NULL"); + query.andWhere( + '0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)', + ); } } if (!ps.includeReplies) { - query.andWhere('note.replyId IS NULL'); + query.andWhere("note.replyId IS NULL"); } if (ps.includeMyRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.userId != :userId', { userId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); + query.andWhere( + new Brackets((qb) => { + qb.orWhere("note.userId != :userId", { userId: user.id }); + qb.orWhere("note.renoteId IS NULL"); + qb.orWhere("note.text IS NOT NULL"); + qb.orWhere("note.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', + ); + }), + ); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/users/pages.ts b/packages/backend/src/server/api/endpoints/users/pages.ts index b76071264..c08258b19 100644 --- a/packages/backend/src/server/api/endpoints/users/pages.ts +++ b/packages/backend/src/server/api/endpoints/users/pages.ts @@ -1,45 +1,48 @@ -import { Pages } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Pages } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; export const meta = { - tags: ['users', 'pages'], + tags: ["users", "pages"], requireCredentialPrivateMode: true, - description: 'Show all pages this user created.', + description: "Show all pages this user created.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', + type: "object", + optional: false, + nullable: false, + ref: "Page", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId) - .andWhere('page.userId = :userId', { userId: ps.userId }) - .andWhere('page.visibility = \'public\'') - .andWhere('page.isPublic = true'); + const query = makePaginationQuery( + Pages.createQueryBuilder("page"), + ps.sinceId, + ps.untilId, + ) + .andWhere("page.userId = :userId", { userId: ps.userId }) + .andWhere("page.visibility = 'public'") + .andWhere("page.isPublic = true"); - const pages = await query - .take(ps.limit) - .getMany(); + const pages = await query.take(ps.limit).getMany(); return await Pages.packMany(pages); }); diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 144326958..17b7a04a0 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -1,50 +1,51 @@ -import { NoteReactions, UserProfiles } from '@/models/index.js'; -import define from '../../define.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; -import { ApiError } from '../../error.js'; +import { NoteReactions, UserProfiles } from "@/models/index.js"; +import define from "../../define.js"; +import { makePaginationQuery } from "../../common/make-pagination-query.js"; +import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['users', 'reactions'], + tags: ["users", "reactions"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Show all reactions this user made.', + description: "Show all reactions this user made.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'NoteReaction', + type: "object", + optional: false, + nullable: false, + ref: "NoteReaction", }, }, errors: { reactionsNotPublic: { - message: 'Reactions of the user is not public.', - code: 'REACTIONS_NOT_PUBLIC', - id: '673a7dd2-6924-1093-e0c0-e68456ceae5c', + message: "Reactions of the user is not public.", + code: "REACTIONS_NOT_PUBLIC", + id: "673a7dd2-6924-1093-e0c0-e68456ceae5c", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - sinceDate: { type: 'integer' }, - untilDate: { type: 'integer' }, + userId: { type: "string", format: "misskey:id" }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: "string", format: "misskey:id" }, + untilId: { type: "string", format: "misskey:id" }, + sinceDate: { type: "integer" }, + untilDate: { type: "integer" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const profile = await UserProfiles.findOneByOrFail({ userId: ps.userId }); @@ -52,16 +53,19 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.reactionsNotPublic); } - const query = makePaginationQuery(NoteReactions.createQueryBuilder('reaction'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('reaction.userId = :userId', { userId: ps.userId }) - .leftJoinAndSelect('reaction.note', 'note'); + const query = makePaginationQuery( + NoteReactions.createQueryBuilder("reaction"), + ps.sinceId, + ps.untilId, + ps.sinceDate, + ps.untilDate, + ) + .andWhere("reaction.userId = :userId", { userId: ps.userId }) + .leftJoinAndSelect("reaction.note", "note"); generateVisibilityQuery(query, me); - const reactions = await query - .take(ps.limit) - .getMany(); + const reactions = await query.take(ps.limit).getMany(); return await NoteReactions.packMany(reactions, me, { withNote: true }); }); diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts index d4dc524d9..615cca785 100644 --- a/packages/backend/src/server/api/endpoints/users/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts @@ -1,58 +1,64 @@ -import { Users, Followings } from '@/models/index.js'; -import define from '../../define.js'; -import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query.js'; -import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query.js'; -import { DAY } from '@/const.js'; +import { Users, Followings } from "@/models/index.js"; +import define from "../../define.js"; +import { generateMutedUserQueryForUsers } from "../../common/generate-muted-user-query.js"; +import { + generateBlockedUserQuery, + generateBlockQueryForUsers, +} from "../../common/generate-block-query.js"; +import { DAY } from "@/const.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: true, - kind: 'read:account', + kind: "read:account", - description: 'Show users that the authenticated user might be interested to follow.', + description: + "Show users that the authenticated user might be interested to follow.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailed', + type: "object", + optional: false, + nullable: false, + ref: "UserDetailed", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - offset: { type: 'integer', default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + offset: { type: "integer", default: 0 }, }, required: [], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const query = Users.createQueryBuilder('user') - .where('user.isLocked = FALSE') - .andWhere('user.isExplorable = TRUE') - .andWhere('user.host IS NULL') - .andWhere('user.updatedAt >= :date', { date: new Date(Date.now() - (7 * DAY)) }) - .andWhere('user.id != :meId', { meId: me.id }) - .orderBy('user.followersCount', 'DESC'); + const query = Users.createQueryBuilder("user") + .where("user.isLocked = FALSE") + .andWhere("user.isExplorable = TRUE") + .andWhere("user.host IS NULL") + .andWhere("user.updatedAt >= :date", { + date: new Date(Date.now() - 7 * DAY), + }) + .andWhere("user.id != :meId", { meId: me.id }) + .orderBy("user.followersCount", "DESC"); generateMutedUserQueryForUsers(query, me); generateBlockQueryForUsers(query, me); generateBlockedUserQuery(query, me); - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: me.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: me.id }); - query - .andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`); + query.andWhere(`user.id NOT IN (${followingQuery.getQuery()})`); query.setParameters(followingQuery.getParameters()); diff --git a/packages/backend/src/server/api/endpoints/users/relation.ts b/packages/backend/src/server/api/endpoints/users/relation.ts index 233a6a90b..01f39396d 100644 --- a/packages/backend/src/server/api/endpoints/users/relation.ts +++ b/packages/backend/src/server/api/endpoints/users/relation.ts @@ -1,92 +1,111 @@ -import { Users } from '@/models/index.js'; -import define from '../../define.js'; +import { Users } from "@/models/index.js"; +import define from "../../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: true, - description: 'Show the different kinds of relations between the authenticated user and the specified user(s).', + description: + "Show the different kinds of relations between the authenticated user and the specified user(s).", res: { - optional: false, nullable: false, + optional: false, + nullable: false, oneOf: [ { - type: 'object', + type: "object", properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, isFollowing: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hasPendingFollowRequestFromYou: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hasPendingFollowRequestToYou: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isFollowed: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isBlocking: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isBlocked: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isMuted: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, }, { - type: 'array', + type: "array", items: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + type: "string", + optional: false, + nullable: false, + format: "id", }, isFollowing: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hasPendingFollowRequestFromYou: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, hasPendingFollowRequestToYou: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isFollowed: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isBlocking: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isBlocked: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, isMuted: { - type: 'boolean', - optional: false, nullable: false, + type: "boolean", + optional: false, + nullable: false, }, }, }, @@ -96,26 +115,27 @@ export const meta = { } as const; export const paramDef = { - type: 'object', + type: "object", properties: { userId: { anyOf: [ - { type: 'string', format: 'misskey:id' }, + { type: "string", format: "misskey:id" }, { - type: 'array', - items: { type: 'string', format: 'misskey:id' }, + type: "array", + items: { type: "string", format: "misskey:id" }, }, ], }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const ids = Array.isArray(ps.userId) ? ps.userId : [ps.userId]; - const relations = await Promise.all(ids.map(id => Users.getRelation(me.id, id))); + const relations = await Promise.all( + ids.map((id) => Users.getRelation(me.id, id)), + ); return Array.isArray(ps.userId) ? relations : relations[0]; }); diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index a9987eafa..44d3f9b50 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -1,55 +1,55 @@ -import * as sanitizeHtml from 'sanitize-html'; -import { publishAdminStream } from '@/services/stream.js'; -import { AbuseUserReports, Users } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { sendEmail } from '@/services/send-email.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { getUser } from '../../common/getters.js'; -import { ApiError } from '../../error.js'; -import define from '../../define.js'; +import * as sanitizeHtml from "sanitize-html"; +import { publishAdminStream } from "@/services/stream.js"; +import { AbuseUserReports, Users } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { sendEmail } from "@/services/send-email.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { getUser } from "../../common/getters.js"; +import { ApiError } from "../../error.js"; +import define from "../../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: true, - description: 'File a report.', + description: "File a report.", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '1acefcb5-0959-43fd-9685-b48305736cb5', + message: "No such user.", + code: "NO_SUCH_USER", + id: "1acefcb5-0959-43fd-9685-b48305736cb5", }, cannotReportYourself: { - message: 'Cannot report yourself.', - code: 'CANNOT_REPORT_YOURSELF', - id: '1e13149e-b1e8-43cf-902e-c01dbfcb202f', + message: "Cannot report yourself.", + code: "CANNOT_REPORT_YOURSELF", + id: "1e13149e-b1e8-43cf-902e-c01dbfcb202f", }, cannotReportAdmin: { - message: 'Cannot report the admin.', - code: 'CANNOT_REPORT_THE_ADMIN', - id: '35e166f5-05fb-4f87-a2d5-adb42676d48f', + message: "Cannot report the admin.", + code: "CANNOT_REPORT_THE_ADMIN", + id: "35e166f5-05fb-4f87-a2d5-adb42676d48f", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, - comment: { type: 'string', minLength: 1, maxLength: 2048 }, + userId: { type: "string", format: "misskey:id" }, + comment: { type: "string", minLength: 1, maxLength: 2048 }, }, - required: ['userId', 'comment'], + required: ["userId", "comment"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + const user = await getUser(ps.userId).catch((e) => { + if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") + throw new ApiError(meta.errors.noSuchUser); throw e; }); @@ -69,20 +69,23 @@ export default define(meta, paramDef, async (ps, me) => { reporterId: me.id, reporterHost: null, comment: ps.comment, - }).then(x => AbuseUserReports.findOneByOrFail(x.identifiers[0])); + }).then((x) => AbuseUserReports.findOneByOrFail(x.identifiers[0])); // Publish event to moderators setImmediate(async () => { const moderators = await Users.find({ - where: [{ - isAdmin: true, - }, { - isModerator: true, - }], + where: [ + { + isAdmin: true, + }, + { + isModerator: true, + }, + ], }); for (const moderator of moderators) { - publishAdminStream(moderator.id, 'newAbuseUserReport', { + publishAdminStream(moderator.id, "newAbuseUserReport", { id: report.id, targetUserId: report.targetUserId, reporterId: report.reporterId, @@ -92,9 +95,12 @@ export default define(meta, paramDef, async (ps, me) => { const meta = await fetchMeta(); if (meta.email) { - sendEmail(meta.email, 'New abuse report', + sendEmail( + meta.email, + "New abuse report", sanitizeHtml(ps.comment), - sanitizeHtml(ps.comment)); + sanitizeHtml(ps.comment), + ); } }); }); diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index fa1cb8761..99aa2f1af 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -1,59 +1,59 @@ -import { Brackets } from 'typeorm'; -import { Followings, Users } from '@/models/index.js'; -import { USER_ACTIVE_THRESHOLD } from '@/const.js'; -import { User } from '@/models/entities/user.js'; -import define from '../../define.js'; +import { Brackets } from "typeorm"; +import { Followings, Users } from "@/models/index.js"; +import { USER_ACTIVE_THRESHOLD } from "@/const.js"; +import type { User } from "@/models/entities/user.js"; +import define from "../../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Search for a user by username and/or host.', + description: "Search for a user by username and/or host.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'User', + type: "object", + optional: false, + nullable: false, + ref: "User", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - username: { type: 'string', nullable: true }, - host: { type: 'string', nullable: true }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - detail: { type: 'boolean', default: true }, + username: { type: "string", nullable: true }, + host: { type: "string", nullable: true }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + detail: { type: "boolean", default: true }, }, - anyOf: [ - { required: ['username'] }, - { required: ['host'] }, - ], + anyOf: [{ required: ["username"] }, { required: ["host"] }], } as const; // TODO: avatar,bannerをJOINしたいけどエラーになる -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 + const activeThreshold = new Date(Date.now() - 1000 * 60 * 60 * 24 * 30); // 30日 if (ps.host) { - const q = Users.createQueryBuilder('user') - .where('user.isSuspended = FALSE') - .andWhere('user.host LIKE :host', { host: ps.host.toLowerCase() + '%' }); + const q = Users.createQueryBuilder("user") + .where("user.isSuspended = FALSE") + .andWhere("user.host LIKE :host", { host: `${ps.host.toLowerCase()}%` }); if (ps.username) { - q.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }); + q.andWhere("user.usernameLower LIKE :username", { + username: `${ps.username.toLowerCase()}%`, + }); } - q.andWhere('user.updatedAt IS NOT NULL'); - q.orderBy('user.updatedAt', 'DESC'); + q.andWhere("user.updatedAt IS NOT NULL"); + q.orderBy("user.updatedAt", "DESC"); const users = await q.take(ps.limit).getMany(); @@ -62,50 +62,60 @@ export default define(meta, paramDef, async (ps, me) => { let users: User[] = []; if (me) { - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: me.id }); + const followingQuery = Followings.createQueryBuilder("following") + .select("following.followeeId") + .where("following.followerId = :followerId", { followerId: me.id }); - const query = Users.createQueryBuilder('user') - .where(`user.id IN (${ followingQuery.getQuery() })`) - .andWhere('user.id != :meId', { meId: me.id }) - .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })); + const query = Users.createQueryBuilder("user") + .where(`user.id IN (${followingQuery.getQuery()})`) + .andWhere("user.id != :meId", { meId: me.id }) + .andWhere("user.isSuspended = FALSE") + .andWhere("user.usernameLower LIKE :username", { + username: `${ps.username.toLowerCase()}%`, + }) + .andWhere( + new Brackets((qb) => { + qb.where("user.updatedAt IS NULL").orWhere( + "user.updatedAt > :activeThreshold", + { activeThreshold: activeThreshold }, + ); + }), + ); query.setParameters(followingQuery.getParameters()); users = await query - .orderBy('user.usernameLower', 'ASC') + .orderBy("user.usernameLower", "ASC") .take(ps.limit) .getMany(); if (users.length < ps.limit) { - const otherQuery = await Users.createQueryBuilder('user') - .where(`user.id NOT IN (${ followingQuery.getQuery() })`) - .andWhere('user.id != :meId', { meId: me.id }) - .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere('user.updatedAt IS NOT NULL'); + const otherQuery = await Users.createQueryBuilder("user") + .where(`user.id NOT IN (${followingQuery.getQuery()})`) + .andWhere("user.id != :meId", { meId: me.id }) + .andWhere("user.isSuspended = FALSE") + .andWhere("user.usernameLower LIKE :username", { + username: `${ps.username.toLowerCase()}%`, + }) + .andWhere("user.updatedAt IS NOT NULL"); otherQuery.setParameters(followingQuery.getParameters()); const otherUsers = await otherQuery - .orderBy('user.updatedAt', 'DESC') + .orderBy("user.updatedAt", "DESC") .take(ps.limit - users.length) .getMany(); users = users.concat(otherUsers); } } else { - users = await Users.createQueryBuilder('user') - .where('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere('user.updatedAt IS NOT NULL') - .orderBy('user.updatedAt', 'DESC') + users = await Users.createQueryBuilder("user") + .where("user.isSuspended = FALSE") + .andWhere("user.usernameLower LIKE :username", { + username: `${ps.username.toLowerCase()}%`, + }) + .andWhere("user.updatedAt IS NOT NULL") + .orderBy("user.updatedAt", "DESC") .take(ps.limit - users.length) .getMany(); } diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 70aaa4526..db687a107 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -1,120 +1,146 @@ -import { Brackets } from 'typeorm'; -import { UserProfiles, Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import define from '../../define.js'; +import { Brackets } from "typeorm"; +import { UserProfiles, Users } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import define from "../../define.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Search for users.', + description: "Search for users.", res: { - type: 'array', - optional: false, nullable: false, + type: "array", + optional: false, + nullable: false, items: { - type: 'object', - optional: false, nullable: false, - ref: 'User', + type: "object", + optional: false, + nullable: false, + ref: "User", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - query: { type: 'string' }, - offset: { type: 'integer', default: 0 }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - origin: { type: 'string', enum: ['local', 'remote', 'combined'], default: 'combined' }, - detail: { type: 'boolean', default: true }, + query: { type: "string" }, + offset: { type: "integer", default: 0 }, + limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + origin: { + type: "string", + enum: ["local", "remote", "combined"], + default: "combined", + }, + detail: { type: "boolean", default: true }, }, - required: ['query'], + required: ["query"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 + const activeThreshold = new Date(Date.now() - 1000 * 60 * 60 * 24 * 30); // 30日 - const isUsername = ps.query.startsWith('@'); + const isUsername = ps.query.startsWith("@"); let users: User[] = []; if (isUsername) { - const usernameQuery = Users.createQueryBuilder('user') - .where('user.usernameLower LIKE :username', { username: ps.query.replace('@', '').toLowerCase() + '%' }) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE'); + const usernameQuery = Users.createQueryBuilder("user") + .where("user.usernameLower LIKE :username", { + username: `${ps.query.replace("@", "").toLowerCase()}%`, + }) + .andWhere( + new Brackets((qb) => { + qb.where("user.updatedAt IS NULL").orWhere( + "user.updatedAt > :activeThreshold", + { activeThreshold: activeThreshold }, + ); + }), + ) + .andWhere("user.isSuspended = FALSE"); - if (ps.origin === 'local') { - usernameQuery.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - usernameQuery.andWhere('user.host IS NOT NULL'); + if (ps.origin === "local") { + usernameQuery.andWhere("user.host IS NULL"); + } else if (ps.origin === "remote") { + usernameQuery.andWhere("user.host IS NOT NULL"); } users = await usernameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') + .orderBy("user.updatedAt", "DESC", "NULLS LAST") .take(ps.limit) .skip(ps.offset) .getMany(); } else { - const nameQuery = Users.createQueryBuilder('user') - .where(new Brackets(qb => { - qb.where('user.name ILIKE :query', { query: '%' + ps.query + '%' }); + const nameQuery = Users.createQueryBuilder("user") + .where( + new Brackets((qb) => { + qb.where("user.name ILIKE :query", { query: `%${ps.query}%` }); - // Also search username if it qualifies as username - if (Users.validateLocalUsername(ps.query)) { - qb.orWhere('user.usernameLower LIKE :username', { username: '%' + ps.query.toLowerCase() + '%' }); - } - })) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE'); + // Also search username if it qualifies as username + if (Users.validateLocalUsername(ps.query)) { + qb.orWhere("user.usernameLower LIKE :username", { + username: `%${ps.query.toLowerCase()}%`, + }); + } + }), + ) + .andWhere( + new Brackets((qb) => { + qb.where("user.updatedAt IS NULL").orWhere( + "user.updatedAt > :activeThreshold", + { activeThreshold: activeThreshold }, + ); + }), + ) + .andWhere("user.isSuspended = FALSE"); - if (ps.origin === 'local') { - nameQuery.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - nameQuery.andWhere('user.host IS NOT NULL'); + if (ps.origin === "local") { + nameQuery.andWhere("user.host IS NULL"); + } else if (ps.origin === "remote") { + nameQuery.andWhere("user.host IS NOT NULL"); } users = await nameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') + .orderBy("user.updatedAt", "DESC", "NULLS LAST") .take(ps.limit) .skip(ps.offset) .getMany(); if (users.length < ps.limit) { - const profQuery = UserProfiles.createQueryBuilder('prof') - .select('prof.userId') - .where('prof.description ILIKE :query', { query: '%' + ps.query + '%' }); + const profQuery = UserProfiles.createQueryBuilder("prof") + .select("prof.userId") + .where("prof.description ILIKE :query", { + query: `%${ps.query}%`, + }); - if (ps.origin === 'local') { - profQuery.andWhere('prof.userHost IS NULL'); - } else if (ps.origin === 'remote') { - profQuery.andWhere('prof.userHost IS NOT NULL'); + if (ps.origin === "local") { + profQuery.andWhere("prof.userHost IS NULL"); + } else if (ps.origin === "remote") { + profQuery.andWhere("prof.userHost IS NOT NULL"); } - const query = Users.createQueryBuilder('user') - .where(`user.id IN (${ profQuery.getQuery() })`) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE') + const query = Users.createQueryBuilder("user") + .where(`user.id IN (${profQuery.getQuery()})`) + .andWhere( + new Brackets((qb) => { + qb.where("user.updatedAt IS NULL").orWhere( + "user.updatedAt > :activeThreshold", + { activeThreshold: activeThreshold }, + ); + }), + ) + .andWhere("user.isSuspended = FALSE") .setParameters(profQuery.getParameters()); - users = users.concat(await query - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit) - .skip(ps.offset) - .getMany(), + users = users.concat( + await query + .orderBy("user.updatedAt", "DESC", "NULLS LAST") + .take(ps.limit) + .skip(ps.offset) + .getMany(), ); } } diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 892e37bdf..49cac81fd 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -1,31 +1,33 @@ -import { FindOptionsWhere, In, IsNull } from 'typeorm'; -import { resolveUser } from '@/remote/resolve-user.js'; -import { Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import define from '../../define.js'; -import { apiLogger } from '../../logger.js'; -import { ApiError } from '../../error.js'; +import type { FindOptionsWhere } from "typeorm"; +import { In, IsNull } from "typeorm"; +import { resolveUser } from "@/remote/resolve-user.js"; +import { Users } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import define from "../../define.js"; +import { apiLogger } from "../../logger.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Show the properties of a user.', + description: "Show the properties of a user.", res: { - optional: false, nullable: false, + optional: false, + nullable: false, oneOf: [ { - type: 'object', - ref: 'UserDetailed', + type: "object", + ref: "UserDetailed", }, { - type: 'array', + type: "array", items: { - type: 'object', - ref: 'UserDetailed', + type: "object", + ref: "UserDetailed", }, }, ], @@ -33,52 +35,56 @@ export const meta = { errors: { failedToResolveRemoteUser: { - message: 'Failed to resolve remote user.', - code: 'FAILED_TO_RESOLVE_REMOTE_USER', - id: 'ef7b9be4-9cba-4e6f-ab41-90ed171c7d3c', - kind: 'server', + message: "Failed to resolve remote user.", + code: "FAILED_TO_RESOLVE_REMOTE_USER", + id: "ef7b9be4-9cba-4e6f-ab41-90ed171c7d3c", + kind: "server", }, noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '4362f8dc-731f-4ad8-a694-be5a88922a24', + message: "No such user.", + code: "NO_SUCH_USER", + id: "4362f8dc-731f-4ad8-a694-be5a88922a24", }, }, } as const; export const paramDef = { - type: 'object', + type: "object", anyOf: [ { properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], }, { properties: { - userIds: { type: 'array', uniqueItems: true, items: { - type: 'string', format: 'misskey:id', - } }, - }, - required: ['userIds'], - }, - { - properties: { - username: { type: 'string' }, - host: { - type: 'string', - nullable: true, - description: 'The local host is represented with `null`.', + userIds: { + type: "array", + uniqueItems: true, + items: { + type: "string", + format: "misskey:id", + }, }, }, - required: ['username'], + required: ["userIds"], + }, + { + properties: { + username: { type: "string" }, + host: { + type: "string", + nullable: true, + description: "The local host is represented with `null`.", + }, + }, + required: ["username"], }, ], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { let user; @@ -89,33 +95,42 @@ export default define(meta, paramDef, async (ps, me) => { return []; } - const users = await Users.findBy(isAdminOrModerator ? { - id: In(ps.userIds), - } : { - id: In(ps.userIds), - isSuspended: false, - }); + const users = await Users.findBy( + isAdminOrModerator + ? { + id: In(ps.userIds), + } + : { + id: In(ps.userIds), + isSuspended: false, + }, + ); // リクエストされた通りに並べ替え const _users: User[] = []; for (const id of ps.userIds) { - _users.push(users.find(x => x.id === id)!); + _users.push(users.find((x) => x.id === id)!); } - return await Promise.all(_users.map(u => Users.pack(u, me, { - detail: true, - }))); + return await Promise.all( + _users.map((u) => + Users.pack(u, me, { + detail: true, + }), + ), + ); } else { // Lookup user - if (typeof ps.host === 'string' && typeof ps.username === 'string') { - user = await resolveUser(ps.username, ps.host).catch(e => { + if (typeof ps.host === "string" && typeof ps.username === "string") { + user = await resolveUser(ps.username, ps.host).catch((e) => { apiLogger.warn(`failed to resolve remote user: ${e}`); throw new ApiError(meta.errors.failedToResolveRemoteUser); }); } else { - const q: FindOptionsWhere = ps.userId != null - ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: IsNull() }; + const q: FindOptionsWhere = + ps.userId != null + ? { id: ps.userId } + : { usernameLower: ps.username!.toLowerCase(), host: IsNull() }; user = await Users.findOneBy(q); } diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts index a68b6ea40..83e821f49 100644 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ b/packages/backend/src/server/api/endpoints/users/stats.ts @@ -1,122 +1,151 @@ -import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, Users } from '@/models/index.js'; -import { awaitAll } from '@/prelude/await-all.js'; -import define from '../../define.js'; -import { ApiError } from '../../error.js'; +import { + DriveFiles, + Followings, + NoteFavorites, + NoteReactions, + Notes, + PageLikes, + PollVotes, + Users, +} from "@/models/index.js"; +import { awaitAll } from "@/prelude/await-all.js"; +import define from "../../define.js"; +import { ApiError } from "../../error.js"; export const meta = { - tags: ['users'], + tags: ["users"], requireCredential: false, requireCredentialPrivateMode: true, - description: 'Show statistics about a user.', + description: "Show statistics about a user.", errors: { noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '9e638e45-3b25-4ef7-8f95-07e8498f1819', + message: "No such user.", + code: "NO_SUCH_USER", + id: "9e638e45-3b25-4ef7-8f95-07e8498f1819", }, }, res: { - type: 'object', - optional: false, nullable: false, + type: "object", + optional: false, + nullable: false, properties: { notesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, repliesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, renotesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, repliedCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, renotedCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, pollVotesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, pollVotedCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, localFollowingCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, remoteFollowingCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, localFollowersCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, remoteFollowersCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, followingCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, followersCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, sentReactionsCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, receivedReactionsCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, noteFavoritesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, pageLikesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, pageLikedCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, driveFilesCount: { - type: 'integer', - optional: false, nullable: false, + type: "integer", + optional: false, + nullable: false, }, driveUsage: { - type: 'integer', - optional: false, nullable: false, - description: 'Drive usage in bytes', + type: "integer", + optional: false, + nullable: false, + description: "Drive usage in bytes", }, }, }, } as const; export const paramDef = { - type: 'object', + type: "object", properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: "string", format: "misskey:id" }, }, - required: ['userId'], + required: ["userId"], } as const; -// eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { @@ -124,71 +153,73 @@ export default define(meta, paramDef, async (ps, me) => { } const result = await awaitAll({ - notesCount: Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) + notesCount: Notes.createQueryBuilder("note") + .where("note.userId = :userId", { userId: user.id }) .getCount(), - repliesCount: Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.replyId IS NOT NULL') + repliesCount: Notes.createQueryBuilder("note") + .where("note.userId = :userId", { userId: user.id }) + .andWhere("note.replyId IS NOT NULL") .getCount(), - renotesCount: Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.renoteId IS NOT NULL') + renotesCount: Notes.createQueryBuilder("note") + .where("note.userId = :userId", { userId: user.id }) + .andWhere("note.renoteId IS NOT NULL") .getCount(), - repliedCount: Notes.createQueryBuilder('note') - .where('note.replyUserId = :userId', { userId: user.id }) + repliedCount: Notes.createQueryBuilder("note") + .where("note.replyUserId = :userId", { userId: user.id }) .getCount(), - renotedCount: Notes.createQueryBuilder('note') - .where('note.renoteUserId = :userId', { userId: user.id }) + renotedCount: Notes.createQueryBuilder("note") + .where("note.renoteUserId = :userId", { userId: user.id }) .getCount(), - pollVotesCount: PollVotes.createQueryBuilder('vote') - .where('vote.userId = :userId', { userId: user.id }) + pollVotesCount: PollVotes.createQueryBuilder("vote") + .where("vote.userId = :userId", { userId: user.id }) .getCount(), - pollVotedCount: PollVotes.createQueryBuilder('vote') - .innerJoin('vote.note', 'note') - .where('note.userId = :userId', { userId: user.id }) + pollVotedCount: PollVotes.createQueryBuilder("vote") + .innerJoin("vote.note", "note") + .where("note.userId = :userId", { userId: user.id }) .getCount(), - localFollowingCount: Followings.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NULL') + localFollowingCount: Followings.createQueryBuilder("following") + .where("following.followerId = :userId", { userId: user.id }) + .andWhere("following.followeeHost IS NULL") .getCount(), - remoteFollowingCount: Followings.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NOT NULL') + remoteFollowingCount: Followings.createQueryBuilder("following") + .where("following.followerId = :userId", { userId: user.id }) + .andWhere("following.followeeHost IS NOT NULL") .getCount(), - localFollowersCount: Followings.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NULL') + localFollowersCount: Followings.createQueryBuilder("following") + .where("following.followeeId = :userId", { userId: user.id }) + .andWhere("following.followerHost IS NULL") .getCount(), - remoteFollowersCount: Followings.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NOT NULL') + remoteFollowersCount: Followings.createQueryBuilder("following") + .where("following.followeeId = :userId", { userId: user.id }) + .andWhere("following.followerHost IS NOT NULL") .getCount(), - sentReactionsCount: NoteReactions.createQueryBuilder('reaction') - .where('reaction.userId = :userId', { userId: user.id }) + sentReactionsCount: NoteReactions.createQueryBuilder("reaction") + .where("reaction.userId = :userId", { userId: user.id }) .getCount(), - receivedReactionsCount: NoteReactions.createQueryBuilder('reaction') - .innerJoin('reaction.note', 'note') - .where('note.userId = :userId', { userId: user.id }) + receivedReactionsCount: NoteReactions.createQueryBuilder("reaction") + .innerJoin("reaction.note", "note") + .where("note.userId = :userId", { userId: user.id }) .getCount(), - noteFavoritesCount: NoteFavorites.createQueryBuilder('favorite') - .where('favorite.userId = :userId', { userId: user.id }) + noteFavoritesCount: NoteFavorites.createQueryBuilder("favorite") + .where("favorite.userId = :userId", { userId: user.id }) .getCount(), - pageLikesCount: PageLikes.createQueryBuilder('like') - .where('like.userId = :userId', { userId: user.id }) + pageLikesCount: PageLikes.createQueryBuilder("like") + .where("like.userId = :userId", { userId: user.id }) .getCount(), - pageLikedCount: PageLikes.createQueryBuilder('like') - .innerJoin('like.page', 'page') - .where('page.userId = :userId', { userId: user.id }) + pageLikedCount: PageLikes.createQueryBuilder("like") + .innerJoin("like.page", "page") + .where("page.userId = :userId", { userId: user.id }) .getCount(), - driveFilesCount: DriveFiles.createQueryBuilder('file') - .where('file.userId = :userId', { userId: user.id }) + driveFilesCount: DriveFiles.createQueryBuilder("file") + .where("file.userId = :userId", { userId: user.id }) .getCount(), driveUsage: DriveFiles.calcDriveUsageOf(user), }); - result.followingCount = result.localFollowingCount + result.remoteFollowingCount; - result.followersCount = result.localFollowersCount + result.remoteFollowersCount; + result.followingCount = + result.localFollowingCount + result.remoteFollowingCount; + result.followersCount = + result.localFollowersCount + result.remoteFollowersCount; return result; }); diff --git a/packages/backend/src/server/api/error.ts b/packages/backend/src/server/api/error.ts index 3f0861fdb..c58561a04 100644 --- a/packages/backend/src/server/api/error.ts +++ b/packages/backend/src/server/api/error.ts @@ -1,4 +1,10 @@ -type E = { message: string, code: string, id: string, kind?: 'client' | 'server', httpStatusCode?: number }; +type E = { + message: string; + code: string; + id: string; + kind?: "client" | "server"; + httpStatusCode?: number; +}; export class ApiError extends Error { public message: string; @@ -9,19 +15,21 @@ export class ApiError extends Error { public info?: any; constructor(e?: E | null | undefined, info?: any | null | undefined) { - if (e == null) e = { - message: 'Internal error occurred. Please contact us if the error persists.', - code: 'INTERNAL_ERROR', - id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac', - kind: 'server', - httpStatusCode: 500, - }; + if (e == null) + e = { + message: + "Internal error occurred. Please contact us if the error persists.", + code: "INTERNAL_ERROR", + id: "5d37dbcb-891e-41ca-a3d6-e690c97775ac", + kind: "server", + httpStatusCode: 500, + }; super(e.message); this.message = e.message; this.code = e.code; this.id = e.id; - this.kind = e.kind || 'client'; + this.kind = e.kind || "client"; this.httpStatusCode = e.httpStatusCode; this.info = info; } diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index 83ece51f5..b84bbdbb3 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -2,40 +2,48 @@ * API Server */ -import Koa from 'koa'; -import Router from '@koa/router'; -import multer from '@koa/multer'; -import bodyParser from 'koa-bodyparser'; -import cors from '@koa/cors'; - -import { Instances, AccessTokens, Users } from '@/models/index.js'; -import config from '@/config/index.js'; -import endpoints from './endpoints.js'; -import handler from './api-handler.js'; -import signup from './private/signup.js'; -import signin from './private/signin.js'; -import signupPending from './private/signup-pending.js'; -import discord from './service/discord.js'; -import github from './service/github.js'; -import twitter from './service/twitter.js'; +import Koa from "koa"; +import Router from "@koa/router"; +import multer from "@koa/multer"; +import bodyParser from "koa-bodyparser"; +import cors from "@koa/cors"; +import { Instances, AccessTokens, Users } from "@/models/index.js"; +import config from "@/config/index.js"; +import endpoints from "./endpoints.js"; +import compatibility from "./compatibility.js"; +import handler from "./api-handler.js"; +import signup from "./private/signup.js"; +import signin from "./private/signin.js"; +import signupPending from "./private/signup-pending.js"; +import discord from "./service/discord.js"; +import github from "./service/github.js"; +import twitter from "./service/twitter.js"; // Init app const app = new Koa(); -app.use(cors({ - origin: '*', -})); +app.use( + cors({ + origin: "*", + }), +); // No caching app.use(async (ctx, next) => { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); await next(); }); -app.use(bodyParser({ - // リクエストが multipart/form-data でない限りはJSONだと見なす - detectJSON: ctx => !ctx.is('multipart/form-data'), -})); +app.use( + bodyParser({ + // リクエストが multipart/form-data でない限りはJSONだと見なす + detectJSON: (ctx) => + !( + ctx.is("multipart/form-data") || + ctx.is("application/x-www-form-urlencoded") + ), + }), +); // Init multer instance const upload = multer({ @@ -52,18 +60,30 @@ const router = new Router(); /** * Register endpoint handlers */ -for (const endpoint of endpoints) { +for (const endpoint of [...endpoints, ...compatibility]) { if (endpoint.meta.requireFile) { - router.post(`/${endpoint.name}`, upload.single('file'), handler.bind(null, endpoint)); + router.post( + `/${endpoint.name}`, + upload.single("file"), + handler.bind(null, endpoint), + ); } else { // 後方互換性のため - if (endpoint.name.includes('-')) { - router.post(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint)); + if (endpoint.name.includes("-")) { + router.post( + `/${endpoint.name.replace(/-/g, "_")}`, + handler.bind(null, endpoint), + ); if (endpoint.meta.allowGet) { - router.get(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint)); + router.get( + `/${endpoint.name.replace(/-/g, "_")}`, + handler.bind(null, endpoint), + ); } else { - router.get(`/${endpoint.name.replace(/-/g, '_')}`, async ctx => { ctx.status = 405; }); + router.get(`/${endpoint.name.replace(/-/g, "_")}`, async (ctx) => { + ctx.status = 405; + }); } } @@ -72,33 +92,38 @@ for (const endpoint of endpoints) { if (endpoint.meta.allowGet) { router.get(`/${endpoint.name}`, handler.bind(null, endpoint)); } else { - router.get(`/${endpoint.name}`, async ctx => { ctx.status = 405; }); + router.get(`/${endpoint.name}`, async (ctx) => { + ctx.status = 405; + }); } } } -router.post('/signup', signup); -router.post('/signin', signin); -router.post('/signup-pending', signupPending); +router.post("/signup", signup); +router.post("/signin", signin); +router.post("/signup-pending", signupPending); router.use(discord.routes()); router.use(github.routes()); router.use(twitter.routes()); -router.get('/v1/instance/peers', async ctx => { +router.get("/v1/instance/peers", async (ctx) => { const instances = await Instances.find({ - select: ['host'], + select: ["host"], + where: { + isSuspended: false, + }, }); - ctx.body = instances.map(instance => instance.host); + ctx.body = instances.map((instance) => instance.host); }); -router.post('/miauth/:session/check', async ctx => { +router.post("/miauth/:session/check", async (ctx) => { const token = await AccessTokens.findOneBy({ session: ctx.params.session, }); - if (token && token.session != null && !token.fetched) { + if (token?.session != null && !token.fetched) { AccessTokens.update(token.id, { fetched: true, }); @@ -116,7 +141,7 @@ router.post('/miauth/:session/check', async ctx => { }); // Return 404 for unknown API -router.all('(.*)', async ctx => { +router.all("(.*)", async (ctx) => { ctx.status = 404; }); diff --git a/packages/backend/src/server/api/limiter.ts b/packages/backend/src/server/api/limiter.ts index 9a7751716..dd005ad13 100644 --- a/packages/backend/src/server/api/limiter.ts +++ b/packages/backend/src/server/api/limiter.ts @@ -1,77 +1,85 @@ -import Limiter from 'ratelimiter'; -import { CacheableLocalUser, User } from '@/models/entities/user.js'; -import Logger from '@/services/logger.js'; -import { redisClient } from '../../db/redis.js'; -import { IEndpointMeta } from './endpoints.js'; +import Limiter from "ratelimiter"; +import { CacheableLocalUser, User } from "@/models/entities/user.js"; +import Logger from "@/services/logger.js"; +import { redisClient } from "../../db/redis.js"; +import type { IEndpointMeta } from "./endpoints.js"; -const logger = new Logger('limiter'); +const logger = new Logger("limiter"); -export const limiter = (limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string) => new Promise((ok, reject) => { - if (process.env.NODE_ENV === 'test') ok(); +export const limiter = ( + limitation: IEndpointMeta["limit"] & { key: NonNullable }, + actor: string, +) => + new Promise((ok, reject) => { + if (process.env.NODE_ENV === "test") ok(); - const hasShortTermLimit = typeof limitation.minInterval === 'number'; + const hasShortTermLimit = typeof limitation.minInterval === "number"; - const hasLongTermLimit = - typeof limitation.duration === 'number' && - typeof limitation.max === 'number'; + const hasLongTermLimit = + typeof limitation.duration === "number" && + typeof limitation.max === "number"; - if (hasShortTermLimit) { - min(); - } else if (hasLongTermLimit) { - max(); - } else { - ok(); - } + if (hasShortTermLimit) { + min(); + } else if (hasLongTermLimit) { + max(); + } else { + ok(); + } - // Short-term limit - function min(): void { - const minIntervalLimiter = new Limiter({ - id: `${actor}:${limitation.key}:min`, - duration: limitation.minInterval, - max: 1, - db: redisClient, - }); + // Short-term limit + function min(): void { + const minIntervalLimiter = new Limiter({ + id: `${actor}:${limitation.key}:min`, + duration: limitation.minInterval, + max: 1, + db: redisClient, + }); - minIntervalLimiter.get((err, info) => { - if (err) { - return reject('ERR'); - } + minIntervalLimiter.get((err, info) => { + if (err) { + return reject("ERR"); + } - logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); + logger.debug( + `${actor} ${limitation.key} min remaining: ${info.remaining}`, + ); - if (info.remaining === 0) { - reject('BRIEF_REQUEST_INTERVAL'); - } else { - if (hasLongTermLimit) { - max(); + if (info.remaining === 0) { + reject("BRIEF_REQUEST_INTERVAL"); + } else { + if (hasLongTermLimit) { + max(); + } else { + ok(); + } + } + }); + } + + // Long term limit + function max(): void { + const limiter = new Limiter({ + id: `${actor}:${limitation.key}`, + duration: limitation.duration, + max: limitation.max, + db: redisClient, + }); + + limiter.get((err, info) => { + if (err) { + return reject("ERR"); + } + + logger.debug( + `${actor} ${limitation.key} max remaining: ${info.remaining}`, + ); + + if (info.remaining === 0) { + reject("RATE_LIMIT_EXCEEDED"); } else { ok(); } - } - }); - } - - // Long term limit - function max(): void { - const limiter = new Limiter({ - id: `${actor}:${limitation.key}`, - duration: limitation.duration, - max: limitation.max, - db: redisClient, - }); - - limiter.get((err, info) => { - if (err) { - return reject('ERR'); - } - - logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); - - if (info.remaining === 0) { - reject('RATE_LIMIT_EXCEEDED'); - } else { - ok(); - } - }); - } -}); + }); + } + }); diff --git a/packages/backend/src/server/api/logger.ts b/packages/backend/src/server/api/logger.ts index ec22d6c3e..083888ed7 100644 --- a/packages/backend/src/server/api/logger.ts +++ b/packages/backend/src/server/api/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger.js'; +import Logger from "@/services/logger.js"; -export const apiLogger = new Logger('api'); +export const apiLogger = new Logger("api"); diff --git a/packages/backend/src/server/api/openapi/errors.ts b/packages/backend/src/server/api/openapi/errors.ts index e632b4a0f..0fe229d88 100644 --- a/packages/backend/src/server/api/openapi/errors.ts +++ b/packages/backend/src/server/api/openapi/errors.ts @@ -1,67 +1,69 @@ - export const errors = { - '400': { - 'INVALID_PARAM': { + "400": { + INVALID_PARAM: { value: { error: { - message: 'Invalid param.', - code: 'INVALID_PARAM', - id: '3d81ceae-475f-4600-b2a8-2bc116157532', + message: "Invalid param.", + code: "INVALID_PARAM", + id: "3d81ceae-475f-4600-b2a8-2bc116157532", }, }, }, }, - '401': { - 'CREDENTIAL_REQUIRED': { + "401": { + CREDENTIAL_REQUIRED: { value: { error: { - message: 'Credential required.', - code: 'CREDENTIAL_REQUIRED', - id: '1384574d-a912-4b81-8601-c7b1c4085df1', + message: "Credential required.", + code: "CREDENTIAL_REQUIRED", + id: "1384574d-a912-4b81-8601-c7b1c4085df1", }, }, }, }, - '403': { - 'AUTHENTICATION_FAILED': { + "403": { + AUTHENTICATION_FAILED: { value: { error: { - message: 'Authentication failed. Please ensure your token is correct.', - code: 'AUTHENTICATION_FAILED', - id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14', + message: + "Authentication failed. Please ensure your token is correct.", + code: "AUTHENTICATION_FAILED", + id: "b0a7f5f8-dc2f-4171-b91f-de88ad238e14", }, }, }, }, - '418': { - 'I_AM_CALC': { + "418": { + I_AM_CALC: { value: { error: { - message: 'You sent a request to Calc, Calckey\'s resident stoner furry, instead of the server.', - code: 'I_AM_CALC', - id: '60c46cd1-f23a-46b1-bebe-5d2b73951a84', + message: + "You sent a request to Calc, Calckey's resident stoner furry, instead of the server.", + code: "I_AM_CALC", + id: "60c46cd1-f23a-46b1-bebe-5d2b73951a84", }, }, }, }, - '429': { - 'RATE_LIMIT_EXCEEDED': { + "429": { + RATE_LIMIT_EXCEEDED: { value: { error: { - message: 'Rate limit exceeded. Please try again later.', - code: 'RATE_LIMIT_EXCEEDED', - id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', + message: "Rate limit exceeded. Please try again later.", + code: "RATE_LIMIT_EXCEEDED", + id: "d5826d14-3982-4d2e-8011-b9e9f02499ef", }, }, }, }, - '500': { - 'INTERNAL_ERROR': { + "500": { + INTERNAL_ERROR: { value: { error: { - message: 'Internal error occurred. Please contact us if the error persists.', - code: 'INTERNAL_ERROR', - id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac', + message: + "Internal error occurred. Please contact us if the error persists.", + code: "INTERNAL_ERROR", + id: "5d37dbcb-891e-41ca-a3d6-e690c97775ac", }, }, }, diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index e49f5e8d0..dfaacf9e5 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -1,26 +1,28 @@ -import endpoints from '../endpoints.js'; -import config from '@/config/index.js'; -import { errors as basicErrors } from './errors.js'; -import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; +import endpoints from "../endpoints.js"; +import config from "@/config/index.js"; +import { errors as basicErrors } from "./errors.js"; +import { schemas, convertSchemaToOpenApiSchema } from "./schemas.js"; export function genOpenapiSpec() { const spec = { - openapi: '3.0.0', + openapi: "3.0.0", info: { - version: 'v1', - title: 'Calckey API', - 'x-logo': { url: '/static-assets/api-doc.png' }, + version: "v1", + title: "Calckey API", + "x-logo": { url: "/static-assets/api-doc.png" }, }, externalDocs: { - description: 'Repository', - url: 'https://codeberg.org/calckey/calckey', + description: "Repository", + url: "https://codeberg.org/calckey/calckey", }, - servers: [{ - url: config.apiUrl, - }], + servers: [ + { + url: config.apiUrl, + }, + ], paths: {} as any, @@ -29,20 +31,20 @@ export function genOpenapiSpec() { securitySchemes: { ApiKeyAuth: { - type: 'apiKey', - in: 'body', - name: 'i', + type: "apiKey", + in: "body", + name: "i", }, // TODO: change this to oauth2 when the remaining oauth stuff is set up Bearer: { - type: 'http', - scheme: 'bearer', - } + type: "http", + scheme: "bearer", + }, }, }, }; - for (const endpoint of endpoints.filter(ep => !ep.meta.secure)) { + for (const endpoint of endpoints.filter((ep) => !ep.meta.secure)) { const errors = {} as any; if (endpoint.meta.errors) { @@ -55,25 +57,34 @@ export function genOpenapiSpec() { } } - const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res) : {}; + const resSchema = endpoint.meta.res + ? convertSchemaToOpenApiSchema(endpoint.meta.res) + : {}; - let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n'; - desc += `**Credential required**: *${endpoint.meta.requireCredential ? 'Yes' : 'No'}*`; + let desc = + (endpoint.meta.description + ? endpoint.meta.description + : "No description provided.") + "\n\n"; + desc += `**Credential required**: *${ + endpoint.meta.requireCredential ? "Yes" : "No" + }*`; if (endpoint.meta.kind) { const kind = endpoint.meta.kind; desc += ` / **Permission**: *${kind}*`; } - const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json'; + const requestType = endpoint.meta.requireFile + ? "multipart/form-data" + : "application/json"; const schema = endpoint.params; if (endpoint.meta.requireFile) { schema.properties.file = { - type: 'string', - format: 'binary', - description: 'The file contents.', + type: "string", + format: "binary", + description: "The file contents.", }; - schema.required.push('file'); + schema.required.push("file"); } const security = [ @@ -94,7 +105,7 @@ export function genOpenapiSpec() { summary: endpoint.name, description: desc, externalDocs: { - description: 'Source code', + description: "Source code", url: `https://codeberg.org/calckey/calckey/src/branch/develop/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`, }, tags: endpoint.meta.tags || undefined, @@ -108,85 +119,89 @@ export function genOpenapiSpec() { }, }, responses: { - ...(endpoint.meta.res ? { - '200': { - description: 'OK (with results)', - content: { - 'application/json': { - schema: resSchema, - }, - }, - }, - } : { - '204': { - description: 'OK (without any results)', - }, - }), - '400': { - description: 'Client error', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/Error', - }, - examples: { ...errors, ...basicErrors['400'] }, - }, - }, - }, - '401': { - description: 'Authentication error', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/Error', - }, - examples: basicErrors['401'], - }, - }, - }, - '403': { - description: 'Forbidden error', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/Error', - }, - examples: basicErrors['403'], - }, - }, - }, - '418': { - description: 'I\'m Calc', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/Error', - }, - examples: basicErrors['418'], - }, - }, - }, - ...(endpoint.meta.limit ? { - '429': { - description: 'To many requests', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/Error', + ...(endpoint.meta.res + ? { + "200": { + description: "OK (with results)", + content: { + "application/json": { + schema: resSchema, + }, }, - examples: basicErrors['429'], }, + } + : { + "204": { + description: "OK (without any results)", + }, + }), + "400": { + description: "Client error", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Error", + }, + examples: { ...errors, ...basicErrors["400"] }, }, }, - } : {}), - '500': { - description: 'Internal server error', + }, + "401": { + description: "Authentication error", content: { - 'application/json': { + "application/json": { schema: { - $ref: '#/components/schemas/Error', + $ref: "#/components/schemas/Error", }, - examples: basicErrors['500'], + examples: basicErrors["401"], + }, + }, + }, + "403": { + description: "Forbidden error", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Error", + }, + examples: basicErrors["403"], + }, + }, + }, + "418": { + description: "I'm Calc", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Error", + }, + examples: basicErrors["418"], + }, + }, + }, + ...(endpoint.meta.limit + ? { + "429": { + description: "To many requests", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Error", + }, + examples: basicErrors["429"], + }, + }, + }, + } + : {}), + "500": { + description: "Internal server error", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Error", + }, + examples: basicErrors["500"], }, }, }, @@ -199,10 +214,12 @@ export function genOpenapiSpec() { if (endpoint.meta.allowGet) { path.get = { ...info }; // API Key authentication is not permitted for GET requests - path.get.security = path.get.security.filter(elem => !Object.prototype.hasOwnProperty.call(elem, 'ApiKeyAuth')); + path.get.security = path.get.security.filter( + (elem) => !Object.prototype.hasOwnProperty.call(elem, "ApiKeyAuth"), + ); } - spec.paths['/' + endpoint.name] = path; + spec.paths[`/${endpoint.name}`] = path; } return spec; diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index 14bef9cab..68b15d567 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -1,17 +1,20 @@ -import { refs, Schema } from '@/misc/schema.js'; +import type { Schema } from "@/misc/schema.js"; +import { refs } from "@/misc/schema.js"; export function convertSchemaToOpenApiSchema(schema: Schema) { const res: any = schema; - if (schema.type === 'object' && schema.properties) { - res.required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); + if (schema.type === "object" && schema.properties) { + res.required = Object.entries(schema.properties) + .filter(([k, v]) => !v.optional) + .map(([k]) => k); for (const k of Object.keys(schema.properties)) { res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]); } } - if (schema.type === 'array' && schema.items) { + if (schema.type === "array" && schema.items) { res.items = convertSchemaToOpenApiSchema(schema.items); } @@ -28,33 +31,36 @@ export function convertSchemaToOpenApiSchema(schema: Schema) { export const schemas = { Error: { - type: 'object', + type: "object", properties: { error: { - type: 'object', - description: 'An error object.', + type: "object", + description: "An error object.", properties: { code: { - type: 'string', - description: 'An error code. Unique within the endpoint.', + type: "string", + description: "An error code. Unique within the endpoint.", }, message: { - type: 'string', - description: 'An error message.', + type: "string", + description: "An error message.", }, id: { - type: 'string', - format: 'uuid', - description: 'An error ID. This ID is static.', + type: "string", + format: "uuid", + description: "An error ID. This ID is static.", }, }, - required: ['code', 'id', 'message'], + required: ["code", "id", "message"], }, }, - required: ['error'], + required: ["error"], }, ...Object.fromEntries( - Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema)]) + Object.entries(refs).map(([key, schema]) => [ + key, + convertSchemaToOpenApiSchema(schema), + ]), ), }; diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts index 79b31764f..b06f47ed4 100644 --- a/packages/backend/src/server/api/private/signin.ts +++ b/packages/backend/src/server/api/private/signin.ts @@ -1,25 +1,31 @@ -import Koa from 'koa'; -import bcrypt from 'bcryptjs'; -import * as speakeasy from 'speakeasy'; -import signin from '../common/signin.js'; -import config from '@/config/index.js'; -import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { genId } from '@/misc/gen-id.js'; -import { verifyLogin, hash } from '../2fa.js'; -import { randomBytes } from 'node:crypto'; -import { IsNull } from 'typeorm'; -import { limiter } from '../limiter.js'; -import { getIpHash } from '@/misc/get-ip-hash.js'; +import type Koa from "koa"; +import bcrypt from "bcryptjs"; +import * as speakeasy from "speakeasy"; +import signin from "../common/signin.js"; +import config from "@/config/index.js"; +import { + Users, + Signins, + UserProfiles, + UserSecurityKeys, + AttestationChallenges, +} from "@/models/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { genId } from "@/misc/gen-id.js"; +import { verifyLogin, hash } from "../2fa.js"; +import { randomBytes } from "node:crypto"; +import { IsNull } from "typeorm"; +import { limiter } from "../limiter.js"; +import { getIpHash } from "@/misc/get-ip-hash.js"; export default async (ctx: Koa.Context) => { - ctx.set('Access-Control-Allow-Origin', config.url); - ctx.set('Access-Control-Allow-Credentials', 'true'); + ctx.set("Access-Control-Allow-Origin", config.url); + ctx.set("Access-Control-Allow-Credentials", "true"); const body = ctx.request.body as any; - const username = body['username']; - const password = body['password']; - const token = body['token']; + const username = body["username"]; + const password = body["password"]; + const token = body["token"]; function error(status: number, error: { id: string }) { ctx.status = status; @@ -28,50 +34,53 @@ export default async (ctx: Koa.Context) => { try { // not more than 1 attempt per second and not more than 10 attempts per hour - await limiter({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(ctx.ip)); + await limiter( + { key: "signin", duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, + getIpHash(ctx.ip), + ); } catch (err) { ctx.status = 429; ctx.body = { error: { - message: 'Too many failed attempts to sign in. Try again later.', - code: 'TOO_MANY_AUTHENTICATION_FAILURES', - id: '22d05606-fbcf-421a-a2db-b32610dcfd1b', + message: "Too many failed attempts to sign in. Try again later.", + code: "TOO_MANY_AUTHENTICATION_FAILURES", + id: "22d05606-fbcf-421a-a2db-b32610dcfd1b", }, }; return; } - if (typeof username !== 'string') { + if (typeof username !== "string") { ctx.status = 400; return; } - if (typeof password !== 'string') { + if (typeof password !== "string") { ctx.status = 400; return; } - if (token != null && typeof token !== 'string') { + if (token != null && typeof token !== "string") { ctx.status = 400; return; } // Fetch user - const user = await Users.findOneBy({ + const user = (await Users.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull(), - }) as ILocalUser; + })) as ILocalUser; if (user == null) { error(404, { - id: '6cc579cc-885d-43d8-95c2-b8c7fc963280', + id: "6cc579cc-885d-43d8-95c2-b8c7fc963280", }); return; } if (user.isSuspended) { error(403, { - id: 'e03a5f46-d309-4865-9b69-56282d94e1eb', + id: "e03a5f46-d309-4865-9b69-56282d94e1eb", }); return; } @@ -92,7 +101,10 @@ export default async (ctx: Koa.Context) => { success: false, }); - error(status || 500, failure || { id: '4e30e80c-e338-45a0-8c8f-44455efa3b76' }); + error( + status || 500, + failure || { id: "4e30e80c-e338-45a0-8c8f-44455efa3b76" }, + ); } if (!profile.twoFactorEnabled) { @@ -101,7 +113,7 @@ export default async (ctx: Koa.Context) => { return; } else { await fail(403, { - id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', + id: "932c904e-9460-45b7-9ce6-7ed33be7eb2c", }); return; } @@ -110,14 +122,14 @@ export default async (ctx: Koa.Context) => { if (token) { if (!same) { await fail(403, { - id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', + id: "932c904e-9460-45b7-9ce6-7ed33be7eb2c", }); return; } const verified = (speakeasy as any).totp.verify({ secret: profile.twoFactorSecret, - encoding: 'base32', + encoding: "base32", token: token, window: 2, }); @@ -127,30 +139,30 @@ export default async (ctx: Koa.Context) => { return; } else { await fail(403, { - id: 'cdf1235b-ac71-46d4-a3a6-84ccce48df6f', + id: "cdf1235b-ac71-46d4-a3a6-84ccce48df6f", }); return; } } else if (body.credentialId) { - if (!same && !profile.usePasswordLessLogin) { + if (!(same || profile.usePasswordLessLogin)) { await fail(403, { - id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', + id: "932c904e-9460-45b7-9ce6-7ed33be7eb2c", }); return; } - const clientDataJSON = Buffer.from(body.clientDataJSON, 'hex'); - const clientData = JSON.parse(clientDataJSON.toString('utf-8')); + const clientDataJSON = Buffer.from(body.clientDataJSON, "hex"); + const clientData = JSON.parse(clientDataJSON.toString("utf-8")); const challenge = await AttestationChallenges.findOneBy({ userId: user.id, id: body.challengeId, registrationChallenge: false, - challenge: hash(clientData.challenge).toString('hex'), + challenge: hash(clientData.challenge).toString("hex"), }); if (!challenge) { await fail(403, { - id: '2715a88a-2125-4013-932f-aa6fe72792da', + id: "2715a88a-2125-4013-932f-aa6fe72792da", }); return; } @@ -162,33 +174,31 @@ export default async (ctx: Koa.Context) => { if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * 60 * 1000) { await fail(403, { - id: '2715a88a-2125-4013-932f-aa6fe72792da', + id: "2715a88a-2125-4013-932f-aa6fe72792da", }); return; } const securityKey = await UserSecurityKeys.findOneBy({ id: Buffer.from( - body.credentialId - .replace(/-/g, '+') - .replace(/_/g, '/'), - 'base64' - ).toString('hex'), + body.credentialId.replace(/-/g, "+").replace(/_/g, "/"), + "base64", + ).toString("hex"), }); if (!securityKey) { await fail(403, { - id: '66269679-aeaf-4474-862b-eb761197e046', + id: "66269679-aeaf-4474-862b-eb761197e046", }); return; } const isValid = verifyLogin({ - publicKey: Buffer.from(securityKey.publicKey, 'hex'), - authenticatorData: Buffer.from(body.authenticatorData, 'hex'), + publicKey: Buffer.from(securityKey.publicKey, "hex"), + authenticatorData: Buffer.from(body.authenticatorData, "hex"), clientDataJSON, clientData, - signature: Buffer.from(body.signature, 'hex'), + signature: Buffer.from(body.signature, "hex"), challenge: challenge.challenge, }); @@ -197,14 +207,14 @@ export default async (ctx: Koa.Context) => { return; } else { await fail(403, { - id: '93b86c4b-72f9-40eb-9815-798928603d1e', + id: "93b86c4b-72f9-40eb-9815-798928603d1e", }); return; } } else { - if (!same && !profile.usePasswordLessLogin) { + if (!(same || profile.usePasswordLessLogin)) { await fail(403, { - id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', + id: "932c904e-9460-45b7-9ce6-7ed33be7eb2c", }); return; } @@ -215,23 +225,24 @@ export default async (ctx: Koa.Context) => { if (keys.length === 0) { await fail(403, { - id: 'f27fd449-9af4-4841-9249-1f989b9fa4a4', + id: "f27fd449-9af4-4841-9249-1f989b9fa4a4", }); return; } // 32 byte challenge - const challenge = randomBytes(32).toString('base64') - .replace(/=/g, '') - .replace(/\+/g, '-') - .replace(/\//g, '_'); + const challenge = randomBytes(32) + .toString("base64") + .replace(/=/g, "") + .replace(/\+/g, "-") + .replace(/\//g, "_"); const challengeId = genId(); await AttestationChallenges.insert({ userId: user.id, id: challengeId, - challenge: hash(Buffer.from(challenge, 'utf-8')).toString('hex'), + challenge: hash(Buffer.from(challenge, "utf-8")).toString("hex"), createdAt: new Date(), registrationChallenge: false, }); @@ -239,7 +250,7 @@ export default async (ctx: Koa.Context) => { ctx.body = { challenge, challengeId, - securityKeys: keys.map(key => ({ + securityKeys: keys.map((key) => ({ id: key.id, })), }; diff --git a/packages/backend/src/server/api/private/signup-pending.ts b/packages/backend/src/server/api/private/signup-pending.ts index e5e39ba00..c7fdcea22 100644 --- a/packages/backend/src/server/api/private/signup-pending.ts +++ b/packages/backend/src/server/api/private/signup-pending.ts @@ -1,12 +1,12 @@ -import Koa from 'koa'; -import { Users, UserPendings, UserProfiles } from '@/models/index.js'; -import { signup } from '../common/signup.js'; -import signin from '../common/signin.js'; +import type Koa from "koa"; +import { Users, UserPendings, UserProfiles } from "@/models/index.js"; +import { signup } from "../common/signup.js"; +import signin from "../common/signin.js"; export default async (ctx: Koa.Context) => { const body = ctx.request.body; - const code = body['code']; + const code = body["code"]; try { const pendingUser = await UserPendings.findOneByOrFail({ code }); @@ -22,11 +22,14 @@ export default async (ctx: Koa.Context) => { const profile = await UserProfiles.findOneByOrFail({ userId: account.id }); - await UserProfiles.update({ userId: profile.userId }, { - email: pendingUser.email, - emailVerified: true, - emailVerifyCode: null, - }); + await UserProfiles.update( + { userId: profile.userId }, + { + email: pendingUser.email, + emailVerified: true, + emailVerifyCode: null, + }, + ); signin(ctx, account); } catch (e) { diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 26f172637..dc5eb2316 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -1,14 +1,14 @@ -import Koa from 'koa'; -import rndstr from 'rndstr'; -import bcrypt from 'bcryptjs'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha.js'; -import { Users, RegistrationTickets, UserPendings } from '@/models/index.js'; -import { signup } from '../common/signup.js'; -import config from '@/config/index.js'; -import { sendEmail } from '@/services/send-email.js'; -import { genId } from '@/misc/gen-id.js'; -import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; +import type Koa from "koa"; +import rndstr from "rndstr"; +import bcrypt from "bcryptjs"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { verifyHcaptcha, verifyRecaptcha } from "@/misc/captcha.js"; +import { Users, RegistrationTickets, UserPendings } from "@/models/index.js"; +import { signup } from "../common/signup.js"; +import config from "@/config/index.js"; +import { sendEmail } from "@/services/send-email.js"; +import { genId } from "@/misc/gen-id.js"; +import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; export default async (ctx: Koa.Context) => { const body = ctx.request.body; @@ -17,28 +17,35 @@ export default async (ctx: Koa.Context) => { // Verify *Captcha // ただしテスト時はこの機構は障害となるため無効にする - if (process.env.NODE_ENV !== 'test') { + if (process.env.NODE_ENV !== "test") { if (instance.enableHcaptcha && instance.hcaptchaSecretKey) { - await verifyHcaptcha(instance.hcaptchaSecretKey, body['hcaptcha-response']).catch(e => { + await verifyHcaptcha( + instance.hcaptchaSecretKey, + body["hcaptcha-response"], + ).catch((e) => { ctx.throw(400, e); }); } if (instance.enableRecaptcha && instance.recaptchaSecretKey) { - await verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(e => { + await verifyRecaptcha( + instance.recaptchaSecretKey, + body["g-recaptcha-response"], + ).catch((e) => { ctx.throw(400, e); }); } } - const username = body['username']; - const password = body['password']; - const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null; - const invitationCode = body['invitationCode']; - const emailAddress = body['emailAddress']; + const username = body["username"]; + const password = body["password"]; + const host: string | null = + process.env.NODE_ENV === "test" ? body["host"] || null : null; + const invitationCode = body["invitationCode"]; + const emailAddress = body["emailAddress"]; if (instance.emailRequiredForSignup) { - if (emailAddress == null || typeof emailAddress !== 'string') { + if (emailAddress == null || typeof emailAddress !== "string") { ctx.status = 400; return; } @@ -51,7 +58,7 @@ export default async (ctx: Koa.Context) => { } if (instance.disableRegistration) { - if (invitationCode == null || typeof invitationCode !== 'string') { + if (invitationCode == null || typeof invitationCode !== "string") { ctx.status = 400; return; } @@ -69,7 +76,7 @@ export default async (ctx: Koa.Context) => { } if (instance.emailRequiredForSignup) { - const code = rndstr('a-z0-9', 16); + const code = rndstr("a-z0-9", 16); // Generate hash of password const salt = await bcrypt.genSalt(8); @@ -86,15 +93,20 @@ export default async (ctx: Koa.Context) => { const link = `${config.url}/signup-complete/${code}`; - sendEmail(emailAddress, 'Signup', + sendEmail( + emailAddress, + "Signup", `To complete signup, please click this link:
${link}`, - `To complete signup, please click this link: ${link}`); + `To complete signup, please click this link: ${link}`, + ); ctx.status = 204; } else { try { const { account, secret } = await signup({ - username, password, host, + username, + password, + host, }); const res = await Users.pack(account, account, { diff --git a/packages/backend/src/server/api/service/discord.ts b/packages/backend/src/server/api/service/discord.ts index 97cbcbecd..9906d2f7c 100644 --- a/packages/backend/src/server/api/service/discord.ts +++ b/packages/backend/src/server/api/service/discord.ts @@ -1,43 +1,43 @@ -import Koa from 'koa'; -import Router from '@koa/router'; -import { OAuth2 } from 'oauth'; -import { v4 as uuid } from 'uuid'; -import { IsNull } from 'typeorm'; -import { getJson } from '@/misc/fetch.js'; -import config from '@/config/index.js'; -import { publishMainStream } from '@/services/stream.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Users, UserProfiles } from '@/models/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { redisClient } from '../../../db/redis.js'; -import signin from '../common/signin.js'; +import type Koa from "koa"; +import Router from "@koa/router"; +import { OAuth2 } from "oauth"; +import { v4 as uuid } from "uuid"; +import { IsNull } from "typeorm"; +import { getJson } from "@/misc/fetch.js"; +import config from "@/config/index.js"; +import { publishMainStream } from "@/services/stream.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Users, UserProfiles } from "@/models/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { redisClient } from "../../../db/redis.js"; +import signin from "../common/signin.js"; function getUserToken(ctx: Koa.BaseContext): string | null { - return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; + return ((ctx.headers["cookie"] || "").match(/igi=(\w+)/) || [null, null])[1]; } function compareOrigin(ctx: Koa.BaseContext): boolean { function normalizeUrl(url?: string): string { - return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; + return url ? (url.endsWith("/") ? url.substr(0, url.length - 1) : url) : ""; } - const referer = ctx.headers['referer']; + const referer = ctx.headers["referer"]; - return (normalizeUrl(referer) === normalizeUrl(config.url)); + return normalizeUrl(referer) === normalizeUrl(config.url); } // Init router const router = new Router(); -router.get('/disconnect/discord', async ctx => { +router.get("/disconnect/discord", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (!userToken) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } @@ -48,19 +48,23 @@ router.get('/disconnect/discord', async ctx => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - delete profile.integrations.discord; + profile.integrations.discord = undefined; await UserProfiles.update(user.id, { integrations: profile.integrations, }); - ctx.body = 'Discordの連携を解除しました :v:'; + ctx.body = "Discordの連携を解除しました :v:"; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); }); async function getOAuth2() { @@ -70,31 +74,32 @@ async function getOAuth2() { return new OAuth2( meta.discordClientId!, meta.discordClientSecret!, - 'https://discord.com/', - 'api/oauth2/authorize', - 'api/oauth2/token'); + "https://discord.com/", + "api/oauth2/authorize", + "api/oauth2/token", + ); } else { return null; } } -router.get('/connect/discord', async ctx => { +router.get("/connect/discord", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (!userToken) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } const params = { redirect_uri: `${config.url}/api/dc/cb`, - scope: ['identify'], + scope: ["identify"], state: uuid(), - response_type: 'code', + response_type: "code", }; redisClient.set(userToken, JSON.stringify(params)); @@ -103,19 +108,19 @@ router.get('/connect/discord', async ctx => { ctx.redirect(oauth2!.getAuthorizeUrl(params)); }); -router.get('/signin/discord', async ctx => { +router.get("/signin/discord", async (ctx) => { const sessid = uuid(); const params = { redirect_uri: `${config.url}/api/dc/cb`, - scope: ['identify'], + scope: ["identify"], state: uuid(), - response_type: 'code', + response_type: "code", }; - ctx.cookies.set('signin_with_discord_sid', sessid, { - path: '/', - secure: config.url.startsWith('https'), + ctx.cookies.set("signin_with_discord_sid", sessid, { + path: "/", + secure: config.url.startsWith("https"), httpOnly: true, }); @@ -125,23 +130,23 @@ router.get('/signin/discord', async ctx => { ctx.redirect(oauth2!.getAuthorizeUrl(params)); }); -router.get('/dc/cb', async ctx => { +router.get("/dc/cb", async (ctx) => { const userToken = getUserToken(ctx); const oauth2 = await getOAuth2(); if (!userToken) { - const sessid = ctx.cookies.get('signin_with_discord_sid'); + const sessid = ctx.cookies.get("signin_with_discord_sid"); if (!sessid) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } const code = ctx.query.code; - if (!code || typeof code !== 'string') { - ctx.throw(400, 'invalid session'); + if (!code || typeof code !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -152,44 +157,62 @@ router.get('/dc/cb', async ctx => { }); if (ctx.query.state !== state) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } - const { accessToken, refreshToken, expiresDate } = await new Promise((res, rej) => - oauth2!.getOAuthAccessToken(code, { - grant_type: 'authorization_code', - redirect_uri, - }, (err, accessToken, refreshToken, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ - accessToken, - refreshToken, - expiresDate: Date.now() + Number(result.expires_in) * 1000, - }); - } - })); + const { accessToken, refreshToken, expiresDate } = await new Promise( + (res, rej) => + oauth2!.getOAuthAccessToken( + code, + { + grant_type: "authorization_code", + redirect_uri, + }, + (err, accessToken, refreshToken, result) => { + if (err) { + rej(err); + } else if (result.error) { + rej(result.error); + } else { + res({ + accessToken, + refreshToken, + expiresDate: Date.now() + Number(result.expires_in) * 1000, + }); + } + }, + ), + ); - const { id, username, discriminator } = (await getJson('https://discord.com/api/users/@me', '*/*', 10 * 1000, { - 'Authorization': `Bearer ${accessToken}`, - })) as Record; + const { id, username, discriminator } = (await getJson( + "https://discord.com/api/users/@me", + "*/*", + 10 * 1000, + { + Authorization: `Bearer ${accessToken}`, + }, + )) as Record; - if (typeof id !== 'string' || typeof username !== 'string' || typeof discriminator !== 'string') { - ctx.throw(400, 'invalid session'); + if ( + typeof id !== "string" || + typeof username !== "string" || + typeof discriminator !== "string" + ) { + ctx.throw(400, "invalid session"); return; } const profile = await UserProfiles.createQueryBuilder() - .where('"integrations"->\'discord\'->>\'id\' = :id', { id: id }) + .where("\"integrations\"->'discord'->>'id' = :id", { id: id }) .andWhere('"userHost" IS NULL') .getOne(); if (profile == null) { - ctx.throw(404, `@${username}#${discriminator}と連携しているMisskeyアカウントはありませんでした...`); + ctx.throw( + 404, + `@${username}#${discriminator}と連携しているMisskeyアカウントはありませんでした...`, + ); return; } @@ -207,12 +230,16 @@ router.get('/dc/cb', async ctx => { }, }); - signin(ctx, await Users.findOneBy({ id: profile.userId }) as ILocalUser, true); + signin( + ctx, + (await Users.findOneBy({ id: profile.userId })) as ILocalUser, + true, + ); } else { const code = ctx.query.code; - if (!code || typeof code !== 'string') { - ctx.throw(400, 'invalid session'); + if (!code || typeof code !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -223,33 +250,48 @@ router.get('/dc/cb', async ctx => { }); if (ctx.query.state !== state) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } - const { accessToken, refreshToken, expiresDate } = await new Promise((res, rej) => - oauth2!.getOAuthAccessToken(code, { - grant_type: 'authorization_code', - redirect_uri, - }, (err, accessToken, refreshToken, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ - accessToken, - refreshToken, - expiresDate: Date.now() + Number(result.expires_in) * 1000, - }); - } - })); + const { accessToken, refreshToken, expiresDate } = await new Promise( + (res, rej) => + oauth2!.getOAuthAccessToken( + code, + { + grant_type: "authorization_code", + redirect_uri, + }, + (err, accessToken, refreshToken, result) => { + if (err) { + rej(err); + } else if (result.error) { + rej(result.error); + } else { + res({ + accessToken, + refreshToken, + expiresDate: Date.now() + Number(result.expires_in) * 1000, + }); + } + }, + ), + ); - const { id, username, discriminator } = (await getJson('https://discord.com/api/users/@me', '*/*', 10 * 1000, { - 'Authorization': `Bearer ${accessToken}`, - })) as Record; - if (typeof id !== 'string' || typeof username !== 'string' || typeof discriminator !== 'string') { - ctx.throw(400, 'invalid session'); + const { id, username, discriminator } = (await getJson( + "https://discord.com/api/users/@me", + "*/*", + 10 * 1000, + { + Authorization: `Bearer ${accessToken}`, + }, + )) as Record; + if ( + typeof id !== "string" || + typeof username !== "string" || + typeof discriminator !== "string" + ) { + ctx.throw(400, "invalid session"); return; } @@ -277,10 +319,14 @@ router.get('/dc/cb', async ctx => { ctx.body = `Discord: @${username}#${discriminator} を、Misskey: @${user.username} に接続しました!`; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); } }); diff --git a/packages/backend/src/server/api/service/github.ts b/packages/backend/src/server/api/service/github.ts index 04dbd1f7a..f77c5f795 100644 --- a/packages/backend/src/server/api/service/github.ts +++ b/packages/backend/src/server/api/service/github.ts @@ -1,43 +1,43 @@ -import Koa from 'koa'; -import Router from '@koa/router'; -import { OAuth2 } from 'oauth'; -import { v4 as uuid } from 'uuid'; -import { IsNull } from 'typeorm'; -import { getJson } from '@/misc/fetch.js'; -import config from '@/config/index.js'; -import { publishMainStream } from '@/services/stream.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Users, UserProfiles } from '@/models/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { redisClient } from '../../../db/redis.js'; -import signin from '../common/signin.js'; +import type Koa from "koa"; +import Router from "@koa/router"; +import { OAuth2 } from "oauth"; +import { v4 as uuid } from "uuid"; +import { IsNull } from "typeorm"; +import { getJson } from "@/misc/fetch.js"; +import config from "@/config/index.js"; +import { publishMainStream } from "@/services/stream.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Users, UserProfiles } from "@/models/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { redisClient } from "../../../db/redis.js"; +import signin from "../common/signin.js"; function getUserToken(ctx: Koa.BaseContext): string | null { - return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; + return ((ctx.headers["cookie"] || "").match(/igi=(\w+)/) || [null, null])[1]; } function compareOrigin(ctx: Koa.BaseContext): boolean { function normalizeUrl(url?: string): string { - return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; + return url ? (url.endsWith("/") ? url.substr(0, url.length - 1) : url) : ""; } - const referer = ctx.headers['referer']; + const referer = ctx.headers["referer"]; - return (normalizeUrl(referer) === normalizeUrl(config.url)); + return normalizeUrl(referer) === normalizeUrl(config.url); } // Init router const router = new Router(); -router.get('/disconnect/github', async ctx => { +router.get("/disconnect/github", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (!userToken) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } @@ -48,51 +48,60 @@ router.get('/disconnect/github', async ctx => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - delete profile.integrations.github; + profile.integrations.github = undefined; await UserProfiles.update(user.id, { integrations: profile.integrations, }); - ctx.body = 'GitHubの連携を解除しました :v:'; + ctx.body = "GitHubの連携を解除しました :v:"; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); }); async function getOath2() { const meta = await fetchMeta(true); - if (meta.enableGithubIntegration && meta.githubClientId && meta.githubClientSecret) { + if ( + meta.enableGithubIntegration && + meta.githubClientId && + meta.githubClientSecret + ) { return new OAuth2( meta.githubClientId, meta.githubClientSecret, - 'https://github.com/', - 'login/oauth/authorize', - 'login/oauth/access_token'); + "https://github.com/", + "login/oauth/authorize", + "login/oauth/access_token", + ); } else { return null; } } -router.get('/connect/github', async ctx => { +router.get("/connect/github", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (!userToken) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } const params = { redirect_uri: `${config.url}/api/gh/cb`, - scope: ['read:user'], + scope: ["read:user"], state: uuid(), }; @@ -102,18 +111,18 @@ router.get('/connect/github', async ctx => { ctx.redirect(oauth2!.getAuthorizeUrl(params)); }); -router.get('/signin/github', async ctx => { +router.get("/signin/github", async (ctx) => { const sessid = uuid(); const params = { redirect_uri: `${config.url}/api/gh/cb`, - scope: ['read:user'], + scope: ["read:user"], state: uuid(), }; - ctx.cookies.set('signin_with_github_sid', sessid, { - path: '/', - secure: config.url.startsWith('https'), + ctx.cookies.set("signin_with_github_sid", sessid, { + path: "/", + secure: config.url.startsWith("https"), httpOnly: true, }); @@ -123,23 +132,23 @@ router.get('/signin/github', async ctx => { ctx.redirect(oauth2!.getAuthorizeUrl(params)); }); -router.get('/gh/cb', async ctx => { +router.get("/gh/cb", async (ctx) => { const userToken = getUserToken(ctx); const oauth2 = await getOath2(); if (!userToken) { - const sessid = ctx.cookies.get('signin_with_github_sid'); + const sessid = ctx.cookies.get("signin_with_github_sid"); if (!sessid) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } const code = ctx.query.code; - if (!code || typeof code !== 'string') { - ctx.throw(400, 'invalid session'); + if (!code || typeof code !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -150,47 +159,64 @@ router.get('/gh/cb', async ctx => { }); if (ctx.query.state !== state) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } const { accessToken } = await new Promise((res, rej) => - oauth2!.getOAuthAccessToken(code, { - redirect_uri, - }, (err, accessToken, refresh, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ accessToken }); - } - })); + oauth2!.getOAuthAccessToken( + code, + { + redirect_uri, + }, + (err, accessToken, refresh, result) => { + if (err) { + rej(err); + } else if (result.error) { + rej(result.error); + } else { + res({ accessToken }); + } + }, + ), + ); - const { login, id } = (await getJson('https://api.github.com/user', 'application/vnd.github.v3+json', 10 * 1000, { - 'Authorization': `bearer ${accessToken}`, - })) as Record; - if (typeof login !== 'string' || typeof id !== 'string') { - ctx.throw(400, 'invalid session'); + const { login, id } = (await getJson( + "https://api.github.com/user", + "application/vnd.github.v3+json", + 10 * 1000, + { + Authorization: `bearer ${accessToken}`, + }, + )) as Record; + if (typeof login !== "string" || typeof id !== "string") { + ctx.throw(400, "invalid session"); return; } const link = await UserProfiles.createQueryBuilder() - .where('"integrations"->\'github\'->>\'id\' = :id', { id: id }) + .where("\"integrations\"->'github'->>'id' = :id", { id: id }) .andWhere('"userHost" IS NULL') .getOne(); if (link == null) { - ctx.throw(404, `@${login}と連携しているMisskeyアカウントはありませんでした...`); + ctx.throw( + 404, + `@${login}と連携しているMisskeyアカウントはありませんでした...`, + ); return; } - signin(ctx, await Users.findOneBy({ id: link.userId }) as ILocalUser, true); + signin( + ctx, + (await Users.findOneBy({ id: link.userId })) as ILocalUser, + true, + ); } else { const code = ctx.query.code; - if (!code || typeof code !== 'string') { - ctx.throw(400, 'invalid session'); + if (!code || typeof code !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -201,7 +227,7 @@ router.get('/gh/cb', async ctx => { }); if (ctx.query.state !== state) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } @@ -217,14 +243,21 @@ router.get('/gh/cb', async ctx => { } else { res({ accessToken }); } - })); + }, + ), + ); - const { login, id } = (await getJson('https://api.github.com/user', 'application/vnd.github.v3+json', 10 * 1000, { - 'Authorization': `bearer ${accessToken}`, - })) as Record; + const { login, id } = (await getJson( + "https://api.github.com/user", + "application/vnd.github.v3+json", + 10 * 1000, + { + Authorization: `bearer ${accessToken}`, + }, + )) as Record; - if (typeof login !== 'string' || typeof id !== 'string') { - ctx.throw(400, 'invalid session'); + if (typeof login !== "string" || typeof id !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -249,10 +282,14 @@ router.get('/gh/cb', async ctx => { ctx.body = `GitHub: @${login} を、Misskey: @${user.username} に接続しました!`; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); } }); diff --git a/packages/backend/src/server/api/service/twitter.ts b/packages/backend/src/server/api/service/twitter.ts index 2b4f9f6da..369559241 100644 --- a/packages/backend/src/server/api/service/twitter.ts +++ b/packages/backend/src/server/api/service/twitter.ts @@ -1,42 +1,46 @@ -import Koa from 'koa'; -import Router from '@koa/router'; -import { v4 as uuid } from 'uuid'; -import autwh from 'autwh'; -import { IsNull } from 'typeorm'; -import { publishMainStream } from '@/services/stream.js'; -import config from '@/config/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Users, UserProfiles } from '@/models/index.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import signin from '../common/signin.js'; -import { redisClient } from '../../../db/redis.js'; +import type Koa from "koa"; +import Router from "@koa/router"; +import { v4 as uuid } from "uuid"; +import autwh from "autwh"; +import { IsNull } from "typeorm"; +import { publishMainStream } from "@/services/stream.js"; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Users, UserProfiles } from "@/models/index.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import signin from "../common/signin.js"; +import { redisClient } from "../../../db/redis.js"; function getUserToken(ctx: Koa.BaseContext): string | null { - return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; + return ((ctx.headers["cookie"] || "").match(/igi=(\w+)/) || [null, null])[1]; } function compareOrigin(ctx: Koa.BaseContext): boolean { function normalizeUrl(url?: string): string { - return url == null ? '' : url.endsWith('/') ? url.substr(0, url.length - 1) : url; + return url == null + ? "" + : url.endsWith("/") + ? url.substr(0, url.length - 1) + : url; } - const referer = ctx.headers['referer']; + const referer = ctx.headers["referer"]; - return (normalizeUrl(referer) === normalizeUrl(config.url)); + return normalizeUrl(referer) === normalizeUrl(config.url); } // Init router const router = new Router(); -router.get('/disconnect/twitter', async ctx => { +router.get("/disconnect/twitter", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (userToken == null) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } @@ -47,25 +51,33 @@ router.get('/disconnect/twitter', async ctx => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - delete profile.integrations.twitter; + profile.integrations.twitter = undefined; await UserProfiles.update(user.id, { integrations: profile.integrations, }); - ctx.body = 'Twitterの連携を解除しました :v:'; + ctx.body = "Twitterの連携を解除しました :v:"; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); }); async function getTwAuth() { const meta = await fetchMeta(true); - if (meta.enableTwitterIntegration && meta.twitterConsumerKey && meta.twitterConsumerSecret) { + if ( + meta.enableTwitterIntegration && + meta.twitterConsumerKey && + meta.twitterConsumerSecret + ) { return autwh({ consumerKey: meta.twitterConsumerKey, consumerSecret: meta.twitterConsumerSecret, @@ -76,15 +88,15 @@ async function getTwAuth() { } } -router.get('/connect/twitter', async ctx => { +router.get("/connect/twitter", async (ctx) => { if (!compareOrigin(ctx)) { - ctx.throw(400, 'invalid origin'); + ctx.throw(400, "invalid origin"); return; } const userToken = getUserToken(ctx); if (userToken == null) { - ctx.throw(400, 'signin required'); + ctx.throw(400, "signin required"); return; } @@ -94,7 +106,7 @@ router.get('/connect/twitter', async ctx => { ctx.redirect(twCtx.url); }); -router.get('/signin/twitter', async ctx => { +router.get("/signin/twitter", async (ctx) => { const twAuth = await getTwAuth(); const twCtx = await twAuth!.begin(); @@ -102,25 +114,25 @@ router.get('/signin/twitter', async ctx => { redisClient.set(sessid, JSON.stringify(twCtx)); - ctx.cookies.set('signin_with_twitter_sid', sessid, { - path: '/', - secure: config.url.startsWith('https'), + ctx.cookies.set("signin_with_twitter_sid", sessid, { + path: "/", + secure: config.url.startsWith("https"), httpOnly: true, }); ctx.redirect(twCtx.url); }); -router.get('/tw/cb', async ctx => { +router.get("/tw/cb", async (ctx) => { const userToken = getUserToken(ctx); const twAuth = await getTwAuth(); if (userToken == null) { - const sessid = ctx.cookies.get('signin_with_twitter_sid'); + const sessid = ctx.cookies.get("signin_with_twitter_sid"); if (sessid == null) { - ctx.throw(400, 'invalid session'); + ctx.throw(400, "invalid session"); return; } @@ -133,29 +145,38 @@ router.get('/tw/cb', async ctx => { const twCtx = await get; const verifier = ctx.query.oauth_verifier; - if (!verifier || typeof verifier !== 'string') { - ctx.throw(400, 'invalid session'); + if (!verifier || typeof verifier !== "string") { + ctx.throw(400, "invalid session"); return; } const result = await twAuth!.done(JSON.parse(twCtx), verifier); const link = await UserProfiles.createQueryBuilder() - .where('"integrations"->\'twitter\'->>\'userId\' = :id', { id: result.userId }) + .where("\"integrations\"->'twitter'->>'userId' = :id", { + id: result.userId, + }) .andWhere('"userHost" IS NULL') .getOne(); if (link == null) { - ctx.throw(404, `@${result.screenName}と連携しているMisskeyアカウントはありませんでした...`); + ctx.throw( + 404, + `@${result.screenName}と連携しているMisskeyアカウントはありませんでした...`, + ); return; } - signin(ctx, await Users.findOneBy({ id: link.userId }) as ILocalUser, true); + signin( + ctx, + (await Users.findOneBy({ id: link.userId })) as ILocalUser, + true, + ); } else { const verifier = ctx.query.oauth_verifier; - if (!verifier || typeof verifier !== 'string') { - ctx.throw(400, 'invalid session'); + if (!verifier || typeof verifier !== "string") { + ctx.throw(400, "invalid session"); return; } @@ -191,10 +212,14 @@ router.get('/tw/cb', async ctx => { ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`; // Publish i updated event - publishMainStream(user.id, 'meUpdated', await Users.pack(user, user, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + user.id, + "meUpdated", + await Users.pack(user, user, { + detail: true, + includeSecrets: true, + }), + ); } }); diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index c9cffd2d3..93dbdc426 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -1,8 +1,8 @@ -import Connection from '.'; -import { Note } from '@/models/entities/note.js'; -import { Notes } from '@/models/index.js'; -import { Packed } from '@/misc/schema.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import type Connection from "."; +import type { Note } from "@/models/entities/note.js"; +import { Notes } from "@/models/index.js"; +import type { Packed } from "@/misc/schema.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; /** * Stream channel @@ -51,30 +51,35 @@ export default abstract class Channel { const type = payload === undefined ? typeOrPayload.type : typeOrPayload; const body = payload === undefined ? typeOrPayload.body : payload; - this.connection.sendMessageToWs('channel', { + this.connection.sendMessageToWs("channel", { id: this.id, type: type, body: body, }); } - protected withPackedNote(callback: (note: Packed<'Note'>) => void): (Note) => void { + protected withPackedNote( + callback: (note: Packed<"Note">) => void, + ): (Note) => void { return async (note: Note) => { try { // because `note` was previously JSON.stringify'ed, the fields that // were objects before are now strings and have to be restored or // removed from the object note.createdAt = new Date(note.createdAt); - delete note.reply; - delete note.renote; - delete note.user; - delete note.channel; + note.reply = undefined; + note.renote = undefined; + note.user = undefined; + note.channel = undefined; const packed = await Notes.pack(note, this.user, { detail: true }); callback(packed); } catch (err) { - if (err instanceof IdentifiableError && err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') { + if ( + err instanceof IdentifiableError && + err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24" + ) { // skip: note not visible to user return; } else { diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts index 945182ea1..59ae22825 100644 --- a/packages/backend/src/server/api/stream/channels/admin.ts +++ b/packages/backend/src/server/api/stream/channels/admin.ts @@ -1,13 +1,13 @@ -import Channel from '../channel.js'; +import Channel from "../channel.js"; export default class extends Channel { - public readonly chName = 'admin'; + public readonly chName = "admin"; public static shouldShare = true; public static requireCredential = true; public async init(params: any) { // Subscribe admin stream - this.subscriber.on(`adminStream:${this.user!.id}`, data => { + this.subscriber.on(`adminStream:${this.user!.id}`, (data) => { this.send(data); }); } diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index a9a98e904..8e0d08110 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -1,16 +1,16 @@ -import Channel from '../channel.js'; -import { Notes } from '@/models/index.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { StreamMessages } from '../types.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import Channel from "../channel.js"; +import { Notes } from "@/models/index.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { StreamMessages } from "../types.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; export default class extends Channel { - public readonly chName = 'antenna'; + public readonly chName = "antenna"; public static shouldShare = false; public static requireCredential = false; private antennaId: string; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onEvent = this.onEvent.bind(this); } @@ -22,10 +22,12 @@ export default class extends Channel { this.subscriber.on(`antennaStream:${this.antennaId}`, this.onEvent); } - private async onEvent(data: StreamMessages['antenna']['payload']) { - if (data.type === 'note') { + private async onEvent(data: StreamMessages["antenna"]["payload"]) { + if (data.type === "note") { try { - const note = await Notes.pack(data.body.id, this.user, { detail: true }); + const note = await Notes.pack(data.body.id, this.user, { + detail: true, + }); // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; @@ -34,9 +36,12 @@ export default class extends Channel { this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } catch (e) { - if (e instanceof IdentifiableError && e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') { + if ( + e instanceof IdentifiableError && + e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24" + ) { // skip: note not visible to user return; } else { diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 7ed47c389..841c84af8 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -1,19 +1,19 @@ -import Channel from '../channel.js'; -import { Users } from '@/models/index.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { User } from '@/models/entities/user.js'; -import { StreamMessages } from '../types.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { Users } from "@/models/index.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { User } from "@/models/entities/user.js"; +import type { StreamMessages } from "../types.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'channel'; + public readonly chName = "channel"; public static shouldShare = false; public static requireCredential = false; private channelId: string; - private typers: Record = {}; + private typers: Record = {}; private emitTypersIntervalId: ReturnType; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.onNote.bind(this); this.emitTypers = this.emitTypers.bind(this); @@ -23,12 +23,12 @@ export default class extends Channel { this.channelId = params.channelId as string; // Subscribe stream - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); this.subscriber.on(`channelStream:${this.channelId}`, this.onEvent); this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { if (note.channelId !== this.channelId) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -38,11 +38,11 @@ export default class extends Channel { this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } - private onEvent(data: StreamMessages['channel']['payload']) { - if (data.type === 'typing') { + private onEvent(data: StreamMessages["channel"]["payload"]) { + if (data.type === "typing") { const id = data.body; const begin = this.typers[id] == null; this.typers[id] = new Date(); @@ -57,20 +57,23 @@ export default class extends Channel { // Remove not typing users for (const [userId, date] of Object.entries(this.typers)) { - if (now.getTime() - date.getTime() > 5000) delete this.typers[userId]; + if (now.getTime() - date.getTime() > 5000) + this.typers[userId] = undefined; } - const users = await Users.packMany(Object.keys(this.typers), null, { detail: false }); + const users = await Users.packMany(Object.keys(this.typers), null, { + detail: false, + }); this.send({ - type: 'typers', + type: "typers", body: users, }); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); this.subscriber.off(`channelStream:${this.channelId}`, this.onEvent); clearInterval(this.emitTypersIntervalId); diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts index 140255acd..275730eae 100644 --- a/packages/backend/src/server/api/stream/channels/drive.ts +++ b/packages/backend/src/server/api/stream/channels/drive.ts @@ -1,13 +1,13 @@ -import Channel from '../channel.js'; +import Channel from "../channel.js"; export default class extends Channel { - public readonly chName = 'drive'; + public readonly chName = "drive"; public static shouldShare = true; public static requireCredential = true; public async init(params: any) { // Subscribe drive stream - this.subscriber.on(`driveStream:${this.user!.id}`, data => { + this.subscriber.on(`driveStream:${this.user!.id}`, (data) => { this.send(data); }); } diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 391851ecd..bea201088 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,16 +1,16 @@ -import Channel from '../channel.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { isInstanceMuted } from '@/misc/is-instance-muted.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { isInstanceMuted } from "@/misc/is-instance-muted.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'globalTimeline'; + public readonly chName = "globalTimeline"; public static shouldShare = true; public static requireCredential = false; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } @@ -18,26 +18,38 @@ export default class extends Channel { public async init(params: any) { const meta = await fetchMeta(); if (meta.disableGlobalTimeline) { - if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return; + if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) + return; } // Subscribe events - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { - if (note.visibility !== 'public') return; + private async onNote(note: Packed<"Note">) { + if (note.visibility !== "public") return; if (note.channelId != null) return; // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if ( + reply.userId !== this.user!.id && + note.userId !== this.user!.id && + reply.userId !== note.userId + ) + return; } // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; + if ( + isInstanceMuted( + note, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; @@ -49,15 +61,19 @@ export default class extends Channel { // 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる - if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + if ( + this.userProfile && + (await checkWordMute(note, this.user, this.userProfile.mutedWords)) + ) + return; this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index f9f7ae410..9d7b518d9 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -1,15 +1,15 @@ -import Channel from '../channel.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'hashtag'; + public readonly chName = "hashtag"; public static shouldShare = false; public static requireCredential = false; private q: string[][]; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } @@ -20,12 +20,16 @@ export default class extends Channel { if (this.q == null) return; // Subscribe stream - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { - const noteTags = note.tags ? note.tags.map((t: string) => t.toLowerCase()) : []; - const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag)))); + private async onNote(note: Packed<"Note">) { + const noteTags = note.tags + ? note.tags.map((t: string) => t.toLowerCase()) + : []; + const matched = this.q.some((tags) => + tags.every((tag) => noteTags.includes(normalizeForSearch(tag))), + ); if (!matched) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -35,11 +39,11 @@ export default class extends Channel { this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 9f5188547..47d773638 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -1,40 +1,52 @@ -import Channel from '../channel.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { isInstanceMuted } from '@/misc/is-instance-muted.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import { isInstanceMuted } from "@/misc/is-instance-muted.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'homeTimeline'; + public readonly chName = "homeTimeline"; public static shouldShare = true; public static requireCredential = true; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { // Subscribe events - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { if (note.channelId) { if (!this.followingChannels.has(note.channelId)) return; } else { // その投稿のユーザーをフォローしていなかったら弾く - if ((this.user!.id !== note.userId) && !this.following.has(note.userId)) return; + if (this.user!.id !== note.userId && !this.following.has(note.userId)) + return; } // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; + if ( + isInstanceMuted( + note, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if ( + reply.userId !== this.user!.id && + note.userId !== this.user!.id && + reply.userId !== note.userId + ) + return; } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -47,15 +59,19 @@ export default class extends Channel { // 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる - if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + if ( + this.userProfile && + (await checkWordMute(note, this.user, this.userProfile.mutedWords)) + ) + return; this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index e73136b8e..398127c40 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,48 +1,69 @@ -import Channel from '../channel.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { isInstanceMuted } from '@/misc/is-instance-muted.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import { isInstanceMuted } from "@/misc/is-instance-muted.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'hybridTimeline'; + public readonly chName = "hybridTimeline"; public static shouldShare = true; public static requireCredential = true; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { const meta = await fetchMeta(); - if (meta.disableLocalTimeline && !this.user!.isAdmin && !this.user!.isModerator) return; + if ( + meta.disableLocalTimeline && + !this.user!.isAdmin && + !this.user!.isModerator + ) + return; // Subscribe events - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { // チャンネルの投稿ではなく、自分自身の投稿 または // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または // チャンネルの投稿ではなく、全体公開のローカルの投稿 または // フォローしているチャンネルの投稿 の場合だけ - if (!( - (note.channelId == null && this.user!.id === note.userId) || - (note.channelId == null && this.following.has(note.userId)) || - (note.channelId == null && (note.user.host == null && note.visibility === 'public')) || - (note.channelId != null && this.followingChannels.has(note.channelId)) - )) return; + if ( + !( + (note.channelId == null && this.user!.id === note.userId) || + (note.channelId == null && this.following.has(note.userId)) || + (note.channelId == null && + note.user.host == null && + note.visibility === "public") || + (note.channelId != null && this.followingChannels.has(note.channelId)) + ) + ) + return; // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; + if ( + isInstanceMuted( + note, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if ( + reply.userId !== this.user!.id && + note.userId !== this.user!.id && + reply.userId !== note.userId + ) + return; } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -55,15 +76,19 @@ export default class extends Channel { // 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる - if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + if ( + this.userProfile && + (await checkWordMute(note, this.user, this.userProfile.mutedWords)) + ) + return; this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/index.ts b/packages/backend/src/server/api/stream/channels/index.ts index 926b0d4e4..d1127be47 100644 --- a/packages/backend/src/server/api/stream/channels/index.ts +++ b/packages/backend/src/server/api/stream/channels/index.ts @@ -1,19 +1,19 @@ -import main from './main.js'; -import homeTimeline from './home-timeline.js'; -import localTimeline from './local-timeline.js'; -import hybridTimeline from './hybrid-timeline.js'; -import recommendedTimeline from './recommended-timeline.js'; -import globalTimeline from './global-timeline.js'; -import serverStats from './server-stats.js'; -import queueStats from './queue-stats.js'; -import userList from './user-list.js'; -import antenna from './antenna.js'; -import messaging from './messaging.js'; -import messagingIndex from './messaging-index.js'; -import drive from './drive.js'; -import hashtag from './hashtag.js'; -import channel from './channel.js'; -import admin from './admin.js'; +import main from "./main.js"; +import homeTimeline from "./home-timeline.js"; +import localTimeline from "./local-timeline.js"; +import hybridTimeline from "./hybrid-timeline.js"; +import recommendedTimeline from "./recommended-timeline.js"; +import globalTimeline from "./global-timeline.js"; +import serverStats from "./server-stats.js"; +import queueStats from "./queue-stats.js"; +import userList from "./user-list.js"; +import antenna from "./antenna.js"; +import messaging from "./messaging.js"; +import messagingIndex from "./messaging-index.js"; +import drive from "./drive.js"; +import hashtag from "./hashtag.js"; +import channel from "./channel.js"; +import admin from "./admin.js"; export default { main, diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 729de6d4a..6f8075b7a 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,15 +1,15 @@ -import Channel from '../channel.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'localTimeline'; + public readonly chName = "localTimeline"; public static shouldShare = true; public static requireCredential = false; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } @@ -17,23 +17,30 @@ export default class extends Channel { public async init(params: any) { const meta = await fetchMeta(); if (meta.disableLocalTimeline) { - if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return; + if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) + return; } // Subscribe events - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { if (note.user.host !== null) return; - if (note.visibility !== 'public') return; - if (note.channelId != null && !this.followingChannels.has(note.channelId)) return; + if (note.visibility !== "public") return; + if (note.channelId != null && !this.followingChannels.has(note.channelId)) + return; // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if ( + reply.userId !== this.user!.id && + note.userId !== this.user!.id && + reply.userId !== note.userId + ) + return; } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -46,15 +53,19 @@ export default class extends Channel { // 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる - if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + if ( + this.userProfile && + (await checkWordMute(note, this.user, this.userProfile.mutedWords)) + ) + return; this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index 7f42263db..b8c72442f 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -1,24 +1,39 @@ -import Channel from '../channel.js'; -import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js'; +import Channel from "../channel.js"; +import { + isInstanceMuted, + isUserFromMutedInstance, +} from "@/misc/is-instance-muted.js"; export default class extends Channel { - public readonly chName = 'main'; + public readonly chName = "main"; public static shouldShare = true; public static requireCredential = true; public async init(params: any) { // Subscribe main stream channel - this.subscriber.on(`mainStream:${this.user!.id}`, async data => { + this.subscriber.on(`mainStream:${this.user!.id}`, async (data) => { switch (data.type) { - case 'notification': { + case "notification": { // Ignore notifications from instances the user has muted - if (isUserFromMutedInstance(data.body, new Set(this.userProfile?.mutedInstances ?? []))) return; + if ( + isUserFromMutedInstance( + data.body, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; if (data.body.userId && this.muting.has(data.body.userId)) return; break; } - case 'mention': { - if (isInstanceMuted(data.body, new Set(this.userProfile?.mutedInstances ?? []))) return; + case "mention": { + if ( + isInstanceMuted( + data.body, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; if (this.muting.has(data.body.userId)) return; break; diff --git a/packages/backend/src/server/api/stream/channels/messaging-index.ts b/packages/backend/src/server/api/stream/channels/messaging-index.ts index b930785d2..8165172d7 100644 --- a/packages/backend/src/server/api/stream/channels/messaging-index.ts +++ b/packages/backend/src/server/api/stream/channels/messaging-index.ts @@ -1,13 +1,13 @@ -import Channel from '../channel.js'; +import Channel from "../channel.js"; export default class extends Channel { - public readonly chName = 'messagingIndex'; + public readonly chName = "messagingIndex"; public static shouldShare = true; public static requireCredential = true; public async init(params: any) { // Subscribe messaging index stream - this.subscriber.on(`messagingIndexStream:${this.user!.id}`, data => { + this.subscriber.on(`messagingIndexStream:${this.user!.id}`, (data) => { this.send(data); }); } diff --git a/packages/backend/src/server/api/stream/channels/messaging.ts b/packages/backend/src/server/api/stream/channels/messaging.ts index 877d44c38..dc1825059 100644 --- a/packages/backend/src/server/api/stream/channels/messaging.ts +++ b/packages/backend/src/server/api/stream/channels/messaging.ts @@ -1,23 +1,29 @@ -import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message.js'; -import Channel from '../channel.js'; -import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index.js'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { StreamMessages } from '../types.js'; +import { + readUserMessagingMessage, + readGroupMessagingMessage, + deliverReadActivity, +} from "../../common/read-messaging-message.js"; +import Channel from "../channel.js"; +import { UserGroupJoinings, Users, MessagingMessages } from "@/models/index.js"; +import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import type { StreamMessages } from "../types.js"; export default class extends Channel { - public readonly chName = 'messaging'; + public readonly chName = "messaging"; public static shouldShare = false; public static requireCredential = true; private otherpartyId: string | null; private otherparty: User | null; private groupId: string | null; - private subCh: `messagingStream:${User['id']}-${User['id']}` | `messagingStream:${UserGroup['id']}`; - private typers: Record = {}; + private subCh: + | `messagingStream:${User["id"]}-${User["id"]}` + | `messagingStream:${UserGroup["id"]}`; + private typers: Record = {}; private emitTypersIntervalId: ReturnType; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onEvent = this.onEvent.bind(this); this.onMessage = this.onMessage.bind(this); @@ -26,7 +32,9 @@ export default class extends Channel { public async init(params: any) { this.otherpartyId = params.otherparty; - this.otherparty = this.otherpartyId ? await Users.findOneByOrFail({ id: this.otherpartyId }) : null; + this.otherparty = this.otherpartyId + ? await Users.findOneByOrFail({ id: this.otherpartyId }) + : null; this.groupId = params.group; // Check joining @@ -51,8 +59,12 @@ export default class extends Channel { this.subscriber.on(this.subCh, this.onEvent); } - private onEvent(data: StreamMessages['messaging']['payload'] | StreamMessages['groupMessaging']['payload']) { - if (data.type === 'typing') { + private onEvent( + data: + | StreamMessages["messaging"]["payload"] + | StreamMessages["groupMessaging"]["payload"], + ) { + if (data.type === "typing") { const id = data.body; const begin = this.typers[id] == null; this.typers[id] = new Date(); @@ -66,14 +78,22 @@ export default class extends Channel { public onMessage(type: string, body: any) { switch (type) { - case 'read': + case "read": if (this.otherpartyId) { readUserMessagingMessage(this.user!.id, this.otherpartyId, [body.id]); // リモートユーザーからのメッセージだったら既読配信 - if (Users.isLocalUser(this.user!) && Users.isRemoteUser(this.otherparty!)) { - MessagingMessages.findOneBy({ id: body.id }).then(message => { - if (message) deliverReadActivity(this.user as ILocalUser, this.otherparty as IRemoteUser, message); + if ( + Users.isLocalUser(this.user!) && + Users.isRemoteUser(this.otherparty!) + ) { + MessagingMessages.findOneBy({ id: body.id }).then((message) => { + if (message) + deliverReadActivity( + this.user as ILocalUser, + this.otherparty as IRemoteUser, + message, + ); }); } } else if (this.groupId) { @@ -88,13 +108,16 @@ export default class extends Channel { // Remove not typing users for (const [userId, date] of Object.entries(this.typers)) { - if (now.getTime() - date.getTime() > 5000) delete this.typers[userId]; + if (now.getTime() - date.getTime() > 5000) + this.typers[userId] = undefined; } - const users = await Users.packMany(Object.keys(this.typers), null, { detail: false }); + const users = await Users.packMany(Object.keys(this.typers), null, { + detail: false, + }); this.send({ - type: 'typers', + type: "typers", body: users, }); } diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index b67600474..a5a93c332 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -1,34 +1,34 @@ -import Xev from 'xev'; -import Channel from '../channel.js'; +import Xev from "xev"; +import Channel from "../channel.js"; const ev = new Xev(); export default class extends Channel { - public readonly chName = 'queueStats'; + public readonly chName = "queueStats"; public static shouldShare = true; public static requireCredential = false; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onStats = this.onStats.bind(this); this.onMessage = this.onMessage.bind(this); } public async init(params: any) { - ev.addListener('queueStats', this.onStats); + ev.addListener("queueStats", this.onStats); } private onStats(stats: any) { - this.send('stats', stats); + this.send("stats", stats); } public onMessage(type: string, body: any) { switch (type) { - case 'requestLog': - ev.once(`queueStatsLog:${body.id}`, statsLog => { - this.send('statsLog', statsLog); + case "requestLog": + ev.once(`queueStatsLog:${body.id}`, (statsLog) => { + this.send("statsLog", statsLog); }); - ev.emit('requestQueueStatsLog', { + ev.emit("requestQueueStatsLog", { id: body.id, length: body.length, }); @@ -37,6 +37,6 @@ export default class extends Channel { } public dispose() { - ev.removeListener('queueStats', this.onStats); + ev.removeListener("queueStats", this.onStats); } } diff --git a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts index c0625aec8..a2a03fca1 100644 --- a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts @@ -1,46 +1,67 @@ -import Channel from '../channel.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { isInstanceMuted } from '@/misc/is-instance-muted.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import { isInstanceMuted } from "@/misc/is-instance-muted.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'recommendedTimeline'; + public readonly chName = "recommendedTimeline"; public static shouldShare = true; public static requireCredential = true; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { const meta = await fetchMeta(); - if (meta.disableRecommendedTimeline && !this.user!.isAdmin && !this.user!.isModerator) return; + if ( + meta.disableRecommendedTimeline && + !this.user!.isAdmin && + !this.user!.isModerator + ) + return; // Subscribe events - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { // チャンネルの投稿ではなく、自分自身の投稿 または // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または // チャンネルの投稿ではなく、全体公開のローカルの投稿 または // フォローしているチャンネルの投稿 の場合だけ const meta = await fetchMeta(); - if (!( - ((note.user.host != null && meta.recommendedInstances.includes(note.user.host)) && note.visibility === 'public') - )) return; + if ( + !( + note.user.host != null && + meta.recommendedInstances.includes(note.user.host) && + note.visibility === "public" + ) + ) + return; // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; + if ( + isInstanceMuted( + note, + new Set(this.userProfile?.mutedInstances ?? []), + ) + ) + return; // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if ( + reply.userId !== this.user!.id && + note.userId !== this.user!.id && + reply.userId !== note.userId + ) + return; } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -53,15 +74,19 @@ export default class extends Channel { // 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、 // レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。 // そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる - if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return; + if ( + this.userProfile && + (await checkWordMute(note, this.user, this.userProfile.mutedWords)) + ) + return; this.connection.cacheNote(note); - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); } } diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index db75a6fa3..58659138d 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -1,34 +1,34 @@ -import Xev from 'xev'; -import Channel from '../channel.js'; +import Xev from "xev"; +import Channel from "../channel.js"; const ev = new Xev(); export default class extends Channel { - public readonly chName = 'serverStats'; + public readonly chName = "serverStats"; public static shouldShare = true; public static requireCredential = false; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.onStats = this.onStats.bind(this); this.onMessage = this.onMessage.bind(this); } public async init(params: any) { - ev.addListener('serverStats', this.onStats); + ev.addListener("serverStats", this.onStats); } private onStats(stats: any) { - this.send('stats', stats); + this.send("stats", stats); } public onMessage(type: string, body: any) { switch (type) { - case 'requestLog': - ev.once(`serverStatsLog:${body.id}`, statsLog => { - this.send('statsLog', statsLog); + case "requestLog": + ev.once(`serverStatsLog:${body.id}`, (statsLog) => { + this.send("statsLog", statsLog); }); - ev.emit('requestServerStatsLog', { + ev.emit("requestServerStatsLog", { id: body.id, length: body.length, }); @@ -37,6 +37,6 @@ export default class extends Channel { } public dispose() { - ev.removeListener('serverStats', this.onStats); + ev.removeListener("serverStats", this.onStats); } } diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 9b2476148..f63776c9e 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -1,18 +1,18 @@ -import Channel from '../channel.js'; -import { UserListJoinings, UserLists } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { Packed } from '@/misc/schema.js'; +import Channel from "../channel.js"; +import { UserListJoinings, UserLists } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import type { Packed } from "@/misc/schema.js"; export default class extends Channel { - public readonly chName = 'userList'; + public readonly chName = "userList"; public static shouldShare = false; public static requireCredential = false; private listId: string; - public listUsers: User['id'][] = []; + public listUsers: User["id"][] = []; private listUsersClock: NodeJS.Timer; - constructor(id: string, connection: Channel['connection']) { + constructor(id: string, connection: Channel["connection"]) { super(id, connection); this.updateListUsers = this.updateListUsers.bind(this); this.onNote = this.withPackedNote(this.onNote.bind(this)); @@ -31,7 +31,7 @@ export default class extends Channel { // Subscribe stream this.subscriber.on(`userListStream:${this.listId}`, this.send); - this.subscriber.on('notesStream', this.onNote); + this.subscriber.on("notesStream", this.onNote); this.updateListUsers(); this.listUsersClock = setInterval(this.updateListUsers, 5000); @@ -42,13 +42,13 @@ export default class extends Channel { where: { userListId: this.listId, }, - select: ['userId'], + select: ["userId"], }); - this.listUsers = users.map(x => x.userId); + this.listUsers = users.map((x) => x.userId); } - private async onNote(note: Packed<'Note'>) { + private async onNote(note: Packed<"Note">) { if (!this.listUsers.includes(note.userId)) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する @@ -56,13 +56,13 @@ export default class extends Channel { // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する if (isUserRelated(note, this.blocking)) return; - this.send('note', note); + this.send("note", note); } public dispose() { // Unsubscribe events this.subscriber.off(`userListStream:${this.listId}`, this.send); - this.subscriber.off('notesStream', this.onNote); + this.subscriber.off("notesStream", this.onNote); clearInterval(this.listUsersClock); } diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index 2d23145f1..9675d184c 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -1,18 +1,29 @@ -import { EventEmitter } from 'events'; -import * as websocket from 'websocket'; -import readNote from '@/services/note/read.js'; -import { User } from '@/models/entities/user.js'; -import { Channel as ChannelModel } from '@/models/entities/channel.js'; -import { Users, Followings, Mutings, UserProfiles, ChannelFollowings, Blockings } from '@/models/index.js'; -import { AccessToken } from '@/models/entities/access-token.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { Packed } from '@/misc/schema.js'; -import { readNotification } from '../common/read-notification.js'; -import channels from './channels/index.js'; -import Channel from './channel.js'; -import { StreamEventEmitter, StreamMessages } from './types.js'; +import type { EventEmitter } from "events"; +import type * as websocket from "websocket"; +import readNote from "@/services/note/read.js"; +import type { User } from "@/models/entities/user.js"; +import type { Channel as ChannelModel } from "@/models/entities/channel.js"; +import { + Users, + Followings, + Mutings, + UserProfiles, + ChannelFollowings, + Blockings, +} from "@/models/index.js"; +import type { AccessToken } from "@/models/entities/access-token.js"; +import type { UserProfile } from "@/models/entities/user-profile.js"; +import { + publishChannelStream, + publishGroupMessagingStream, + publishMessagingStream, +} from "@/services/stream.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import type { Packed } from "@/misc/schema.js"; +import { readNotification } from "../common/read-notification.js"; +import channels from "./channels/index.js"; +import type Channel from "./channel.js"; +import type { StreamEventEmitter, StreamMessages } from "./types.js"; /** * Main stream connection @@ -20,16 +31,16 @@ import { StreamEventEmitter, StreamMessages } from './types.js'; export default class Connection { public user?: User; public userProfile?: UserProfile | null; - public following: Set = new Set(); - public muting: Set = new Set(); - public blocking: Set = new Set(); // "被"blocking - public followingChannels: Set = new Set(); + public following: Set = new Set(); + public muting: Set = new Set(); + public blocking: Set = new Set(); // "被"blocking + public followingChannels: Set = new Set(); public token?: AccessToken; private wsConnection: websocket.connection; public subscriber: StreamEventEmitter; private channels: Channel[] = []; private subscribingNotes: any = {}; - private cachedNotes: Packed<'Note'>[] = []; + private cachedNotes: Packed<"Note">[] = []; constructor( wsConnection: websocket.connection, @@ -47,9 +58,9 @@ export default class Connection { this.onNoteStreamMessage = this.onNoteStreamMessage.bind(this); this.onBroadcastMessage = this.onBroadcastMessage.bind(this); - this.wsConnection.on('message', this.onWsConnectionMessage); + this.wsConnection.on("message", this.onWsConnectionMessage); - this.subscriber.on('broadcast', data => { + this.subscriber.on("broadcast", (data) => { this.onBroadcastMessage(data); }); @@ -64,39 +75,40 @@ export default class Connection { } } - private onUserEvent(data: StreamMessages['user']['payload']) { // { type, body }と展開するとそれぞれ型が分離してしまう + private onUserEvent(data: StreamMessages["user"]["payload"]) { + // { type, body }と展開するとそれぞれ型が分離してしまう switch (data.type) { - case 'follow': + case "follow": this.following.add(data.body.id); break; - case 'unfollow': + case "unfollow": this.following.delete(data.body.id); break; - case 'mute': + case "mute": this.muting.add(data.body.id); break; - case 'unmute': + case "unmute": this.muting.delete(data.body.id); break; - // TODO: block events + // TODO: block events - case 'followChannel': + case "followChannel": this.followingChannels.add(data.body.id); break; - case 'unfollowChannel': + case "unfollowChannel": this.followingChannels.delete(data.body.id); break; - case 'updateUserProfile': + case "updateUserProfile": this.userProfile = data.body; break; - case 'terminate': + case "terminate": this.wsConnection.close(); this.dispose(); break; @@ -110,7 +122,7 @@ export default class Connection { * クライアントからメッセージ受信時 */ private async onWsConnectionMessage(data: websocket.Message) { - if (data.type !== 'utf8') return; + if (data.type !== "utf8") return; if (data.utf8Data == null) return; let obj: Record; @@ -124,32 +136,57 @@ export default class Connection { const { type, body } = obj; switch (type) { - case 'readNotification': this.onReadNotification(body); break; - case 'subNote': this.onSubscribeNote(body); break; - case 's': this.onSubscribeNote(body); break; // alias - case 'sr': this.onSubscribeNote(body); this.readNote(body); break; - case 'unsubNote': this.onUnsubscribeNote(body); break; - case 'un': this.onUnsubscribeNote(body); break; // alias - case 'connect': this.onChannelConnectRequested(body); break; - case 'disconnect': this.onChannelDisconnectRequested(body); break; - case 'channel': this.onChannelMessageRequested(body); break; - case 'ch': this.onChannelMessageRequested(body); break; // alias + case "readNotification": + this.onReadNotification(body); + break; + case "subNote": + this.onSubscribeNote(body); + break; + case "s": + this.onSubscribeNote(body); + break; // alias + case "sr": + this.onSubscribeNote(body); + this.readNote(body); + break; + case "unsubNote": + this.onUnsubscribeNote(body); + break; + case "un": + this.onUnsubscribeNote(body); + break; // alias + case "connect": + this.onChannelConnectRequested(body); + break; + case "disconnect": + this.onChannelDisconnectRequested(body); + break; + case "channel": + this.onChannelMessageRequested(body); + break; + case "ch": + this.onChannelMessageRequested(body); + break; // alias // 個々のチャンネルではなくルートレベルでこれらのメッセージを受け取る理由は、 // クライアントの事情を考慮したとき、入力フォームはノートチャンネルやメッセージのメインコンポーネントとは別 // なこともあるため、それらのコンポーネントがそれぞれ各チャンネルに接続するようにするのは面倒なため。 - case 'typingOnChannel': this.typingOnChannel(body.channel); break; - case 'typingOnMessaging': this.typingOnMessaging(body); break; + case "typingOnChannel": + this.typingOnChannel(body.channel); + break; + case "typingOnMessaging": + this.typingOnMessaging(body); + break; } } - private onBroadcastMessage(data: StreamMessages['broadcast']['payload']) { + private onBroadcastMessage(data: StreamMessages["broadcast"]["payload"]) { this.sendMessageToWs(data.type, data.body); } - public cacheNote(note: Packed<'Note'>) { - const add = (note: Packed<'Note'>) => { - const existIndex = this.cachedNotes.findIndex(n => n.id === note.id); + public cacheNote(note: Packed<"Note">) { + const add = (note: Packed<"Note">) => { + const existIndex = this.cachedNotes.findIndex((n) => n.id === note.id); if (existIndex > -1) { this.cachedNotes[existIndex] = note; return; @@ -169,10 +206,10 @@ export default class Connection { private readNote(body: any) { const id = body.id; - const note = this.cachedNotes.find(n => n.id === id); + const note = this.cachedNotes.find((n) => n.id === id); if (note == null) return; - if (this.user && (note.userId !== this.user.id)) { + if (this.user && note.userId !== this.user.id) { readNote(this.user.id, [note], { following: this.following, followingChannels: this.followingChannels, @@ -210,13 +247,13 @@ export default class Connection { this.subscribingNotes[payload.id]--; if (this.subscribingNotes[payload.id] <= 0) { - delete this.subscribingNotes[payload.id]; + this.subscribingNotes[payload.id] = undefined; this.subscriber.off(`noteStream:${payload.id}`, this.onNoteStreamMessage); } } - private async onNoteStreamMessage(data: StreamMessages['note']['payload']) { - this.sendMessageToWs('noteUpdated', { + private async onNoteStreamMessage(data: StreamMessages["note"]["payload"]) { + this.sendMessageToWs("noteUpdated", { id: data.body.id, type: data.type, body: data.body.body, @@ -243,22 +280,32 @@ export default class Connection { * クライアントにメッセージ送信 */ public sendMessageToWs(type: string, payload: any) { - this.wsConnection.send(JSON.stringify({ - type: type, - body: payload, - })); + this.wsConnection.send( + JSON.stringify({ + type: type, + body: payload, + }), + ); } /** * チャンネルに接続 */ - public connectChannel(id: string, params: any, channel: string, pong = false) { + public connectChannel( + id: string, + params: any, + channel: string, + pong = false, + ) { if ((channels as any)[channel].requireCredential && this.user == null) { return; } // 共有可能チャンネルに接続しようとしていて、かつそのチャンネルに既に接続していたら無意味なので無視 - if ((channels as any)[channel].shouldShare && this.channels.some(c => c.chName === channel)) { + if ( + (channels as any)[channel].shouldShare && + this.channels.some((c) => c.chName === channel) + ) { return; } @@ -267,7 +314,7 @@ export default class Connection { ch.init(params); if (pong) { - this.sendMessageToWs('connected', { + this.sendMessageToWs("connected", { id: id, }); } @@ -278,11 +325,11 @@ export default class Connection { * @param id チャンネルコネクションID */ public disconnectChannel(id: string) { - const channel = this.channels.find(c => c.id === id); + const channel = this.channels.find((c) => c.id === id); if (channel) { if (channel.dispose) channel.dispose(); - this.channels = this.channels.filter(c => c.id !== id); + this.channels = this.channels.filter((c) => c.id !== id); } } @@ -291,24 +338,32 @@ export default class Connection { * @param data メッセージ */ private onChannelMessageRequested(data: any) { - const channel = this.channels.find(c => c.id === data.id); - if (channel != null && channel.onMessage != null) { + const channel = this.channels.find((c) => c.id === data.id); + if (channel?.onMessage != null) { channel.onMessage(data.type, data.body); } } - private typingOnChannel(channel: ChannelModel['id']) { + private typingOnChannel(channel: ChannelModel["id"]) { if (this.user) { - publishChannelStream(channel, 'typing', this.user.id); + publishChannelStream(channel, "typing", this.user.id); } } - private typingOnMessaging(param: { partner?: User['id']; group?: UserGroup['id']; }) { + private typingOnMessaging(param: { + partner?: User["id"]; + group?: UserGroup["id"]; + }) { if (this.user) { if (param.partner) { - publishMessagingStream(param.partner, this.user.id, 'typing', this.user.id); + publishMessagingStream( + param.partner, + this.user.id, + "typing", + this.user.id, + ); } else if (param.group) { - publishGroupMessagingStream(param.group, 'typing', this.user.id); + publishGroupMessagingStream(param.group, "typing", this.user.id); } } } @@ -318,10 +373,10 @@ export default class Connection { where: { followerId: this.user!.id, }, - select: ['followeeId'], + select: ["followeeId"], }); - this.following = new Set(followings.map(x => x.followeeId)); + this.following = new Set(followings.map((x) => x.followeeId)); } private async updateMuting() { @@ -329,21 +384,22 @@ export default class Connection { where: { muterId: this.user!.id, }, - select: ['muteeId'], + select: ["muteeId"], }); - this.muting = new Set(mutings.map(x => x.muteeId)); + this.muting = new Set(mutings.map((x) => x.muteeId)); } - private async updateBlocking() { // ここでいうBlockingは被Blockingの意 + private async updateBlocking() { + // ここでいうBlockingは被Blockingの意 const blockings = await Blockings.find({ where: { blockeeId: this.user!.id, }, - select: ['blockerId'], + select: ["blockerId"], }); - this.blocking = new Set(blockings.map(x => x.blockerId)); + this.blocking = new Set(blockings.map((x) => x.blockerId)); } private async updateFollowingChannels() { @@ -351,10 +407,12 @@ export default class Connection { where: { followerId: this.user!.id, }, - select: ['followeeId'], + select: ["followeeId"], }); - this.followingChannels = new Set(followings.map(x => x.followeeId)); + this.followingChannels = new Set( + followings.map((x) => x.followeeId), + ); } private async updateUserProfile() { @@ -367,7 +425,7 @@ export default class Connection { * ストリームが切れたとき */ public dispose() { - for (const c of this.channels.filter(c => c.dispose)) { + for (const c of this.channels.filter((c) => c.dispose)) { if (c.dispose) c.dispose(); } } diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 8050d8a1d..837f42c87 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -1,29 +1,39 @@ -import { EventEmitter } from 'events'; -import Emitter from 'strict-event-emitter-types'; -import { Channel } from '@/models/entities/channel.js'; -import { User } from '@/models/entities/user.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { Note } from '@/models/entities/note.js'; -import { Antenna } from '@/models/entities/antenna.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFolder } from '@/models/entities/drive-folder.js'; -import { Emoji } from '@/models/entities/emoji.js'; -import { UserList } from '@/models/entities/user-list.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; -import { Signin } from '@/models/entities/signin.js'; -import { Page } from '@/models/entities/page.js'; -import { Packed } from '@/misc/schema.js'; -import { Webhook } from '@/models/entities/webhook'; +import type { EventEmitter } from "events"; +import type Emitter from "strict-event-emitter-types"; +import type { Channel } from "@/models/entities/channel.js"; +import type { User } from "@/models/entities/user.js"; +import type { UserProfile } from "@/models/entities/user-profile.js"; +import type { Note } from "@/models/entities/note.js"; +import type { Antenna } from "@/models/entities/antenna.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { DriveFolder } from "@/models/entities/drive-folder.js"; +import { Emoji } from "@/models/entities/emoji.js"; +import type { UserList } from "@/models/entities/user-list.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import type { AbuseUserReport } from "@/models/entities/abuse-user-report.js"; +import type { Signin } from "@/models/entities/signin.js"; +import type { Page } from "@/models/entities/page.js"; +import type { Packed } from "@/misc/schema.js"; +import type { Webhook } from "@/models/entities/webhook"; //#region Stream type-body definitions export interface InternalStreamTypes { - userChangeSuspendedState: { id: User['id']; isSuspended: User['isSuspended']; }; - userChangeSilencedState: { id: User['id']; isSilenced: User['isSilenced']; }; - userChangeModeratorState: { id: User['id']; isModerator: User['isModerator']; }; - userTokenRegenerated: { id: User['id']; oldToken: User['token']; newToken: User['token']; }; - remoteUserUpdated: { id: User['id']; }; + userChangeSuspendedState: { + id: User["id"]; + isSuspended: User["isSuspended"]; + }; + userChangeSilencedState: { id: User["id"]; isSilenced: User["isSilenced"] }; + userChangeModeratorState: { + id: User["id"]; + isModerator: User["isModerator"]; + }; + userTokenRegenerated: { + id: User["id"]; + oldToken: User["token"]; + newToken: User["token"]; + }; + remoteUserUpdated: { id: User["id"] }; webhookCreated: Webhook; webhookDeleted: Webhook; webhookUpdated: Webhook; @@ -34,7 +44,7 @@ export interface InternalStreamTypes { export interface BroadcastTypes { emojiAdded: { - emoji: Packed<'Emoji'>; + emoji: Packed<"Emoji">; }; } @@ -45,45 +55,45 @@ export interface UserStreamTypes { updateUserProfile: UserProfile; mute: User; unmute: User; - follow: Packed<'UserDetailedNotMe'>; - unfollow: Packed<'User'>; - userAdded: Packed<'User'>; + follow: Packed<"UserDetailedNotMe">; + unfollow: Packed<"User">; + userAdded: Packed<"User">; } export interface MainStreamTypes { - notification: Packed<'Notification'>; - mention: Packed<'Note'>; - reply: Packed<'Note'>; - renote: Packed<'Note'>; - follow: Packed<'UserDetailedNotMe'>; - followed: Packed<'User'>; - unfollow: Packed<'User'>; - meUpdated: Packed<'User'>; + notification: Packed<"Notification">; + mention: Packed<"Note">; + reply: Packed<"Note">; + renote: Packed<"Note">; + follow: Packed<"UserDetailedNotMe">; + followed: Packed<"User">; + unfollow: Packed<"User">; + meUpdated: Packed<"User">; pageEvent: { - pageId: Page['id']; + pageId: Page["id"]; event: string; var: any; - userId: User['id']; - user: Packed<'User'>; + userId: User["id"]; + user: Packed<"User">; }; urlUploadFinished: { marker?: string | null; - file: Packed<'DriveFile'>; + file: Packed<"DriveFile">; }; readAllNotifications: undefined; - unreadNotification: Packed<'Notification'>; - unreadMention: Note['id']; + unreadNotification: Packed<"Notification">; + unreadMention: Note["id"]; readAllUnreadMentions: undefined; - unreadSpecifiedNote: Note['id']; + unreadSpecifiedNote: Note["id"]; readAllUnreadSpecifiedNotes: undefined; readAllMessagingMessages: undefined; - messagingMessage: Packed<'MessagingMessage'>; - unreadMessagingMessage: Packed<'MessagingMessage'>; + messagingMessage: Packed<"MessagingMessage">; + unreadMessagingMessage: Packed<"MessagingMessage">; readAllAntennas: undefined; unreadAntenna: Antenna; readAllAnnouncements: undefined; readAllChannels: undefined; - unreadChannel: Note['id']; + unreadChannel: Note["id"]; myTokenRegenerated: undefined; signin: Signin; registryUpdated: { @@ -91,24 +101,24 @@ export interface MainStreamTypes { key: string; value: any | null; }; - driveFileCreated: Packed<'DriveFile'>; + driveFileCreated: Packed<"DriveFile">; readAntenna: Antenna; - receiveFollowRequest: Packed<'User'>; + receiveFollowRequest: Packed<"User">; } export interface DriveStreamTypes { - fileCreated: Packed<'DriveFile'>; - fileDeleted: DriveFile['id']; - fileUpdated: Packed<'DriveFile'>; - folderCreated: Packed<'DriveFolder'>; - folderDeleted: DriveFolder['id']; - folderUpdated: Packed<'DriveFolder'>; + fileCreated: Packed<"DriveFile">; + fileDeleted: DriveFile["id"]; + fileUpdated: Packed<"DriveFile">; + folderCreated: Packed<"DriveFolder">; + folderDeleted: DriveFolder["id"]; + folderUpdated: Packed<"DriveFolder">; } export interface NoteStreamTypes { pollVoted: { choice: number; - userId: User['id']; + userId: User["id"]; }; deleted: { deletedAt: Date; @@ -119,27 +129,27 @@ export interface NoteStreamTypes { name: string; url: string; } | null; - userId: User['id']; + userId: User["id"]; }; unreacted: { reaction: string; - userId: User['id']; + userId: User["id"]; }; } type NoteStreamEventTypes = { [key in keyof NoteStreamTypes]: { - id: Note['id']; + id: Note["id"]; body: NoteStreamTypes[key]; }; }; export interface ChannelStreamTypes { - typing: User['id']; + typing: User["id"]; } export interface UserListStreamTypes { - userAdded: Packed<'User'>; - userRemoved: Packed<'User'>; + userAdded: Packed<"User">; + userRemoved: Packed<"User">; } export interface AntennaStreamTypes { @@ -147,32 +157,32 @@ export interface AntennaStreamTypes { } export interface MessagingStreamTypes { - read: MessagingMessage['id'][]; - typing: User['id']; - message: Packed<'MessagingMessage'>; - deleted: MessagingMessage['id']; + read: MessagingMessage["id"][]; + typing: User["id"]; + message: Packed<"MessagingMessage">; + deleted: MessagingMessage["id"]; } export interface GroupMessagingStreamTypes { read: { - ids: MessagingMessage['id'][]; - userId: User['id']; + ids: MessagingMessage["id"][]; + userId: User["id"]; }; - typing: User['id']; - message: Packed<'MessagingMessage'>; - deleted: MessagingMessage['id']; + typing: User["id"]; + message: Packed<"MessagingMessage">; + deleted: MessagingMessage["id"]; } export interface MessagingIndexStreamTypes { - read: MessagingMessage['id'][]; - message: Packed<'MessagingMessage'>; + read: MessagingMessage["id"][]; + message: Packed<"MessagingMessage">; } export interface AdminStreamTypes { newAbuseUserReport: { - id: AbuseUserReport['id']; - targetUserId: User['id'], - reporterId: User['id'], + id: AbuseUserReport["id"]; + targetUserId: User["id"]; + reporterId: User["id"]; comment: string; }; } @@ -181,80 +191,92 @@ export interface AdminStreamTypes { // 辞書(interface or type)から{ type, body }ユニオンを定義 // https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type // VS Codeの展開を防止するためにEvents型を定義 -type Events = { [K in keyof T]: { type: K; body: T[K]; } }; -type EventUnionFromDictionary< - T extends object, - U = Events -> = U[keyof U]; +type Events = { [K in keyof T]: { type: K; body: T[K] } }; +type EventUnionFromDictionary> = U[keyof U]; // name/messages(spec) pairs dictionary export type StreamMessages = { internal: { - name: 'internal'; + name: "internal"; payload: EventUnionFromDictionary; }; broadcast: { - name: 'broadcast'; + name: "broadcast"; payload: EventUnionFromDictionary; }; user: { - name: `user:${User['id']}`; + name: `user:${User["id"]}`; payload: EventUnionFromDictionary; }; main: { - name: `mainStream:${User['id']}`; + name: `mainStream:${User["id"]}`; payload: EventUnionFromDictionary; }; drive: { - name: `driveStream:${User['id']}`; + name: `driveStream:${User["id"]}`; payload: EventUnionFromDictionary; }; note: { - name: `noteStream:${Note['id']}`; + name: `noteStream:${Note["id"]}`; payload: EventUnionFromDictionary; }; channel: { - name: `channelStream:${Channel['id']}`; + name: `channelStream:${Channel["id"]}`; payload: EventUnionFromDictionary; }; userList: { - name: `userListStream:${UserList['id']}`; + name: `userListStream:${UserList["id"]}`; payload: EventUnionFromDictionary; }; antenna: { - name: `antennaStream:${Antenna['id']}`; + name: `antennaStream:${Antenna["id"]}`; payload: EventUnionFromDictionary; }; messaging: { - name: `messagingStream:${User['id']}-${User['id']}`; + name: `messagingStream:${User["id"]}-${User["id"]}`; payload: EventUnionFromDictionary; }; groupMessaging: { - name: `messagingStream:${UserGroup['id']}`; + name: `messagingStream:${UserGroup["id"]}`; payload: EventUnionFromDictionary; }; messagingIndex: { - name: `messagingIndexStream:${User['id']}`; + name: `messagingIndexStream:${User["id"]}`; payload: EventUnionFromDictionary; }; admin: { - name: `adminStream:${User['id']}`; + name: `adminStream:${User["id"]}`; payload: EventUnionFromDictionary; }; notes: { - name: 'notesStream'; + name: "notesStream"; payload: Note; }; }; // API event definitions // ストリームごとのEmitterの辞書を用意 -type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter void }> }; +type EventEmitterDictionary = { + [x in keyof StreamMessages]: Emitter< + EventEmitter, + { + [y in StreamMessages[x]["name"]]: ( + e: StreamMessages[x]["payload"], + ) => void; + } + >; +}; // 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( + k: infer I, +) => void + ? I + : never; // Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする -export type StreamEventEmitter = UnionToIntersection; +export type StreamEventEmitter = UnionToIntersection< + EventEmitterDictionary[keyof StreamMessages] +>; // { [y in name]: (e: spec) => void }をまとめてその交差型をEmitterにかけるとts(2590)にひっかかる // provide stream channels union -export type StreamChannels = StreamMessages[keyof StreamMessages]['name']; +export type StreamChannels = StreamMessages[keyof StreamMessages]["name"]; diff --git a/packages/backend/src/server/api/streaming.ts b/packages/backend/src/server/api/streaming.ts index 7cf365faf..9e84ec307 100644 --- a/packages/backend/src/server/api/streaming.ts +++ b/packages/backend/src/server/api/streaming.ts @@ -1,12 +1,12 @@ -import * as http from 'node:http'; -import { EventEmitter } from 'events'; -import { ParsedUrlQuery } from 'querystring'; -import * as websocket from 'websocket'; +import type * as http from "node:http"; +import { EventEmitter } from "events"; +import type { ParsedUrlQuery } from "querystring"; +import * as websocket from "websocket"; -import { subscriber as redisClient } from '@/db/redis.js'; -import { Users } from '@/models/index.js'; -import MainStreamConnection from './stream/index.js'; -import authenticate from './authenticate.js'; +import { subscriber as redisClient } from "@/db/redis.js"; +import { Users } from "@/models/index.js"; +import MainStreamConnection from "./stream/index.js"; +import authenticate from "./authenticate.js"; export const initializeStreamingServer = (server: http.Server) => { // Init websocket server @@ -14,15 +14,17 @@ export const initializeStreamingServer = (server: http.Server) => { httpServer: server, }); - ws.on('request', async (request) => { + ws.on("request", async (request) => { const q = request.resourceURL.query as ParsedUrlQuery; - const [user, app] = await authenticate(request.httpRequest.headers.authorization, q.i) - .catch(err => { - request.reject(403, err.message); - return []; - }); - if (typeof user === 'undefined') { + const [user, app] = await authenticate( + request.httpRequest.headers.authorization, + q.i, + ).catch((err) => { + request.reject(403, err.message); + return []; + }); + if (typeof user === "undefined") { return; } @@ -40,31 +42,33 @@ export const initializeStreamingServer = (server: http.Server) => { ev.emit(parsed.channel, parsed.message); } - redisClient.on('message', onRedisMessage); + redisClient.on("message", onRedisMessage); const main = new MainStreamConnection(connection, ev, user, app); - const intervalId = user ? setInterval(() => { - Users.update(user.id, { - lastActiveDate: new Date(), - }); - }, 1000 * 60 * 5) : null; + const intervalId = user + ? setInterval(() => { + Users.update(user.id, { + lastActiveDate: new Date(), + }); + }, 1000 * 60 * 5) + : null; if (user) { Users.update(user.id, { lastActiveDate: new Date(), }); } - connection.once('close', () => { + connection.once("close", () => { ev.removeAllListeners(); main.dispose(); - redisClient.off('message', onRedisMessage); + redisClient.off("message", onRedisMessage); if (intervalId) clearInterval(intervalId); }); - connection.on('message', async (data) => { - if (data.type === 'utf8' && data.utf8Data === 'ping') { - connection.send('pong'); + connection.on("message", async (data) => { + if (data.type === "utf8" && data.utf8Data === "ping") { + connection.send("pong"); } }); }); diff --git a/packages/backend/src/server/file/index.ts b/packages/backend/src/server/file/index.ts index 07a493700..26df1de51 100644 --- a/packages/backend/src/server/file/index.ts +++ b/packages/backend/src/server/file/index.ts @@ -2,13 +2,13 @@ * File Server */ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import Koa from 'koa'; -import cors from '@koa/cors'; -import Router from '@koa/router'; -import sendDriveFile from './send-drive-file.js'; +import * as fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import Koa from "koa"; +import cors from "@koa/cors"; +import Router from "@koa/router"; +import sendDriveFile from "./send-drive-file.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -17,22 +17,25 @@ const _dirname = dirname(_filename); const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); + ctx.set( + "Content-Security-Policy", + `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`, + ); await next(); }); // Init router const router = new Router(); -router.get('/app-default.jpg', ctx => { +router.get("/app-default.jpg", (ctx) => { const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); ctx.body = file; - ctx.set('Content-Type', 'image/jpeg'); - ctx.set('Cache-Control', 'max-age=31536000, immutable'); + ctx.set("Content-Type", "image/jpeg"); + ctx.set("Cache-Control", "max-age=31536000, immutable"); }); -router.get('/:key', sendDriveFile); -router.get('/:key/(.*)', sendDriveFile); +router.get("/:key", sendDriveFile); +router.get("/:key/(.*)", sendDriveFile); // Register router app.use(router.routes()); diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index acfde9cfc..087736902 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -1,47 +1,51 @@ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import Koa from 'koa'; -import send from 'koa-send'; -import rename from 'rename'; -import { serverLogger } from '../index.js'; -import { contentDisposition } from '@/misc/content-disposition.js'; -import { DriveFiles } from '@/models/index.js'; -import { InternalStorage } from '@/services/drive/internal-storage.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { downloadUrl } from '@/misc/download-url.js'; -import { detectType } from '@/misc/get-file-info.js'; -import { convertToWebp, convertToJpeg, convertToPng } from '@/services/drive/image-processor.js'; -import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail.js'; -import { StatusError } from '@/misc/fetch.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; +import * as fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import type Koa from "koa"; +import send from "koa-send"; +import rename from "rename"; +import { serverLogger } from "../index.js"; +import { contentDisposition } from "@/misc/content-disposition.js"; +import { DriveFiles } from "@/models/index.js"; +import { InternalStorage } from "@/services/drive/internal-storage.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { downloadUrl } from "@/misc/download-url.js"; +import { detectType } from "@/misc/get-file-info.js"; +import { convertToWebp } from "@/services/drive/image-processor.js"; +import { GenerateVideoThumbnail } from "@/services/drive/generate-video-thumbnail.js"; +import { StatusError } from "@/misc/fetch.js"; +import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const assets = `${_dirname}/../../server/file/assets/`; -const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => { - serverLogger.error(e); - ctx.status = 500; - ctx.set('Cache-Control', 'max-age=300'); -}; +const commonReadableHandlerGenerator = + (ctx: Koa.Context) => (e: Error): void => { + serverLogger.error(e); + ctx.status = 500; + ctx.set("Cache-Control", "max-age=300"); + }; -// eslint-disable-next-line import/no-default-export -export default async function(ctx: Koa.Context) { +export default async function (ctx: Koa.Context) { const key = ctx.params.key; // Fetch drive file - const file = await DriveFiles.createQueryBuilder('file') - .where('file.accessKey = :accessKey', { accessKey: key }) - .orWhere('file.thumbnailAccessKey = :thumbnailAccessKey', { thumbnailAccessKey: key }) - .orWhere('file.webpublicAccessKey = :webpublicAccessKey', { webpublicAccessKey: key }) + const file = await DriveFiles.createQueryBuilder("file") + .where("file.accessKey = :accessKey", { accessKey: key }) + .orWhere("file.thumbnailAccessKey = :thumbnailAccessKey", { + thumbnailAccessKey: key, + }) + .orWhere("file.webpublicAccessKey = :webpublicAccessKey", { + webpublicAccessKey: key, + }) .getOne(); if (file == null) { ctx.status = 404; - ctx.set('Cache-Control', 'max-age=86400'); - await send(ctx as any, '/dummy.png', { root: assets }); + ctx.set("Cache-Control", "max-age=86400"); + await send(ctx as any, "/dummy.png", { root: assets }); return; } @@ -49,7 +53,8 @@ export default async function(ctx: Koa.Context) { const isWebpublic = file.webpublicAccessKey === key; if (!file.storedInternal) { - if (file.isLink && file.uri) { // 期限切れリモートファイル + if (file.isLink && file.uri) { + // 期限切れリモートファイル const [path, cleanup] = await createTemp(); try { @@ -59,16 +64,24 @@ export default async function(ctx: Koa.Context) { const convertFile = async () => { if (isThumbnail) { - if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml', 'image/avif'].includes(mime)) { - return await convertToWebp(path, 498, 280); - } else if (mime.startsWith('video/')) { + if ( + [ + "image/jpeg", + "image/webp", + "image/png", + "image/svg+xml", + "image/avif", + ].includes(mime) + ) { + return await convertToWebp(path, 996, 560); + } else if (mime.startsWith("video/")) { return await GenerateVideoThumbnail(path); } } if (isWebpublic) { - if (['image/svg+xml'].includes(mime)) { - return await convertToPng(path, 2048, 2048); + if (["image/svg+xml"].includes(mime)) { + return await convertToWebp(path, 2048, 2048, 100); } } @@ -81,17 +94,22 @@ export default async function(ctx: Koa.Context) { const image = await convertFile(); ctx.body = image.data; - ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream'); - ctx.set('Cache-Control', 'max-age=31536000, immutable'); + ctx.set( + "Content-Type", + FILE_TYPE_BROWSERSAFE.includes(image.type) + ? image.type + : "application/octet-stream", + ); + ctx.set("Cache-Control", "max-age=31536000, immutable"); } catch (e) { serverLogger.error(`${e}`); if (e instanceof StatusError && e.isClientError) { ctx.status = e.statusCode; - ctx.set('Cache-Control', 'max-age=86400'); + ctx.set("Cache-Control", "max-age=86400"); } else { ctx.status = 500; - ctx.set('Cache-Control', 'max-age=300'); + ctx.set("Cache-Control", "max-age=300"); } } finally { cleanup(); @@ -100,27 +118,35 @@ export default async function(ctx: Koa.Context) { } ctx.status = 204; - ctx.set('Cache-Control', 'max-age=86400'); + ctx.set("Cache-Control", "max-age=86400"); return; } if (isThumbnail || isWebpublic) { const { mime, ext } = await detectType(InternalStorage.resolvePath(key)); const filename = rename(file.name, { - suffix: isThumbnail ? '-thumb' : '-web', + suffix: isThumbnail ? "-thumb" : "-web", extname: ext ? `.${ext}` : undefined, }).toString(); ctx.body = InternalStorage.read(key); - ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream'); - ctx.set('Cache-Control', 'max-age=31536000, immutable'); - ctx.set('Content-Disposition', contentDisposition('inline', filename)); + ctx.set( + "Content-Type", + FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : "application/octet-stream", + ); + ctx.set("Cache-Control", "max-age=31536000, immutable"); + ctx.set("Content-Disposition", contentDisposition("inline", filename)); } else { const readable = InternalStorage.read(file.accessKey!); - readable.on('error', commonReadableHandlerGenerator(ctx)); + readable.on("error", commonReadableHandlerGenerator(ctx)); ctx.body = readable; - ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream'); - ctx.set('Cache-Control', 'max-age=31536000, immutable'); - ctx.set('Content-Disposition', contentDisposition('inline', file.name)); + ctx.set( + "Content-Type", + FILE_TYPE_BROWSERSAFE.includes(file.type) + ? file.type + : "application/octet-stream", + ); + ctx.set("Cache-Control", "max-age=31536000, immutable"); + ctx.set("Content-Disposition", contentDisposition("inline", file.name)); } } diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index ae236ce34..4d4b81d7a 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -2,65 +2,69 @@ * Core Server */ -import cluster from 'node:cluster'; -import * as fs from 'node:fs'; -import * as http from 'node:http'; -import Koa from 'koa'; -import Router from '@koa/router'; -import mount from 'koa-mount'; -import koaLogger from 'koa-logger'; -import * as slow from 'koa-slow'; +import cluster from "node:cluster"; +import * as fs from "node:fs"; +import * as http from "node:http"; +import Koa from "koa"; +import Router from "@koa/router"; +import mount from "koa-mount"; +import koaLogger from "koa-logger"; +import * as slow from "koa-slow"; -import { IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import Logger from '@/services/logger.js'; -import { UserProfiles, Users } from '@/models/index.js'; -import { genIdenticon } from '@/misc/gen-identicon.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { publishMainStream } from '@/services/stream.js'; -import * as Acct from '@/misc/acct.js'; -import { envOption } from '@/env.js'; -import activityPub from './activitypub.js'; -import nodeinfo from './nodeinfo.js'; -import wellKnown from './well-known.js'; -import apiServer from './api/index.js'; -import fileServer from './file/index.js'; -import proxyServer from './proxy/index.js'; -import webServer from './web/index.js'; -import { initializeStreamingServer } from './api/streaming.js'; +import { IsNull } from "typeorm"; +import config from "@/config/index.js"; +import Logger from "@/services/logger.js"; +import { UserProfiles, Users } from "@/models/index.js"; +import { genIdenticon } from "@/misc/gen-identicon.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { publishMainStream } from "@/services/stream.js"; +import * as Acct from "@/misc/acct.js"; +import { envOption } from "@/env.js"; +import activityPub from "./activitypub.js"; +import nodeinfo from "./nodeinfo.js"; +import wellKnown from "./well-known.js"; +import apiServer from "./api/index.js"; +import fileServer from "./file/index.js"; +import proxyServer from "./proxy/index.js"; +import webServer from "./web/index.js"; +import { initializeStreamingServer } from "./api/streaming.js"; -export const serverLogger = new Logger('server', 'gray', false); +export const serverLogger = new Logger("server", "gray", false); // Init app const app = new Koa(); app.proxy = true; -if (!['production', 'test'].includes(process.env.NODE_ENV || '')) { +if (!["production", "test"].includes(process.env.NODE_ENV || "")) { // Logger - app.use(koaLogger(str => { - serverLogger.info(str); - })); + app.use( + koaLogger((str) => { + serverLogger.info(str); + }), + ); // Delay if (envOption.slow) { - app.use(slow({ - delay: 3000, - })); + app.use( + slow({ + delay: 3000, + }), + ); } } // HSTS // 6months (15552000sec) -if (config.url.startsWith('https') && !config.disableHsts) { +if (config.url.startsWith("https") && !config.disableHsts) { app.use(async (ctx, next) => { - ctx.set('strict-transport-security', 'max-age=15552000; preload'); + ctx.set("strict-transport-security", "max-age=15552000; preload"); await next(); }); } -app.use(mount('/api', apiServer)); -app.use(mount('/files', fileServer)); -app.use(mount('/proxy', proxyServer)); +app.use(mount("/api", apiServer)); +app.use(mount("/files", fileServer)); +app.use(mount("/proxy", proxyServer)); // Init router const router = new Router(); @@ -70,49 +74,60 @@ router.use(activityPub.routes()); router.use(nodeinfo.routes()); router.use(wellKnown.routes()); -router.get('/avatar/@:acct', async ctx => { +router.get("/avatar/@:acct", async (ctx) => { const { username, host } = Acct.parse(ctx.params.acct); const user = await Users.findOne({ where: { usernameLower: username.toLowerCase(), - host: (host == null) || (host === config.host) ? IsNull() : host, + host: host == null || host === config.host ? IsNull() : host, isSuspended: false, }, - relations: ['avatar'], + relations: ["avatar"], }); if (user) { ctx.redirect(Users.getAvatarUrlSync(user)); } else { - ctx.redirect('/static-assets/user-unknown.png'); + ctx.redirect("/static-assets/user-unknown.png"); } }); -router.get('/identicon/:x', async ctx => { +router.get("/identicon/:x", async (ctx) => { const [temp, cleanup] = await createTemp(); await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); - ctx.set('Content-Type', 'image/png'); - ctx.body = fs.createReadStream(temp).on('close', () => cleanup()); + ctx.set("Content-Type", "image/png"); + ctx.body = fs.createReadStream(temp).on("close", () => cleanup()); }); -router.get('/verify-email/:code', async ctx => { +router.get("/verify-email/:code", async (ctx) => { const profile = await UserProfiles.findOneBy({ emailVerifyCode: ctx.params.code, }); if (profile != null) { - ctx.body = 'Verify succeeded!'; + ctx.body = "Verify succeeded!"; ctx.status = 200; - await UserProfiles.update({ userId: profile.userId }, { - emailVerified: true, - emailVerifyCode: null, - }); + await UserProfiles.update( + { userId: profile.userId }, + { + emailVerified: true, + emailVerifyCode: null, + }, + ); - publishMainStream(profile.userId, 'meUpdated', await Users.pack(profile.userId, { id: profile.userId }, { - detail: true, - includeSecrets: true, - })); + publishMainStream( + profile.userId, + "meUpdated", + await Users.pack( + profile.userId, + { id: profile.userId }, + { + detail: true, + includeSecrets: true, + }, + ), + ); } else { ctx.status = 404; } @@ -138,32 +153,37 @@ export const startServer = () => { return server; }; -export default () => new Promise(resolve => { - const server = createServer(); +export default () => + new Promise((resolve) => { + const server = createServer(); - initializeStreamingServer(server); + initializeStreamingServer(server); - server.on('error', e => { - switch ((e as any).code) { - case 'EACCES': - serverLogger.error(`You do not have permission to listen on port ${config.port}.`); - break; - case 'EADDRINUSE': - serverLogger.error(`Port ${config.port} is already in use by another process.`); - break; - default: - serverLogger.error(e); - break; - } + server.on("error", (e) => { + switch ((e as any).code) { + case "EACCES": + serverLogger.error( + `You do not have permission to listen on port ${config.port}.`, + ); + break; + case "EADDRINUSE": + serverLogger.error( + `Port ${config.port} is already in use by another process.`, + ); + break; + default: + serverLogger.error(e); + break; + } - if (cluster.isWorker) { - process.send!('listenFailed'); - } else { - // disableClustering - process.exit(1); - } + if (cluster.isWorker) { + process.send!("listenFailed"); + } else { + // disableClustering + process.exit(1); + } + }); + + // @ts-ignore + server.listen(config.port, resolve); }); - - // @ts-ignore - server.listen(config.port, resolve); -}); diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 0bb9e05c5..a7fa0de4c 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -1,52 +1,64 @@ -import Router from '@koa/router'; -import config from '@/config/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Users, Notes } from '@/models/index.js'; -import { IsNull, MoreThan } from 'typeorm'; -import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import { Cache } from '@/misc/cache.js'; +import Router from "@koa/router"; +import config from "@/config/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { Users, Notes } from "@/models/index.js"; +import { IsNull, MoreThan } from "typeorm"; +import { MAX_NOTE_TEXT_LENGTH } from "@/const.js"; +import { Cache } from "@/misc/cache.js"; const router = new Router(); -const nodeinfo2_1path = '/nodeinfo/2.1'; -const nodeinfo2_0path = '/nodeinfo/2.0'; +const nodeinfo2_1path = "/nodeinfo/2.1"; +const nodeinfo2_0path = "/nodeinfo/2.0"; -export const links = [{ - rel: 'https://nodeinfo.diaspora.software/ns/schema/2.1', - href: config.url + nodeinfo2_1path -}, { - rel: 'https://nodeinfo.diaspora.software/ns/schema/2.0', - href: config.url + nodeinfo2_0path, -}]; +// to cleo: leave this http or bonks +export const links = [ + { + rel: "http://nodeinfo.diaspora.software/ns/schema/2.1", + href: config.url + nodeinfo2_1path, + }, + { + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: config.url + nodeinfo2_0path, + }, +]; const nodeinfo2 = async () => { const now = Date.now(); - const [ - meta, - total, - activeHalfyear, - activeMonth, - localPosts, - ] = await Promise.all([ - fetchMeta(true), - Users.count({ where: { host: IsNull() } }), - Users.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 15552000000)) } }), - Users.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 2592000000)) } }), - Notes.count({ where: { userHost: IsNull() } }), - ]); + const [meta, total, activeHalfyear, activeMonth, localPosts] = + await Promise.all([ + fetchMeta(true), + Users.count({ where: { host: IsNull() } }), + Users.count({ + where: { + host: IsNull(), + lastActiveDate: MoreThan(new Date(now - 15552000000)), + }, + }), + Users.count({ + where: { + host: IsNull(), + lastActiveDate: MoreThan(new Date(now - 2592000000)), + }, + }), + Notes.count({ where: { userHost: IsNull() } }), + ]); - const proxyAccount = meta.proxyAccountId ? await Users.pack(meta.proxyAccountId).catch(() => null) : null; + const proxyAccount = meta.proxyAccountId + ? await Users.pack(meta.proxyAccountId).catch(() => null) + : null; return { software: { - name: 'calckey', + name: "calckey", version: config.version, repository: meta.repositoryUrl, + homepage: "https://calckey.cloud", }, - protocols: ['activitypub'], + protocols: ["activitypub"], services: { inbound: [] as string[], - outbound: ['atom1.0', 'rss2.0'], + outbound: ["atom1.0", "rss2.0"], }, openRegistrations: !meta.disableRegistration, usage: { @@ -79,28 +91,28 @@ const nodeinfo2 = async () => { enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, proxyAccountName: proxyAccount ? proxyAccount.username : null, - themeColor: meta.themeColor || '#31748f', + themeColor: meta.themeColor || "#31748f", }, }; }; const cache = new Cache>>(1000 * 60 * 10); -router.get(nodeinfo2_1path, async ctx => { +router.get(nodeinfo2_1path, async (ctx) => { const base = await cache.fetch(null, () => nodeinfo2()); - ctx.body = { version: '2.1', ...base }; - ctx.set('Cache-Control', 'public, max-age=600'); + ctx.body = { version: "2.1", ...base }; + ctx.set("Cache-Control", "public, max-age=600"); }); -router.get(nodeinfo2_0path, async ctx => { +router.get(nodeinfo2_0path, async (ctx) => { const base = await cache.fetch(null, () => nodeinfo2()); // @ts-ignore - delete base.software.repository; + base.software.repository = undefined; - ctx.body = { version: '2.0', ...base }; - ctx.set('Cache-Control', 'public, max-age=600'); + ctx.body = { version: "2.0", ...base }; + ctx.set("Cache-Control", "public, max-age=600"); }); export default router; diff --git a/packages/backend/src/server/proxy/index.ts b/packages/backend/src/server/proxy/index.ts index 506ba10ef..004b3779f 100644 --- a/packages/backend/src/server/proxy/index.ts +++ b/packages/backend/src/server/proxy/index.ts @@ -2,23 +2,26 @@ * Media Proxy */ -import Koa from 'koa'; -import cors from '@koa/cors'; -import Router from '@koa/router'; -import { proxyMedia } from './proxy-media.js'; +import Koa from "koa"; +import cors from "@koa/cors"; +import Router from "@koa/router"; +import { proxyMedia } from "./proxy-media.js"; // Init app const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); + ctx.set( + "Content-Security-Policy", + `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`, + ); await next(); }); // Init router const router = new Router(); -router.get('/:url*', proxyMedia); +router.get("/:url*", proxyMedia); // Register router app.use(router.routes()); diff --git a/packages/backend/src/server/proxy/proxy-media.ts b/packages/backend/src/server/proxy/proxy-media.ts index ca036e8fd..a9c257bfe 100644 --- a/packages/backend/src/server/proxy/proxy-media.ts +++ b/packages/backend/src/server/proxy/proxy-media.ts @@ -1,20 +1,20 @@ -import * as fs from 'node:fs'; -import Koa from 'koa'; -import sharp from 'sharp'; -import { IImage, convertToWebp } from '@/services/drive/image-processor.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { downloadUrl } from '@/misc/download-url.js'; -import { detectType } from '@/misc/get-file-info.js'; -import { StatusError } from '@/misc/fetch.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; -import { serverLogger } from '../index.js'; -import { isMimeImage } from '@/misc/is-mime-image.js'; +import * as fs from "node:fs"; +import type Koa from "koa"; +import sharp from "sharp"; +import type { IImage } from "@/services/drive/image-processor.js"; +import { convertToWebp } from "@/services/drive/image-processor.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { downloadUrl } from "@/misc/download-url.js"; +import { detectType } from "@/misc/get-file-info.js"; +import { StatusError } from "@/misc/fetch.js"; +import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; +import { serverLogger } from "../index.js"; +import { isMimeImage } from "@/misc/is-mime-image.js"; -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export async function proxyMedia(ctx: Koa.Context) { - const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url; + const url = "url" in ctx.query ? ctx.query.url : `https://${ctx.params.url}`; - if (typeof url !== 'string') { + if (typeof url !== "string") { ctx.status = 400; return; } @@ -26,53 +26,60 @@ export async function proxyMedia(ctx: Koa.Context) { await downloadUrl(url, path); const { mime, ext } = await detectType(path); - const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image'); + const isConvertibleImage = isMimeImage(mime, "sharp-convertible-image"); let image: IImage; - if ('static' in ctx.query && isConvertibleImage) { - image = await convertToWebp(path, 498, 280); - } else if ('preview' in ctx.query && isConvertibleImage) { - image = await convertToWebp(path, 200, 200); - } else if ('badge' in ctx.query) { + if ("static" in ctx.query && isConvertibleImage) { + image = await convertToWebp(path, 996, 560); + } else if ("preview" in ctx.query && isConvertibleImage) { + image = await convertToWebp(path, 400, 400); + } else if ("badge" in ctx.query) { if (!isConvertibleImage) { // 画像でないなら404でお茶を濁す - throw new StatusError('Unexpected mime', 404); + throw new StatusError("Unexpected mime", 404); } const mask = sharp(path) .resize(96, 96, { - fit: 'inside', + fit: "inside", withoutEnlargement: false, }) .greyscale() .normalise() .linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast - .flatten({ background: '#000' }) - .toColorspace('b-w'); + .flatten({ background: "#000" }) + .toColorspace("b-w"); const stats = await mask.clone().stats(); if (stats.entropy < 0.1) { // エントロピーがあまりない場合は404にする - throw new StatusError('Skip to provide badge', 404); + throw new StatusError("Skip to provide badge", 404); } const data = sharp({ - create: { width: 96, height: 96, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } }, + create: { + width: 96, + height: 96, + channels: 4, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }, }) - .pipelineColorspace('b-w') - .boolean(await mask.png().toBuffer(), 'eor'); + .pipelineColorspace("b-w") + .boolean(await mask.png().toBuffer(), "eor"); image = { data: await data.png().toBuffer(), - ext: 'png', - type: 'image/png', + ext: "png", + type: "image/png", }; - } else if (mime === 'image/svg+xml') { + } else if (mime === "image/svg+xml") { image = await convertToWebp(path, 2048, 2048, 1); - } else if (!mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(mime)) { - throw new StatusError('Rejected type', 403, 'Rejected type'); + } else if ( + !(mime.startsWith("image/") && FILE_TYPE_BROWSERSAFE.includes(mime)) + ) { + throw new StatusError("Rejected type", 403, "Rejected type"); } else { image = { data: fs.readFileSync(path), @@ -81,8 +88,8 @@ export async function proxyMedia(ctx: Koa.Context) { }; } - ctx.set('Content-Type', image.type); - ctx.set('Cache-Control', 'max-age=31536000, immutable'); + ctx.set("Content-Type", image.type); + ctx.set("Cache-Control", "max-age=31536000, immutable"); ctx.body = image.data; } catch (e) { serverLogger.error(`${e}`); diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index 9da4cfb16..f4e0707a9 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -281,7 +281,6 @@ `) } - // eslint-disable-next-line no-inner-declarations async function checkUpdate() { try { const res = await fetch('/api/meta', { @@ -302,7 +301,6 @@ } } - // eslint-disable-next-line no-inner-declarations function refresh() { // Clear cache (service worker) try { diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index 157ef54ae..9cbeb28ae 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -1,10 +1,10 @@ -import { Feed } from 'feed'; -import { In, IsNull } from 'typeorm'; -import config from '@/config/index.js'; -import { User } from '@/models/entities/user.js'; -import { Notes, DriveFiles, UserProfiles, Users } from '@/models/index.js'; +import { Feed } from "feed"; +import { In, IsNull } from "typeorm"; +import config from "@/config/index.js"; +import type { User } from "@/models/entities/user.js"; +import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js"; -export default async function(user: User) { +export default async function (user: User) { const author = { link: `${config.url}/@${user.username}`, name: user.name || user.username, @@ -16,7 +16,7 @@ export default async function(user: User) { where: { userId: user.id, renoteId: IsNull(), - visibility: In(['public', 'home']), + visibility: In(["public", "home"]), }, order: { createdAt: -1 }, take: 20, @@ -26,8 +26,12 @@ export default async function(user: User) { id: author.link, title: `${author.name} (@${user.username}@${config.host})`, updated: notes[0].createdAt, - generator: 'Calckey', - description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, + generator: "Calckey", + description: `${user.notesCount} Notes, ${ + profile.ffVisibility === "public" ? user.followingCount : "?" + } Following, ${ + profile.ffVisibility === "public" ? user.followersCount : "?" + } Followers${profile.description ? ` · ${profile.description}` : ""}`, link: author.link, image: await Users.getAvatarUrl(user), feedLinks: { @@ -39,10 +43,13 @@ export default async function(user: User) { }); for (const note of notes) { - const files = note.fileIds.length > 0 ? await DriveFiles.findBy({ - id: In(note.fileIds), - }) : []; - const file = files.find(file => file.type.startsWith('image/')); + const files = + note.fileIds.length > 0 + ? await DriveFiles.findBy({ + id: In(note.fileIds), + }) + : []; + const file = files.find((file) => file.type.startsWith("image/")); feed.addItem({ title: `New note by ${author.name}`, diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 446df1554..4ae8e5bfd 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -2,31 +2,39 @@ * Web Client Server */ -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { readFileSync } from 'node:fs'; -import Koa from 'koa'; -import Router from '@koa/router'; -import send from 'koa-send'; -import favicon from 'koa-favicon'; -import views from 'koa-views'; -import sharp from 'sharp'; -import { createBullBoard } from '@bull-board/api'; -import { BullAdapter } from '@bull-board/api/bullAdapter.js'; -import { KoaAdapter } from '@bull-board/koa'; +import { dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { readFileSync } from "node:fs"; +import Koa from "koa"; +import Router from "@koa/router"; +import send from "koa-send"; +import favicon from "koa-favicon"; +import views from "koa-views"; +import sharp from "sharp"; +import { createBullBoard } from "@bull-board/api"; +import { BullAdapter } from "@bull-board/api/bullAdapter.js"; +import { KoaAdapter } from "@bull-board/koa"; -import { In, IsNull } from 'typeorm'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import config from '@/config/index.js'; -import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js'; -import * as Acct from '@/misc/acct.js'; -import { getNoteSummary } from '@/misc/get-note-summary.js'; -import { queues } from '@/queue/queues.js'; -import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; -import { urlPreviewHandler } from './url-preview.js'; -import { manifestHandler } from './manifest.js'; -import packFeed from './feed.js'; -import { MINUTE, DAY } from '@/const.js'; +import { In, IsNull } from "typeorm"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import config from "@/config/index.js"; +import { + Users, + Notes, + UserProfiles, + Pages, + Channels, + Clips, + GalleryPosts, +} from "@/models/index.js"; +import * as Acct from "@/misc/acct.js"; +import { getNoteSummary } from "@/misc/get-note-summary.js"; +import { queues } from "@/queue/queues.js"; +import { genOpenapiSpec } from "../api/openapi/gen-spec.js"; +import { urlPreviewHandler } from "./url-preview.js"; +import { manifestHandler } from "./manifest.js"; +import packFeed from "./feed.js"; +import { MINUTE, DAY } from "@/const.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -40,12 +48,12 @@ const swAssets = `${_dirname}/../../../../../built/_sw_dist_/`; const app = new Koa(); //#region Bull Dashboard -const bullBoardPath = '/queue'; +const bullBoardPath = "/queue"; // Authenticate app.use(async (ctx, next) => { - if (ctx.path === bullBoardPath || ctx.path.startsWith(bullBoardPath + '/')) { - const token = ctx.cookies.get('token'); + if (ctx.path === bullBoardPath || ctx.path.startsWith(`${bullBoardPath}/`)) { + const token = ctx.cookies.get("token"); if (token == null) { ctx.status = 401; return; @@ -62,7 +70,7 @@ app.use(async (ctx, next) => { const serverAdapter = new KoaAdapter(); createBullBoard({ - queues: queues.map(q => new BullAdapter(q)), + queues: queues.map((q) => new BullAdapter(q)), serverAdapter, }); @@ -71,16 +79,24 @@ app.use(serverAdapter.registerPlugin()); //#endregion // Init renderer -app.use(views(_dirname + '/views', { - extension: 'pug', - options: { - version: config.version, - getClientEntry: () => process.env.NODE_ENV === 'production' ? - config.clientEntry : - JSON.parse(readFileSync(`${_dirname}/../../../../../built/_client_dist_/manifest.json`, 'utf-8'))['src/init.ts'], - config, - }, -})); +app.use( + views(`${_dirname}/views`, { + extension: "pug", + options: { + version: config.version, + getClientEntry: () => + process.env.NODE_ENV === "production" + ? config.clientEntry + : JSON.parse( + readFileSync( + `${_dirname}/../../../../../built/_client_dist_/manifest.json`, + "utf-8", + ), + )["src/init.ts"], + config, + }, + }), +); // Serve favicon app.use(favicon(`${_dirname}/../../../assets/favicon.ico`)); @@ -88,7 +104,7 @@ app.use(favicon(`${_dirname}/../../../assets/favicon.ico`)); // Common request handler app.use(async (ctx, next) => { // IFrameの中に入れられないようにする - ctx.set('X-Frame-Options', 'DENY'); + ctx.set("X-Frame-Options", "DENY"); await next(); }); @@ -97,43 +113,46 @@ const router = new Router(); //#region static assets -router.get('/static-assets/(.*)', async ctx => { - await send(ctx as any, ctx.path.replace('/static-assets/', ''), { +router.get("/static-assets/(.*)", async (ctx) => { + await send(ctx as any, ctx.path.replace("/static-assets/", ""), { root: staticAssets, maxage: 7 * DAY, }); }); -router.get('/client-assets/(.*)', async ctx => { - await send(ctx as any, ctx.path.replace('/client-assets/', ''), { +router.get("/client-assets/(.*)", async (ctx) => { + await send(ctx as any, ctx.path.replace("/client-assets/", ""), { root: clientAssets, maxage: 7 * DAY, }); }); -router.get('/assets/(.*)', async ctx => { - await send(ctx as any, ctx.path.replace('/assets/', ''), { +router.get("/assets/(.*)", async (ctx) => { + await send(ctx as any, ctx.path.replace("/assets/", ""), { root: assets, maxage: 7 * DAY, }); }); // Apple touch icon -router.get('/apple-touch-icon.png', async ctx => { - await send(ctx as any, '/apple-touch-icon.png', { +router.get("/apple-touch-icon.png", async (ctx) => { + await send(ctx as any, "/apple-touch-icon.png", { root: staticAssets, }); }); -router.get('/twemoji/(.*)', async ctx => { - const path = ctx.path.replace('/twemoji/', ''); +router.get("/twemoji/(.*)", async (ctx) => { + const path = ctx.path.replace("/twemoji/", ""); if (!path.match(/^[0-9a-f-]+\.svg$/)) { ctx.status = 404; return; } - ctx.set('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); + ctx.set( + "Content-Security-Policy", + "default-src 'none'; style-src 'unsafe-inline'", + ); await send(ctx as any, path, { root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`, @@ -141,8 +160,8 @@ router.get('/twemoji/(.*)', async ctx => { }); }); -router.get('/twemoji-badge/(.*)', async ctx => { - const path = ctx.path.replace('/twemoji-badge/', ''); +router.get("/twemoji-badge/(.*)", async (ctx) => { + const path = ctx.path.replace("/twemoji-badge/", ""); if (!path.match(/^[0-9a-f-]+\.png$/)) { ctx.status = 404; @@ -150,53 +169,64 @@ router.get('/twemoji-badge/(.*)', async ctx => { } const mask = await sharp( - `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/${path.replace('.png', '')}.svg`, + `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/${path.replace( + ".png", + "", + )}.svg`, { density: 1000 }, ) .resize(488, 488) .greyscale() .normalise() .linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast - .flatten({ background: '#000' }) + .flatten({ background: "#000" }) .extend({ top: 12, bottom: 12, left: 12, right: 12, - background: '#000', + background: "#000", }) - .toColorspace('b-w') + .toColorspace("b-w") .png() .toBuffer(); const buffer = await sharp({ - create: { width: 512, height: 512, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } }, + create: { + width: 512, + height: 512, + channels: 4, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }, }) - .pipelineColorspace('b-w') - .boolean(mask, 'eor') + .pipelineColorspace("b-w") + .boolean(mask, "eor") .resize(96, 96) .png() .toBuffer(); - ctx.set('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); - ctx.set('Cache-Control', 'max-age=2592000'); - ctx.set('Content-Type', 'image/png'); + ctx.set( + "Content-Security-Policy", + "default-src 'none'; style-src 'unsafe-inline'", + ); + ctx.set("Cache-Control", "max-age=2592000"); + ctx.set("Content-Type", "image/png"); ctx.body = buffer; }); // ServiceWorker -router.get(`/sw.js`, async ctx => { - await send(ctx as any, `/sw.js`, { +router.get("/sw.js", async (ctx) => { + await send(ctx as any, "/sw.js", { root: swAssets, maxage: 10 * MINUTE, }); }); // Manifest -router.get('/manifest.json', manifestHandler); +router.get("/manifest.json", manifestHandler); -router.get('/robots.txt', async ctx => { - await send(ctx as any, '/robots.txt', { +router.get("/robots.txt", async (ctx) => { + await send(ctx as any, "/robots.txt", { root: staticAssets, }); }); @@ -204,16 +234,16 @@ router.get('/robots.txt', async ctx => { //#endregion // Docs -router.get('/api-doc', async ctx => { - await send(ctx as any, '/redoc.html', { +router.get("/api-doc", async (ctx) => { + await send(ctx as any, "/redoc.html", { root: staticAssets, }); }); // URL preview endpoint -router.get('/url', urlPreviewHandler); +router.get("/url", urlPreviewHandler); -router.get('/api.json', async ctx => { +router.get("/api.json", async (ctx) => { ctx.body = genOpenapiSpec(); }); @@ -229,11 +259,13 @@ const getFeed = async (acct: string) => { isSuspended: false, }); - return user && await packFeed(user); + return user && (await packFeed(user)); }; // As the /@user[.json|.rss|.atom]/sub endpoint is complicated, we will use a regex to switch between them. -const reUser = new RegExp(`^/@(?[^/]+?)(?:\.(?json|rss|atom))?(?:/(?[^/]+))?$`); +const reUser = new RegExp( + "^/@(?[^/]+?)(?:.(?json|rss|atom))?(?:/(?[^/]+))?$", +); router.get(reUser, async (ctx, next) => { const groups = reUser.exec(ctx.originalUrl)?.groups; if (!groups) { @@ -243,7 +275,7 @@ router.get(reUser, async (ctx, next) => { ctx.params = groups; - console.log(ctx, ctx.params) + console.log(ctx, ctx.params); if (groups.feed) { if (groups.sub) { await next(); @@ -251,13 +283,13 @@ router.get(reUser, async (ctx, next) => { } switch (groups.feed) { - case 'json': + case "json": await jsonFeed(ctx, next); break; - case 'rss': + case "rss": await rssFeed(ctx, next); break; - case 'atom': + case "atom": await atomFeed(ctx, next); break; } @@ -268,11 +300,11 @@ router.get(reUser, async (ctx, next) => { }); // Atom -const atomFeed: Router.Middleware = async ctx => { +const atomFeed: Router.Middleware = async (ctx) => { const feed = await getFeed(ctx.params.user); if (feed) { - ctx.set('Content-Type', 'application/atom+xml; charset=utf-8'); + ctx.set("Content-Type", "application/atom+xml; charset=utf-8"); ctx.body = feed.atom1(); } else { ctx.status = 404; @@ -280,11 +312,11 @@ const atomFeed: Router.Middleware = async ctx => { }; // RSS -const rssFeed: Router.Middleware = async ctx => { +const rssFeed: Router.Middleware = async (ctx) => { const feed = await getFeed(ctx.params.user); if (feed) { - ctx.set('Content-Type', 'application/rss+xml; charset=utf-8'); + ctx.set("Content-Type", "application/rss+xml; charset=utf-8"); ctx.body = feed.rss2(); } else { ctx.status = 404; @@ -292,11 +324,11 @@ const rssFeed: Router.Middleware = async ctx => { }; // JSON -const jsonFeed: Router.Middleware = async ctx => { +const jsonFeed: Router.Middleware = async (ctx) => { const feed = await getFeed(ctx.params.user); if (feed) { - ctx.set('Content-Type', 'application/json; charset=utf-8'); + ctx.set("Content-Type", "application/json; charset=utf-8"); ctx.body = feed.json1(); } else { ctx.status = 404; @@ -325,25 +357,27 @@ const userPage: Router.Middleware = async (ctx, next) => { const meta = await fetchMeta(); const me = profile.fields ? profile.fields - .filter(filed => filed.value != null && filed.value.match(/^https?:/)) - .map(field => field.value) + .filter((filed) => filed.value?.match(/^https?:/)) + .map((field) => field.value) : []; const userDetail = { - user, profile, me, + user, + profile, + me, avatarUrl: await Users.getAvatarUrl(user), sub: subParam, - instanceName: meta.name || 'Calckey', + instanceName: meta.name || "Calckey", icon: meta.iconUrl, themeColor: meta.themeColor, privateMode: meta.privateMode, }; - await ctx.render('user', userDetail); - ctx.set('Cache-Control', 'public, max-age=15'); + await ctx.render("user", userDetail); + ctx.set("Cache-Control", "public, max-age=15"); }; -router.get('/users/:user', async ctx => { +router.get("/users/:user", async (ctx) => { const user = await Users.findOneBy({ id: ctx.params.user, host: IsNull(), @@ -355,33 +389,67 @@ router.get('/users/:user', async ctx => { return; } - ctx.redirect(`/@${user.username}${ user.host == null ? '' : '@' + user.host}`); + ctx.redirect(`/@${user.username}${user.host == null ? "" : `@${user.host}`}`); }); // Note -router.get('/notes/:note', async (ctx, next) => { +router.get("/notes/:note", async (ctx, next) => { const note = await Notes.findOneBy({ id: ctx.params.note, - visibility: In(['public', 'home']), + visibility: In(["public", "home"]), }); if (note) { const _note = await Notes.pack(note); const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); const meta = await fetchMeta(); - await ctx.render('note', { + await ctx.render("note", { note: _note, profile, - avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: note.userId })), + avatarUrl: await Users.getAvatarUrl( + await Users.findOneByOrFail({ id: note.userId }), + ), // TODO: Let locale changeable by instance setting summary: getNoteSummary(_note), - instanceName: meta.name || 'Calckey', + instanceName: meta.name || "Calckey", icon: meta.iconUrl, privateMode: meta.privateMode, themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=15'); + ctx.set("Cache-Control", "public, max-age=15"); + + return; + } + + await next(); +}); + +router.get("/posts/:note", async (ctx, next) => { + const note = await Notes.findOneBy({ + id: ctx.params.note, + visibility: In(["public", "home"]), + }); + + if (note) { + const _note = await Notes.pack(note); + const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); + const meta = await fetchMeta(); + await ctx.render("note", { + note: _note, + profile, + avatarUrl: await Users.getAvatarUrl( + await Users.findOneByOrFail({ id: note.userId }), + ), + // TODO: Let locale changeable by instance setting + summary: getNoteSummary(_note), + instanceName: meta.name || "Calckey", + icon: meta.iconUrl, + privateMode: meta.privateMode, + themeColor: meta.themeColor, + }); + + ctx.set("Cache-Control", "public, max-age=15"); return; } @@ -390,7 +458,7 @@ router.get('/notes/:note', async (ctx, next) => { }); // Page -router.get('/@:user/pages/:page', async (ctx, next) => { +router.get("/@:user/pages/:page", async (ctx, next) => { const { username, host } = Acct.parse(ctx.params.user); const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), @@ -408,20 +476,22 @@ router.get('/@:user/pages/:page', async (ctx, next) => { const _page = await Pages.pack(page); const profile = await UserProfiles.findOneByOrFail({ userId: page.userId }); const meta = await fetchMeta(); - await ctx.render('page', { + await ctx.render("page", { page: _page, profile, - avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: page.userId })), - instanceName: meta.name || 'Calckey', + avatarUrl: await Users.getAvatarUrl( + await Users.findOneByOrFail({ id: page.userId }), + ), + instanceName: meta.name || "Calckey", icon: meta.iconUrl, themeColor: meta.themeColor, privateMode: meta.privateMode, }); - if (['public'].includes(page.visibility)) { - ctx.set('Cache-Control', 'public, max-age=15'); + if (["public"].includes(page.visibility)) { + ctx.set("Cache-Control", "public, max-age=15"); } else { - ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } return; @@ -431,8 +501,8 @@ router.get('/@:user/pages/:page', async (ctx, next) => { }); // Clip -// TODO: 非publicなclipのハンドリング -router.get('/clips/:clip', async (ctx, next) => { +// TODO: handling of private clips +router.get("/clips/:clip", async (ctx, next) => { const clip = await Clips.findOneBy({ id: ctx.params.clip, }); @@ -441,17 +511,19 @@ router.get('/clips/:clip', async (ctx, next) => { const _clip = await Clips.pack(clip); const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId }); const meta = await fetchMeta(); - await ctx.render('clip', { + await ctx.render("clip", { clip: _clip, profile, - avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: clip.userId })), - instanceName: meta.name || 'Calckey', + avatarUrl: await Users.getAvatarUrl( + await Users.findOneByOrFail({ id: clip.userId }), + ), + instanceName: meta.name || "Calckey", privateMode: meta.privateMode, icon: meta.iconUrl, themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=15'); + ctx.set("Cache-Control", "public, max-age=15"); return; } @@ -460,24 +532,26 @@ router.get('/clips/:clip', async (ctx, next) => { }); // Gallery post -router.get('/gallery/:post', async (ctx, next) => { +router.get("/gallery/:post", async (ctx, next) => { const post = await GalleryPosts.findOneBy({ id: ctx.params.post }); if (post) { const _post = await GalleryPosts.pack(post); const profile = await UserProfiles.findOneByOrFail({ userId: post.userId }); const meta = await fetchMeta(); - await ctx.render('gallery-post', { + await ctx.render("gallery-post", { post: _post, profile, - avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: post.userId })), - instanceName: meta.name || 'Calckey', + avatarUrl: await Users.getAvatarUrl( + await Users.findOneByOrFail({ id: post.userId }), + ), + instanceName: meta.name || "Calckey", icon: meta.iconUrl, themeColor: meta.themeColor, privateMode: meta.privateMode, }); - ctx.set('Cache-Control', 'public, max-age=15'); + ctx.set("Cache-Control", "public, max-age=15"); return; } @@ -486,7 +560,7 @@ router.get('/gallery/:post', async (ctx, next) => { }); // Channel -router.get('/channels/:channel', async (ctx, next) => { +router.get("/channels/:channel", async (ctx, next) => { const channel = await Channels.findOneBy({ id: ctx.params.channel, }); @@ -494,15 +568,15 @@ router.get('/channels/:channel', async (ctx, next) => { if (channel) { const _channel = await Channels.pack(channel); const meta = await fetchMeta(); - await ctx.render('channel', { + await ctx.render("channel", { channel: _channel, - instanceName: meta.name || 'Calckey', + instanceName: meta.name || "Calckey", icon: meta.iconUrl, themeColor: meta.themeColor, privateMode: meta.privateMode, }); - ctx.set('Cache-Control', 'public, max-age=15'); + ctx.set("Cache-Control", "public, max-age=15"); return; } @@ -511,16 +585,16 @@ router.get('/channels/:channel', async (ctx, next) => { }); //#endregion -router.get('/_info_card_', async ctx => { +router.get("/_info_card_", async (ctx) => { const meta = await fetchMeta(true); if (meta.privateMode) { ctx.status = 403; return; } - ctx.remove('X-Frame-Options'); + ctx.remove("X-Frame-Options"); - await ctx.render('info-card', { + await ctx.render("info-card", { version: config.version, host: config.host, meta: meta, @@ -529,46 +603,56 @@ router.get('/_info_card_', async ctx => { }); }); -router.get('/bios', async ctx => { - await ctx.render('bios', { +router.get("/bios", async (ctx) => { + await ctx.render("bios", { version: config.version, }); }); -router.get('/cli', async ctx => { - await ctx.render('cli', { +router.get("/cli", async (ctx) => { + await ctx.render("cli", { version: config.version, }); }); const override = (source: string, target: string, depth = 0) => - [, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); + [ + undefined, + ...target.split("/").filter((x) => x), + ...source + .split("/") + .filter((x) => x) + .splice(depth), + ].join("/"); -router.get('/flush', async ctx => { - await ctx.render('flush'); +router.get("/flush", async (ctx) => { + await ctx.render("flush"); }); -// streamingに非WebSocketリクエストが来た場合にbase htmlをキャシュ付きで返すと、Proxy等でそのパスがキャッシュされておかしくなる -router.get('/streaming', async ctx => { +// If a non-WebSocket request comes in to streaming and base html is returned with cache, the path will be cached by Proxy, etc. and it will be wrong. +router.get("/streaming", async (ctx) => { ctx.status = 503; - ctx.set('Cache-Control', 'private, max-age=0'); + ctx.set("Cache-Control", "private, max-age=0"); }); // Render base html for all requests -router.get('(.*)', async ctx => { +router.get("(.*)", async (ctx) => { const meta = await fetchMeta(); - let motd = ['Loading...']; + let motd = ["Loading..."]; if (meta.customMOTD.length > 0) { motd = meta.customMOTD; } let splashIconUrl = meta.iconUrl; if (meta.customSplashIcons.length > 0) { - splashIconUrl = meta.customSplashIcons[Math.floor(Math.random() * meta.customSplashIcons.length)]; + splashIconUrl = + meta.customSplashIcons[ + Math.floor(Math.random() * meta.customSplashIcons.length) + ]; } - await ctx.render('base', { + await ctx.render("base", { img: meta.bannerUrl, - title: meta.name || 'Calckey', - instanceName: meta.name || 'Calckey', + title: meta.name || "Calckey", + instanceName: meta.name || "Calckey", desc: meta.description, icon: meta.iconUrl, splashIcon: splashIconUrl, @@ -576,7 +660,7 @@ router.get('(.*)', async ctx => { randomMOTD: motd[Math.floor(Math.random() * motd.length)], privateMode: meta.privateMode, }); - ctx.set('Cache-Control', 'public, max-age=3'); + ctx.set("Cache-Control", "public, max-age=3"); }); // Register router diff --git a/packages/backend/src/server/web/manifest.json b/packages/backend/src/server/web/manifest.json index 2f053fdc4..1e662fb20 100644 --- a/packages/backend/src/server/web/manifest.json +++ b/packages/backend/src/server/web/manifest.json @@ -11,12 +11,26 @@ { "src": "/static-assets/icons/192.png", "sizes": "192x192", - "type": "image/png" + "type": "image/png", + "purpose": "any" }, { "src": "/static-assets/icons/512.png", "sizes": "512x512", - "type": "image/png" + "type": "image/png", + "purpose": "any" + }, + { + "src": "/static-assets/icons/maskable.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/static-assets/icons/monochrome.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "monochrome" } ], "share_target": { @@ -53,5 +67,8 @@ "name": "Chats", "url": "/my/messaging" } - ] + ], + "categories": [ + "social" + ] } diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts index 36dfbbf42..31acc42f6 100644 --- a/packages/backend/src/server/web/manifest.ts +++ b/packages/backend/src/server/web/manifest.ts @@ -1,6 +1,6 @@ -import Koa from 'koa'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import manifest from './manifest.json' assert { type: 'json' }; +import type Koa from "koa"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import manifest from "./manifest.json" assert { type: "json" }; export const manifestHandler = async (ctx: Koa.Context) => { // TODO @@ -9,10 +9,10 @@ export const manifestHandler = async (ctx: Koa.Context) => { const instance = await fetchMeta(true); - res.short_name = instance.name || 'Calckey'; - res.name = instance.name || 'Calckey'; + res.short_name = instance.name || "Calckey"; + res.name = instance.name || "Calckey"; if (instance.themeColor) res.theme_color = instance.themeColor; - ctx.set('Cache-Control', 'max-age=300'); + ctx.set("Cache-Control", "max-age=300"); ctx.body = res; }; diff --git a/packages/backend/src/server/web/url-preview.ts b/packages/backend/src/server/web/url-preview.ts index 1e259649f..d7da4e72c 100644 --- a/packages/backend/src/server/web/url-preview.ts +++ b/packages/backend/src/server/web/url-preview.ts @@ -1,16 +1,16 @@ -import Koa from 'koa'; -import summaly from 'summaly'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import Logger from '@/services/logger.js'; -import config from '@/config/index.js'; -import { query } from '@/prelude/url.js'; -import { getJson } from '@/misc/fetch.js'; +import type Koa from "koa"; +import summaly from "summaly"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import Logger from "@/services/logger.js"; +import config from "@/config/index.js"; +import { query } from "@/prelude/url.js"; +import { getJson } from "@/misc/fetch.js"; -const logger = new Logger('url-preview'); +const logger = new Logger("url-preview"); export const urlPreviewHandler = async (ctx: Koa.Context) => { const url = ctx.query.url; - if (typeof url !== 'string') { + if (typeof url !== "string") { ctx.status = 400; return; } @@ -23,18 +23,24 @@ export const urlPreviewHandler = async (ctx: Koa.Context) => { const meta = await fetchMeta(); - logger.info(meta.summalyProxy - ? `(Proxy) Getting preview of ${url}@${lang} ...` - : `Getting preview of ${url}@${lang} ...`); + logger.info( + meta.summalyProxy + ? `(Proxy) Getting preview of ${url}@${lang} ...` + : `Getting preview of ${url}@${lang} ...`, + ); try { - const summary = meta.summalyProxy ? await getJson(`${meta.summalyProxy}?${query({ - url: url, - lang: lang ?? 'ja-JP', - })}`) : await summaly.default(url, { - followRedirects: false, - lang: lang ?? 'ja-JP', - }); + const summary = meta.summalyProxy + ? await getJson( + `${meta.summalyProxy}?${query({ + url: url, + lang: lang ?? "en-US", + })}`, + ) + : await summaly.default(url, { + followRedirects: false, + lang: lang ?? "en-US", + }); logger.succ(`Got preview of ${url}: ${summary.title}`); @@ -42,14 +48,14 @@ export const urlPreviewHandler = async (ctx: Koa.Context) => { summary.thumbnail = wrap(summary.thumbnail); // Cache 7days - ctx.set('Cache-Control', 'max-age=604800, immutable'); + ctx.set("Cache-Control", "max-age=604800, immutable"); ctx.body = summary; } catch (err) { logger.warn(`Failed to get preview of ${url}: ${err}`); ctx.status = 200; - ctx.set('Cache-Control', 'max-age=86400, immutable'); - ctx.body = '{}'; + ctx.set("Cache-Control", "max-age=86400, immutable"); + ctx.body = "{}"; } }; @@ -57,9 +63,9 @@ function wrap(url?: string): string | null { return url != null ? url.match(/^https?:\/\//) ? `${config.url}/proxy/preview.webp?${query({ - url, - preview: '1', - })}` + url, + preview: "1", + })}` : url : null; } diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 25c2cb38e..b5841883b 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -50,16 +50,17 @@ html = title || 'Calckey' block desc - meta(name='description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') + meta(name='description' content=desc || 'An open source, decentralized social media platform that\'s free forever! 🚀') block meta if privateMode meta(name='robots' content='noindex') block og - meta(property='og:title' content= title || 'Calckey') - meta(property='og:description' content= desc || '✨🌎 A interplanetary communication platform 🚀✨') - meta(property='og:image' content= img) + meta(property='og:title' content=title || 'Calckey') + meta(property='og:description' content=desc || 'An open source, decentralized social media platform that\'s free forever! 🚀') + meta(property='og:image' content=img) + meta(property='og:image:alt' content=alt || 'Pfp') style include ../style.css diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 6b55f6ba0..b2dc5f63f 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -5,6 +5,9 @@ block vars - const title = privateMode ? instanceName : (user.name ? `${user.name} (@${user.username})` : `@${user.username}`); - const url = `${config.url}/notes/${note.id}`; - const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null; + - const isImage = note.files.length !== 0 && note.files[0].type.startsWith('image'); + - const isVideo = note.files.length !== 0 && note.files[0].type.startsWith('video'); + - const imageUrl = isImage ? note.files[0].url : isVideo ? note.files[0].thumbnailUrl : avatarUrl; block title = `${title} | ${instanceName}` @@ -19,7 +22,15 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= summary) meta(property='og:url' content= url) - meta(property='og:image' content= avatarUrl) + meta(property='og:image' content= imageUrl) + if isImage + meta(property='og:image:width' content=note.files[0].properties.width) + meta(property='og:image:height' content=note.files[0].properties.height) + meta(property='og:image:type' content=note.files[0].type) + meta(property='twitter:card' content="summary_large_image") + if isVideo + meta(property='og:video:type' content=note.files[0].type) + meta(property='og:video' content=note.files[0].url) block meta unless privateMode diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts index 1d094f2ed..5af3b2c84 100644 --- a/packages/backend/src/server/well-known.ts +++ b/packages/backend/src/server/well-known.ts @@ -1,64 +1,96 @@ -import Router from '@koa/router'; +import Router from "@koa/router"; -import config from '@/config/index.js'; -import * as Acct from '@/misc/acct.js'; -import { links } from './nodeinfo.js'; -import { escapeAttribute, escapeValue } from '@/prelude/xml.js'; -import { Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { FindOptionsWhere, IsNull } from 'typeorm'; +import config from "@/config/index.js"; +import * as Acct from "@/misc/acct.js"; +import { links } from "./nodeinfo.js"; +import { escapeAttribute, escapeValue } from "@/prelude/xml.js"; +import { Users } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import type { FindOptionsWhere } from "typeorm"; +import { IsNull } from "typeorm"; // Init router const router = new Router(); -const XRD = (...x: { element: string, value?: string, attributes?: Record }[]) => - `${x.map(({ element, value, attributes }) => - `<${ - Object.entries(typeof attributes === 'object' && attributes || {}).reduce((a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, element) - }${ - typeof value === 'string' ? `>${escapeValue(value)}`).reduce((a, c) => a + c, '')}`; +const XRD = ( + ...x: { + element: string; + value?: string; + attributes?: Record; + }[] +) => + `${x + .map( + ({ element, value, attributes }) => + `<${Object.entries( + (typeof attributes === "object" && attributes) || {}, + ).reduce((a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, element)}${ + typeof value === "string" ? `>${escapeValue(value)}`, + ) + .reduce((a, c) => a + c, "")}`; -const allPath = '/.well-known/(.*)'; -const webFingerPath = '/.well-known/webfinger'; -const jrd = 'application/jrd+json'; -const xrd = 'application/xrd+xml'; +const allPath = "/.well-known/(.*)"; +const webFingerPath = "/.well-known/webfinger"; +const jrd = "application/jrd+json"; +const xrd = "application/xrd+xml"; router.use(allPath, async (ctx, next) => { ctx.set({ - 'Access-Control-Allow-Headers': 'Accept', - 'Access-Control-Allow-Methods': 'GET, OPTIONS', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Expose-Headers': 'Vary', + "Access-Control-Allow-Headers": "Accept", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Access-Control-Expose-Headers": "Vary", }); await next(); }); -router.options(allPath, async ctx => { +router.options(allPath, async (ctx) => { ctx.status = 204; }); -router.get('/.well-known/host-meta', async ctx => { - ctx.set('Content-Type', xrd); - ctx.body = XRD({ element: 'Link', attributes: { - rel: 'lrdd', - type: xrd, - template: `${config.url}${webFingerPath}?resource={uri}`, - } }); +router.get("/.well-known/host-meta", async (ctx) => { + ctx.set("Content-Type", xrd); + ctx.body = XRD({ + element: "Link", + attributes: { + rel: "lrdd", + type: xrd, + template: `${config.url}${webFingerPath}?resource={uri}`, + }, + }); }); -router.get('/.well-known/host-meta.json', async ctx => { - ctx.set('Content-Type', jrd); +router.get("/.well-known/host-meta.json", async (ctx) => { + ctx.set("Content-Type", jrd); ctx.body = { - links: [{ - rel: 'lrdd', - type: jrd, - template: `${config.url}${webFingerPath}?resource={uri}`, - }], + links: [ + { + rel: "lrdd", + type: jrd, + template: `${config.url}${webFingerPath}?resource={uri}`, + }, + ], }; }); -router.get('/.well-known/nodeinfo', async ctx => { +if (config.twa != null) { + router.get("/.well-known/assetlinks.json", async (ctx) => { + ctx.set("Content-Type", "application/json"); + ctx.body = [ + { + relation: ["delegate_permission/common.handle_all_urls"], + target: { + namespace: config.twa.nameSpace, + package_name: config.twa.packageName, + sha256_cert_fingerprints: config.twa.sha256CertFingerprints, + }, + }, + ]; + }); +} + +router.get("/.well-known/nodeinfo", async (ctx) => { ctx.body = { links }; }); @@ -67,36 +99,43 @@ router.get('/.well-known/change-password', async ctx => { }); */ -router.get(webFingerPath, async ctx => { - const fromId = (id: User['id']): FindOptionsWhere => ({ +router.get(webFingerPath, async (ctx) => { + const fromId = (id: User["id"]): FindOptionsWhere => ({ id, host: IsNull(), isSuspended: false, }); const generateQuery = (resource: string): FindOptionsWhere | number => - resource.startsWith(`${config.url.toLowerCase()}/users/`) ? - fromId(resource.split('/').pop()!) : - fromAcct(Acct.parse( - resource.startsWith(`${config.url.toLowerCase()}/@`) ? resource.split('/').pop()! : - resource.startsWith('acct:') ? resource.slice('acct:'.length) : - resource)); + resource.startsWith(`${config.url.toLowerCase()}/users/`) + ? fromId(resource.split("/").pop()!) + : fromAcct( + Acct.parse( + resource.startsWith(`${config.url.toLowerCase()}/@`) + ? resource.split("/").pop()! + : resource.startsWith("acct:") + ? resource.slice("acct:".length) + : resource, + ), + ); const fromAcct = (acct: Acct.Acct): FindOptionsWhere | number => - !acct.host || acct.host === config.host.toLowerCase() ? { - usernameLower: acct.username, - host: IsNull(), - isSuspended: false, - } : 422; + !acct.host || acct.host === config.host.toLowerCase() + ? { + usernameLower: acct.username, + host: IsNull(), + isSuspended: false, + } + : 422; - if (typeof ctx.query.resource !== 'string') { + if (typeof ctx.query.resource !== "string") { ctx.status = 400; return; } const query = generateQuery(ctx.query.resource.toLowerCase()); - if (typeof query === 'number') { + if (typeof query === "number") { ctx.status = query; return; } @@ -110,26 +149,27 @@ router.get(webFingerPath, async ctx => { const subject = `acct:${user.username}@${config.host}`; const self = { - rel: 'self', - type: 'application/activity+json', + rel: "self", + type: "application/activity+json", href: `${config.url}/users/${user.id}`, }; const profilePage = { - rel: 'http://webfinger.net/rel/profile-page', - type: 'text/html', + rel: "http://webfinger.net/rel/profile-page", + type: "text/html", href: `${config.url}/@${user.username}`, }; const subscribe = { - rel: 'http://ostatus.org/schema/1.0/subscribe', + rel: "http://ostatus.org/schema/1.0/subscribe", template: `${config.url}/authorize-follow?acct={uri}`, }; if (ctx.accepts(jrd, xrd) === xrd) { ctx.body = XRD( - { element: 'Subject', value: subject }, - { element: 'Link', attributes: self }, - { element: 'Link', attributes: profilePage }, - { element: 'Link', attributes: subscribe }); + { element: "Subject", value: subject }, + { element: "Link", attributes: self }, + { element: "Link", attributes: profilePage }, + { element: "Link", attributes: subscribe }, + ); ctx.type = xrd; } else { ctx.body = { @@ -139,12 +179,12 @@ router.get(webFingerPath, async ctx => { ctx.type = jrd; } - ctx.vary('Accept'); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.vary("Accept"); + ctx.set("Cache-Control", "public, max-age=180"); }); // Return 404 for other .well-known -router.all(allPath, async ctx => { +router.all(allPath, async (ctx) => { ctx.status = 404; }); diff --git a/packages/backend/src/services/add-note-to-antenna.ts b/packages/backend/src/services/add-note-to-antenna.ts index 1f344222e..38979acb4 100644 --- a/packages/backend/src/services/add-note-to-antenna.ts +++ b/packages/backend/src/services/add-note-to-antenna.ts @@ -1,14 +1,18 @@ -import { Antenna } from '@/models/entities/antenna.js'; -import { Note } from '@/models/entities/note.js'; -import { AntennaNotes, Mutings, Notes } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { isUserRelated } from '@/misc/is-user-related.js'; -import { publishAntennaStream, publishMainStream } from '@/services/stream.js'; -import { User } from '@/models/entities/user.js'; +import type { Antenna } from "@/models/entities/antenna.js"; +import type { Note } from "@/models/entities/note.js"; +import { AntennaNotes, Mutings, Notes } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { isUserRelated } from "@/misc/is-user-related.js"; +import { publishAntennaStream, publishMainStream } from "@/services/stream.js"; +import type { User } from "@/models/entities/user.js"; -export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { id: User['id']; }) { +export async function addNoteToAntenna( + antenna: Antenna, + note: Note, + noteUser: { id: User["id"] }, +) { // 通知しない設定になっているか、自分自身の投稿なら既読にする - const read = !antenna.notify || (antenna.userId === noteUser.id); + const read = !antenna.notify || antenna.userId === noteUser.id; AntennaNotes.insert({ id: genId(), @@ -17,14 +21,14 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { read: read, }); - publishAntennaStream(antenna.id, 'note', note); + publishAntennaStream(antenna.id, "note", note); if (!read) { const mutings = await Mutings.find({ where: { muterId: antenna.userId, }, - select: ['muteeId'], + select: ["muteeId"], }); // Copy @@ -39,15 +43,18 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { _note.renote = await Notes.findOneByOrFail({ id: note.renoteId }); } - if (isUserRelated(_note, new Set(mutings.map(x => x.muteeId)))) { + if (isUserRelated(_note, new Set(mutings.map((x) => x.muteeId)))) { return; } // 2秒経っても既読にならなかったら通知 setTimeout(async () => { - const unread = await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false }); + const unread = await AntennaNotes.findOneBy({ + antennaId: antenna.id, + read: false, + }); if (unread) { - publishMainStream(antenna.userId, 'unreadAntenna', antenna); + publishMainStream(antenna.userId, "unreadAntenna", antenna); } }, 2000); } diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index a2c61cca2..60bd6e943 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -1,20 +1,27 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { renderBlock } from '@/remote/activitypub/renderer/block.js'; -import { deliver } from '@/queue/index.js'; -import renderReject from '@/remote/activitypub/renderer/reject.js'; -import { Blocking } from '@/models/entities/blocking.js'; -import { User } from '@/models/entities/user.js'; -import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js'; -import { perUserFollowingChart } from '@/services/chart/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { getActiveWebhooks } from '@/misc/webhook-cache.js'; -import { webhookDeliver } from '@/queue/index.js'; +import { publishMainStream, publishUserEvent } from "@/services/stream.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { renderBlock } from "@/remote/activitypub/renderer/block.js"; +import { deliver } from "@/queue/index.js"; +import renderReject from "@/remote/activitypub/renderer/reject.js"; +import type { Blocking } from "@/models/entities/blocking.js"; +import type { User } from "@/models/entities/user.js"; +import { + Blockings, + Users, + FollowRequests, + Followings, + UserListJoinings, + UserLists, +} from "@/models/index.js"; +import { perUserFollowingChart } from "@/services/chart/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import { getActiveWebhooks } from "@/misc/webhook-cache.js"; +import { webhookDeliver } from "@/queue/index.js"; -export default async function(blocker: User, blockee: User) { +export default async function (blocker: User, blockee: User) { await Promise.all([ cancelRequest(blocker, blockee), cancelRequest(blockee, blocker), @@ -58,19 +65,21 @@ async function cancelRequest(follower: User, followee: User) { if (Users.isLocalUser(followee)) { Users.pack(followee, followee, { detail: true, - }).then(packed => publishMainStream(followee.id, 'meUpdated', packed)); + }).then((packed) => publishMainStream(followee.id, "meUpdated", packed)); } if (Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true, - }).then(async packed => { - publishUserEvent(follower.id, 'unfollow', packed); - publishMainStream(follower.id, 'unfollow', packed); + }).then(async (packed) => { + publishUserEvent(follower.id, "unfollow", packed); + publishMainStream(follower.id, "unfollow", packed); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === follower.id && x.on.includes("unfollow"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'unfollow', { + webhookDeliver(webhook, "unfollow", { user: packed, }); } @@ -79,13 +88,20 @@ async function cancelRequest(follower: User, followee: User) { // リモートにフォローリクエストをしていたらUndoFollow送信 if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { - const content = renderActivity(renderUndo(renderFollow(follower, followee), follower)); + const content = renderActivity( + renderUndo(renderFollow(follower, followee), follower), + ); deliver(follower, content, followee.inbox); } // リモートからフォローリクエストを受けていたらReject送信 if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - const content = renderActivity(renderReject(renderFollow(follower, followee, request.requestId!), followee)); + const content = renderActivity( + renderReject( + renderFollow(follower, followee, request.requestId!), + followee, + ), + ); deliver(followee, content, follower.inbox); } } @@ -102,8 +118,8 @@ async function unFollow(follower: User, followee: User) { await Promise.all([ Followings.delete(following.id), - Users.decrement({ id: follower.id }, 'followingCount', 1), - Users.decrement({ id: followee.id }, 'followersCount', 1), + Users.decrement({ id: follower.id }, "followingCount", 1), + Users.decrement({ id: followee.id }, "followersCount", 1), perUserFollowingChart.update(follower, followee, false), ]); @@ -111,13 +127,15 @@ async function unFollow(follower: User, followee: User) { if (Users.isLocalUser(follower)) { Users.pack(followee, follower, { detail: true, - }).then(async packed => { - publishUserEvent(follower.id, 'unfollow', packed); - publishMainStream(follower.id, 'unfollow', packed); + }).then(async (packed) => { + publishUserEvent(follower.id, "unfollow", packed); + publishMainStream(follower.id, "unfollow", packed); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === follower.id && x.on.includes("unfollow"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'unfollow', { + webhookDeliver(webhook, "unfollow", { user: packed, }); } @@ -126,7 +144,9 @@ async function unFollow(follower: User, followee: User) { // リモートにフォローをしていたらUndoFollow送信 if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { - const content = renderActivity(renderUndo(renderFollow(follower, followee), follower)); + const content = renderActivity( + renderUndo(renderFollow(follower, followee), follower), + ); deliver(follower, content, followee.inbox); } } diff --git a/packages/backend/src/services/blocking/delete.ts b/packages/backend/src/services/blocking/delete.ts index cb16651bc..67f1e76f0 100644 --- a/packages/backend/src/services/blocking/delete.ts +++ b/packages/backend/src/services/blocking/delete.ts @@ -1,21 +1,24 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { renderBlock } from '@/remote/activitypub/renderer/block.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { deliver } from '@/queue/index.js'; -import Logger from '../logger.js'; -import { CacheableUser, User } from '@/models/entities/user.js'; -import { Blockings, Users } from '@/models/index.js'; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { renderBlock } from "@/remote/activitypub/renderer/block.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { deliver } from "@/queue/index.js"; +import Logger from "../logger.js"; +import type { CacheableUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import { Blockings, Users } from "@/models/index.js"; -const logger = new Logger('blocking/delete'); +const logger = new Logger("blocking/delete"); -export default async function(blocker: CacheableUser, blockee: CacheableUser) { +export default async function (blocker: CacheableUser, blockee: CacheableUser) { const blocking = await Blockings.findOneBy({ blockerId: blocker.id, blockeeId: blockee.id, }); if (blocking == null) { - logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした'); + logger.warn( + "ブロック解除がリクエストされましたがブロックしていませんでした", + ); return; } diff --git a/packages/backend/src/services/chart/charts/active-users.ts b/packages/backend/src/services/chart/charts/active-users.ts index d952ea53b..7a0c45cfa 100644 --- a/packages/backend/src/services/chart/charts/active-users.ts +++ b/packages/backend/src/services/chart/charts/active-users.ts @@ -1,7 +1,8 @@ -import Chart, { KVs } from '../core.js'; -import { User } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; -import { name, schema } from './entities/active-users.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import type { User } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; +import { name, schema } from "./entities/active-users.js"; const week = 1000 * 60 * 60 * 24 * 7; const month = 1000 * 60 * 60 * 24 * 30; @@ -10,7 +11,7 @@ const year = 1000 * 60 * 60 * 24 * 365; /** * アクティブユーザーに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class ActiveUsersChart extends Chart { constructor() { super(name, schema); @@ -24,21 +25,35 @@ export default class ActiveUsersChart extends Chart { return {}; } - public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise { + public async read(user: { + id: User["id"]; + host: null; + createdAt: User["createdAt"]; + }): Promise { await this.commit({ - 'read': [user.id], - 'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [], - 'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < month) ? [user.id] : [], - 'registeredWithinYear': (Date.now() - user.createdAt.getTime() < year) ? [user.id] : [], - 'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > week) ? [user.id] : [], - 'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > month) ? [user.id] : [], - 'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > year) ? [user.id] : [], + read: [user.id], + registeredWithinWeek: + Date.now() - user.createdAt.getTime() < week ? [user.id] : [], + registeredWithinMonth: + Date.now() - user.createdAt.getTime() < month ? [user.id] : [], + registeredWithinYear: + Date.now() - user.createdAt.getTime() < year ? [user.id] : [], + registeredOutsideWeek: + Date.now() - user.createdAt.getTime() > week ? [user.id] : [], + registeredOutsideMonth: + Date.now() - user.createdAt.getTime() > month ? [user.id] : [], + registeredOutsideYear: + Date.now() - user.createdAt.getTime() > year ? [user.id] : [], }); } - public async write(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise { + public async write(user: { + id: User["id"]; + host: null; + createdAt: User["createdAt"]; + }): Promise { await this.commit({ - 'write': [user.id], + write: [user.id], }); } } diff --git a/packages/backend/src/services/chart/charts/ap-request.ts b/packages/backend/src/services/chart/charts/ap-request.ts index e9e42ade7..6e56be0b3 100644 --- a/packages/backend/src/services/chart/charts/ap-request.ts +++ b/packages/backend/src/services/chart/charts/ap-request.ts @@ -1,10 +1,11 @@ -import Chart, { KVs } from '../core.js'; -import { name, schema } from './entities/ap-request.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { name, schema } from "./entities/ap-request.js"; /** * Chart about ActivityPub requests */ -// eslint-disable-next-line import/no-default-export + export default class ApRequestChart extends Chart { constructor() { super(name, schema); @@ -20,19 +21,19 @@ export default class ApRequestChart extends Chart { public async deliverSucc(): Promise { await this.commit({ - 'deliverSucceeded': 1, + deliverSucceeded: 1, }); } public async deliverFail(): Promise { await this.commit({ - 'deliverFailed': 1, + deliverFailed: 1, }); } public async inbox(): Promise { await this.commit({ - 'inboxReceived': 1, + inboxReceived: 1, }); } } diff --git a/packages/backend/src/services/chart/charts/drive.ts b/packages/backend/src/services/chart/charts/drive.ts index 0eeba90dd..9793ff79d 100644 --- a/packages/backend/src/services/chart/charts/drive.ts +++ b/packages/backend/src/services/chart/charts/drive.ts @@ -1,13 +1,14 @@ -import Chart, { KVs } from '../core.js'; -import { DriveFiles } from '@/models/index.js'; -import { Not, IsNull } from 'typeorm'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { name, schema } from './entities/drive.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { DriveFiles } from "@/models/index.js"; +import { Not, IsNull } from "typeorm"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { name, schema } from "./entities/drive.js"; /** * ドライブに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class DriveChart extends Chart { constructor() { super(name, schema); @@ -23,16 +24,20 @@ export default class DriveChart extends Chart { public async update(file: DriveFile, isAdditional: boolean): Promise { const fileSizeKb = file.size / 1000; - await this.commit(file.userHost === null ? { - 'local.incCount': isAdditional ? 1 : 0, - 'local.incSize': isAdditional ? fileSizeKb : 0, - 'local.decCount': isAdditional ? 0 : 1, - 'local.decSize': isAdditional ? 0 : fileSizeKb, - } : { - 'remote.incCount': isAdditional ? 1 : 0, - 'remote.incSize': isAdditional ? fileSizeKb : 0, - 'remote.decCount': isAdditional ? 0 : 1, - 'remote.decSize': isAdditional ? 0 : fileSizeKb, - }); + await this.commit( + file.userHost === null + ? { + "local.incCount": isAdditional ? 1 : 0, + "local.incSize": isAdditional ? fileSizeKb : 0, + "local.decCount": isAdditional ? 0 : 1, + "local.decSize": isAdditional ? 0 : fileSizeKb, + } + : { + "remote.incCount": isAdditional ? 1 : 0, + "remote.incSize": isAdditional ? fileSizeKb : 0, + "remote.decCount": isAdditional ? 0 : 1, + "remote.decSize": isAdditional ? 0 : fileSizeKb, + }, + ); } } diff --git a/packages/backend/src/services/chart/charts/entities/active-users.ts b/packages/backend/src/services/chart/charts/entities/active-users.ts index 5767b76f8..4e5fa37a2 100644 --- a/packages/backend/src/services/chart/charts/entities/active-users.ts +++ b/packages/backend/src/services/chart/charts/entities/active-users.ts @@ -1,17 +1,17 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'activeUsers'; +export const name = "activeUsers"; export const schema = { - 'readWrite': { intersection: ['read', 'write'], range: 'small' }, - 'read': { uniqueIncrement: true, range: 'small' }, - 'write': { uniqueIncrement: true, range: 'small' }, - 'registeredWithinWeek': { uniqueIncrement: true, range: 'small' }, - 'registeredWithinMonth': { uniqueIncrement: true, range: 'small' }, - 'registeredWithinYear': { uniqueIncrement: true, range: 'small' }, - 'registeredOutsideWeek': { uniqueIncrement: true, range: 'small' }, - 'registeredOutsideMonth': { uniqueIncrement: true, range: 'small' }, - 'registeredOutsideYear': { uniqueIncrement: true, range: 'small' }, + readWrite: { intersection: ["read", "write"], range: "small" }, + read: { uniqueIncrement: true, range: "small" }, + write: { uniqueIncrement: true, range: "small" }, + registeredWithinWeek: { uniqueIncrement: true, range: "small" }, + registeredWithinMonth: { uniqueIncrement: true, range: "small" }, + registeredWithinYear: { uniqueIncrement: true, range: "small" }, + registeredOutsideWeek: { uniqueIncrement: true, range: "small" }, + registeredOutsideMonth: { uniqueIncrement: true, range: "small" }, + registeredOutsideYear: { uniqueIncrement: true, range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/ap-request.ts b/packages/backend/src/services/chart/charts/entities/ap-request.ts index 3a9f3dacf..eb0220174 100644 --- a/packages/backend/src/services/chart/charts/entities/ap-request.ts +++ b/packages/backend/src/services/chart/charts/entities/ap-request.ts @@ -1,11 +1,11 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'apRequest'; +export const name = "apRequest"; export const schema = { - 'deliverFailed': { }, - 'deliverSucceeded': { }, - 'inboxReceived': { }, + deliverFailed: {}, + deliverSucceeded: {}, + inboxReceived: {}, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/drive.ts b/packages/backend/src/services/chart/charts/entities/drive.ts index 4bf5bb729..0280ec655 100644 --- a/packages/backend/src/services/chart/charts/entities/drive.ts +++ b/packages/backend/src/services/chart/charts/entities/drive.ts @@ -1,16 +1,16 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'drive'; +export const name = "drive"; export const schema = { - 'local.incCount': {}, - 'local.incSize': {}, // in kilobyte - 'local.decCount': {}, - 'local.decSize': {}, // in kilobyte - 'remote.incCount': {}, - 'remote.incSize': {}, // in kilobyte - 'remote.decCount': {}, - 'remote.decSize': {}, // in kilobyte + "local.incCount": {}, + "local.incSize": {}, // in kilobyte + "local.decCount": {}, + "local.decSize": {}, // in kilobyte + "remote.incCount": {}, + "remote.incSize": {}, // in kilobyte + "remote.decCount": {}, + "remote.decSize": {}, // in kilobyte } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/federation.ts b/packages/backend/src/services/chart/charts/entities/federation.ts index a8466b0b4..b77e02096 100644 --- a/packages/backend/src/services/chart/charts/entities/federation.ts +++ b/packages/backend/src/services/chart/charts/entities/federation.ts @@ -1,16 +1,16 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'federation'; +export const name = "federation"; export const schema = { - 'deliveredInstances': { uniqueIncrement: true, range: 'small' }, - 'inboxInstances': { uniqueIncrement: true, range: 'small' }, - 'stalled': { uniqueIncrement: true, range: 'small' }, - 'sub': { accumulate: true, range: 'small' }, - 'pub': { accumulate: true, range: 'small' }, - 'pubsub': { accumulate: true, range: 'small' }, - 'subActive': { accumulate: true, range: 'small' }, - 'pubActive': { accumulate: true, range: 'small' }, + deliveredInstances: { uniqueIncrement: true, range: "small" }, + inboxInstances: { uniqueIncrement: true, range: "small" }, + stalled: { uniqueIncrement: true, range: "small" }, + sub: { accumulate: true, range: "small" }, + pub: { accumulate: true, range: "small" }, + pubsub: { accumulate: true, range: "small" }, + subActive: { accumulate: true, range: "small" }, + pubActive: { accumulate: true, range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/hashtag.ts b/packages/backend/src/services/chart/charts/entities/hashtag.ts index 4d0403904..77964b4ca 100644 --- a/packages/backend/src/services/chart/charts/entities/hashtag.ts +++ b/packages/backend/src/services/chart/charts/entities/hashtag.ts @@ -1,10 +1,10 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'hashtag'; +export const name = "hashtag"; export const schema = { - 'local.users': { uniqueIncrement: true }, - 'remote.users': { uniqueIncrement: true }, + "local.users": { uniqueIncrement: true }, + "remote.users": { uniqueIncrement: true }, } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/instance.ts b/packages/backend/src/services/chart/charts/entities/instance.ts index 06962120e..a75dea475 100644 --- a/packages/backend/src/services/chart/charts/entities/instance.ts +++ b/packages/backend/src/services/chart/charts/entities/instance.ts @@ -1,32 +1,32 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'instance'; +export const name = "instance"; export const schema = { - 'requests.failed': { range: 'small' }, - 'requests.succeeded': { range: 'small' }, - 'requests.received': { range: 'small' }, - 'notes.total': { accumulate: true }, - 'notes.inc': {}, - 'notes.dec': {}, - 'notes.diffs.normal': {}, - 'notes.diffs.reply': {}, - 'notes.diffs.renote': {}, - 'notes.diffs.withFile': {}, - 'users.total': { accumulate: true }, - 'users.inc': { range: 'small' }, - 'users.dec': { range: 'small' }, - 'following.total': { accumulate: true }, - 'following.inc': { range: 'small' }, - 'following.dec': { range: 'small' }, - 'followers.total': { accumulate: true }, - 'followers.inc': { range: 'small' }, - 'followers.dec': { range: 'small' }, - 'drive.totalFiles': { accumulate: true }, - 'drive.incFiles': {}, - 'drive.decFiles': {}, - 'drive.incUsage': {}, // in kilobyte - 'drive.decUsage': {}, // in kilobyte + "requests.failed": { range: "small" }, + "requests.succeeded": { range: "small" }, + "requests.received": { range: "small" }, + "notes.total": { accumulate: true }, + "notes.inc": {}, + "notes.dec": {}, + "notes.diffs.normal": {}, + "notes.diffs.reply": {}, + "notes.diffs.renote": {}, + "notes.diffs.withFile": {}, + "users.total": { accumulate: true }, + "users.inc": { range: "small" }, + "users.dec": { range: "small" }, + "following.total": { accumulate: true }, + "following.inc": { range: "small" }, + "following.dec": { range: "small" }, + "followers.total": { accumulate: true }, + "followers.inc": { range: "small" }, + "followers.dec": { range: "small" }, + "drive.totalFiles": { accumulate: true }, + "drive.incFiles": {}, + "drive.decFiles": {}, + "drive.incUsage": {}, // in kilobyte + "drive.decUsage": {}, // in kilobyte } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/notes.ts b/packages/backend/src/services/chart/charts/entities/notes.ts index 9387dbfb2..04e75a2f2 100644 --- a/packages/backend/src/services/chart/charts/entities/notes.ts +++ b/packages/backend/src/services/chart/charts/entities/notes.ts @@ -1,22 +1,22 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'notes'; +export const name = "notes"; export const schema = { - 'local.total': { accumulate: true }, - 'local.inc': {}, - 'local.dec': {}, - 'local.diffs.normal': {}, - 'local.diffs.reply': {}, - 'local.diffs.renote': {}, - 'local.diffs.withFile': {}, - 'remote.total': { accumulate: true }, - 'remote.inc': {}, - 'remote.dec': {}, - 'remote.diffs.normal': {}, - 'remote.diffs.reply': {}, - 'remote.diffs.renote': {}, - 'remote.diffs.withFile': {}, + "local.total": { accumulate: true }, + "local.inc": {}, + "local.dec": {}, + "local.diffs.normal": {}, + "local.diffs.reply": {}, + "local.diffs.renote": {}, + "local.diffs.withFile": {}, + "remote.total": { accumulate: true }, + "remote.inc": {}, + "remote.dec": {}, + "remote.diffs.normal": {}, + "remote.diffs.reply": {}, + "remote.diffs.renote": {}, + "remote.diffs.withFile": {}, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-drive.ts b/packages/backend/src/services/chart/charts/entities/per-user-drive.ts index 6111640ea..d9dcd3d35 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-drive.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-drive.ts @@ -1,14 +1,14 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'perUserDrive'; +export const name = "perUserDrive"; export const schema = { - 'totalCount': { accumulate: true }, - 'totalSize': { accumulate: true }, // in kilobyte - 'incCount': { range: 'small' }, - 'incSize': {}, // in kilobyte - 'decCount': { range: 'small' }, - 'decSize': {}, // in kilobyte + totalCount: { accumulate: true }, + totalSize: { accumulate: true }, // in kilobyte + incCount: { range: "small" }, + incSize: {}, // in kilobyte + decCount: { range: "small" }, + decSize: {}, // in kilobyte } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-following.ts b/packages/backend/src/services/chart/charts/entities/per-user-following.ts index 4118daa47..3cbeec111 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-following.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-following.ts @@ -1,20 +1,20 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'perUserFollowing'; +export const name = "perUserFollowing"; export const schema = { - 'local.followings.total': { accumulate: true }, - 'local.followings.inc': { range: 'small' }, - 'local.followings.dec': { range: 'small' }, - 'local.followers.total': { accumulate: true }, - 'local.followers.inc': { range: 'small' }, - 'local.followers.dec': { range: 'small' }, - 'remote.followings.total': { accumulate: true }, - 'remote.followings.inc': { range: 'small' }, - 'remote.followings.dec': { range: 'small' }, - 'remote.followers.total': { accumulate: true }, - 'remote.followers.inc': { range: 'small' }, - 'remote.followers.dec': { range: 'small' }, + "local.followings.total": { accumulate: true }, + "local.followings.inc": { range: "small" }, + "local.followings.dec": { range: "small" }, + "local.followers.total": { accumulate: true }, + "local.followers.inc": { range: "small" }, + "local.followers.dec": { range: "small" }, + "remote.followings.total": { accumulate: true }, + "remote.followings.inc": { range: "small" }, + "remote.followings.dec": { range: "small" }, + "remote.followers.total": { accumulate: true }, + "remote.followers.inc": { range: "small" }, + "remote.followers.dec": { range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts index c1fa17445..30c22e2f4 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts @@ -1,15 +1,15 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'perUserNotes'; +export const name = "perUserNotes"; export const schema = { - 'total': { accumulate: true }, - 'inc': { range: 'small' }, - 'dec': { range: 'small' }, - 'diffs.normal': { range: 'small' }, - 'diffs.reply': { range: 'small' }, - 'diffs.renote': { range: 'small' }, - 'diffs.withFile': { range: 'small' }, + total: { accumulate: true }, + inc: { range: "small" }, + dec: { range: "small" }, + "diffs.normal": { range: "small" }, + "diffs.reply": { range: "small" }, + "diffs.renote": { range: "small" }, + "diffs.withFile": { range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts b/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts index 5e1a6c7b3..f281531c0 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts @@ -1,10 +1,10 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'perUserReaction'; +export const name = "perUserReaction"; export const schema = { - 'local.count': { range: 'small' }, - 'remote.count': { range: 'small' }, + "local.count": { range: "small" }, + "remote.count": { range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/test-grouped.ts b/packages/backend/src/services/chart/charts/entities/test-grouped.ts index 66b6e8e86..428f2bb36 100644 --- a/packages/backend/src/services/chart/charts/entities/test-grouped.ts +++ b/packages/backend/src/services/chart/charts/entities/test-grouped.ts @@ -1,11 +1,11 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'testGrouped'; +export const name = "testGrouped"; export const schema = { - 'foo.total': { accumulate: true }, - 'foo.inc': {}, - 'foo.dec': {}, + "foo.total": { accumulate: true }, + "foo.inc": {}, + "foo.dec": {}, } as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/test-intersection.ts b/packages/backend/src/services/chart/charts/entities/test-intersection.ts index a3bdcb367..30d8753d7 100644 --- a/packages/backend/src/services/chart/charts/entities/test-intersection.ts +++ b/packages/backend/src/services/chart/charts/entities/test-intersection.ts @@ -1,11 +1,11 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'testIntersection'; +export const name = "testIntersection"; export const schema = { - 'a': { uniqueIncrement: true }, - 'b': { uniqueIncrement: true }, - 'aAndB': { intersection: ['a', 'b'] }, + a: { uniqueIncrement: true }, + b: { uniqueIncrement: true }, + aAndB: { intersection: ["a", "b"] }, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/test-unique.ts b/packages/backend/src/services/chart/charts/entities/test-unique.ts index b2cfb71b0..03b8a7653 100644 --- a/packages/backend/src/services/chart/charts/entities/test-unique.ts +++ b/packages/backend/src/services/chart/charts/entities/test-unique.ts @@ -1,9 +1,9 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'testUnique'; +export const name = "testUnique"; export const schema = { - 'foo': { uniqueIncrement: true }, + foo: { uniqueIncrement: true }, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/test.ts b/packages/backend/src/services/chart/charts/entities/test.ts index 7cba21e16..a11d53e32 100644 --- a/packages/backend/src/services/chart/charts/entities/test.ts +++ b/packages/backend/src/services/chart/charts/entities/test.ts @@ -1,11 +1,11 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'test'; +export const name = "test"; export const schema = { - 'foo.total': { accumulate: true }, - 'foo.inc': {}, - 'foo.dec': {}, + "foo.total": { accumulate: true }, + "foo.inc": {}, + "foo.dec": {}, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/users.ts b/packages/backend/src/services/chart/charts/entities/users.ts index c0b83094a..a9544d77b 100644 --- a/packages/backend/src/services/chart/charts/entities/users.ts +++ b/packages/backend/src/services/chart/charts/entities/users.ts @@ -1,14 +1,14 @@ -import Chart from '../../core.js'; +import Chart from "../../core.js"; -export const name = 'users'; +export const name = "users"; export const schema = { - 'local.total': { accumulate: true }, - 'local.inc': { range: 'small' }, - 'local.dec': { range: 'small' }, - 'remote.total': { accumulate: true }, - 'remote.inc': { range: 'small' }, - 'remote.dec': { range: 'small' }, + "local.total": { accumulate: true }, + "local.inc": { range: "small" }, + "local.dec": { range: "small" }, + "remote.total": { accumulate: true }, + "remote.inc": { range: "small" }, + "remote.dec": { range: "small" }, } as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/federation.ts b/packages/backend/src/services/chart/charts/federation.ts index 10221ee1e..1a03d574d 100644 --- a/packages/backend/src/services/chart/charts/federation.ts +++ b/packages/backend/src/services/chart/charts/federation.ts @@ -1,103 +1,142 @@ -import Chart, { KVs } from '../core.js'; -import { Followings, Instances } from '@/models/index.js'; -import { name, schema } from './entities/federation.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { Followings, Instances } from "@/models/index.js"; +import { name, schema } from "./entities/federation.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; /** * フェデレーションに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class FederationChart extends Chart { constructor() { super(name, schema); } protected async tickMajor(): Promise>> { - return { - }; + return {}; } protected async tickMinor(): Promise>> { const meta = await fetchMeta(); - const suspendedInstancesQuery = Instances.createQueryBuilder('instance') - .select('instance.host') - .where('instance.isSuspended = true'); + const suspendedInstancesQuery = Instances.createQueryBuilder("instance") + .select("instance.host") + .where("instance.isSuspended = true"); - const pubsubSubQuery = Followings.createQueryBuilder('f') - .select('f.followerHost') - .where('f.followerHost IS NOT NULL'); + const pubsubSubQuery = Followings.createQueryBuilder("f") + .select("f.followerHost") + .where("f.followerHost IS NOT NULL"); - const subInstancesQuery = Followings.createQueryBuilder('f') - .select('f.followeeHost') - .where('f.followeeHost IS NOT NULL'); + const subInstancesQuery = Followings.createQueryBuilder("f") + .select("f.followeeHost") + .where("f.followeeHost IS NOT NULL"); - const pubInstancesQuery = Followings.createQueryBuilder('f') - .select('f.followerHost') - .where('f.followerHost IS NOT NULL'); + const pubInstancesQuery = Followings.createQueryBuilder("f") + .select("f.followerHost") + .where("f.followerHost IS NOT NULL"); const [sub, pub, pubsub, subActive, pubActive] = await Promise.all([ - Followings.createQueryBuilder('following') - .select('COUNT(DISTINCT following.followeeHost)') - .where('following.followeeHost IS NOT NULL') - .andWhere(meta.blockedHosts.length === 0 ? '1=1' : `following.followeeHost NOT IN (:...blocked)`, { blocked: meta.blockedHosts }) - .andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`) + Followings.createQueryBuilder("following") + .select("COUNT(DISTINCT following.followeeHost)") + .where("following.followeeHost IS NOT NULL") + .andWhere( + meta.blockedHosts.length === 0 + ? "1=1" + : "following.followeeHost NOT IN (:...blocked)", + { blocked: meta.blockedHosts }, + ) + .andWhere( + `following.followeeHost NOT IN (${suspendedInstancesQuery.getQuery()})`, + ) .getRawOne() - .then(x => parseInt(x.count, 10)), - Followings.createQueryBuilder('following') - .select('COUNT(DISTINCT following.followerHost)') - .where('following.followerHost IS NOT NULL') - .andWhere(meta.blockedHosts.length === 0 ? '1=1' : `following.followerHost NOT IN (:...blocked)`, { blocked: meta.blockedHosts }) - .andWhere(`following.followerHost NOT IN (${ suspendedInstancesQuery.getQuery() })`) + .then((x) => parseInt(x.count, 10)), + Followings.createQueryBuilder("following") + .select("COUNT(DISTINCT following.followerHost)") + .where("following.followerHost IS NOT NULL") + .andWhere( + meta.blockedHosts.length === 0 + ? "1=1" + : "following.followerHost NOT IN (:...blocked)", + { blocked: meta.blockedHosts }, + ) + .andWhere( + `following.followerHost NOT IN (${suspendedInstancesQuery.getQuery()})`, + ) .getRawOne() - .then(x => parseInt(x.count, 10)), - Followings.createQueryBuilder('following') - .select('COUNT(DISTINCT following.followeeHost)') - .where('following.followeeHost IS NOT NULL') - .andWhere(meta.blockedHosts.length === 0 ? '1=1' : `following.followeeHost NOT IN (:...blocked)`, { blocked: meta.blockedHosts }) - .andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`) - .andWhere(`following.followeeHost IN (${ pubsubSubQuery.getQuery() })`) + .then((x) => parseInt(x.count, 10)), + Followings.createQueryBuilder("following") + .select("COUNT(DISTINCT following.followeeHost)") + .where("following.followeeHost IS NOT NULL") + .andWhere( + meta.blockedHosts.length === 0 + ? "1=1" + : "following.followeeHost NOT IN (:...blocked)", + { blocked: meta.blockedHosts }, + ) + .andWhere( + `following.followeeHost NOT IN (${suspendedInstancesQuery.getQuery()})`, + ) + .andWhere(`following.followeeHost IN (${pubsubSubQuery.getQuery()})`) .setParameters(pubsubSubQuery.getParameters()) .getRawOne() - .then(x => parseInt(x.count, 10)), - Instances.createQueryBuilder('instance') - .select('COUNT(instance.id)') - .where(`instance.host IN (${ subInstancesQuery.getQuery() })`) - .andWhere(meta.blockedHosts.length === 0 ? '1=1' : `instance.host NOT IN (:...blocked)`, { blocked: meta.blockedHosts }) - .andWhere(`instance.isSuspended = false`) - .andWhere(`instance.lastCommunicatedAt > :gt`, { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) + .then((x) => parseInt(x.count, 10)), + Instances.createQueryBuilder("instance") + .select("COUNT(instance.id)") + .where(`instance.host IN (${subInstancesQuery.getQuery()})`) + .andWhere( + meta.blockedHosts.length === 0 + ? "1=1" + : "instance.host NOT IN (:...blocked)", + { blocked: meta.blockedHosts }, + ) + .andWhere("instance.isSuspended = false") + .andWhere("instance.lastCommunicatedAt > :gt", { + gt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30), + }) .getRawOne() - .then(x => parseInt(x.count, 10)), - Instances.createQueryBuilder('instance') - .select('COUNT(instance.id)') - .where(`instance.host IN (${ pubInstancesQuery.getQuery() })`) - .andWhere(meta.blockedHosts.length === 0 ? '1=1' : `instance.host NOT IN (:...blocked)`, { blocked: meta.blockedHosts }) - .andWhere(`instance.isSuspended = false`) - .andWhere(`instance.lastCommunicatedAt > :gt`, { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) + .then((x) => parseInt(x.count, 10)), + Instances.createQueryBuilder("instance") + .select("COUNT(instance.id)") + .where(`instance.host IN (${pubInstancesQuery.getQuery()})`) + .andWhere( + meta.blockedHosts.length === 0 + ? "1=1" + : "instance.host NOT IN (:...blocked)", + { blocked: meta.blockedHosts }, + ) + .andWhere("instance.isSuspended = false") + .andWhere("instance.lastCommunicatedAt > :gt", { + gt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30), + }) .getRawOne() - .then(x => parseInt(x.count, 10)), + .then((x) => parseInt(x.count, 10)), ]); return { - 'sub': sub, - 'pub': pub, - 'pubsub': pubsub, - 'subActive': subActive, - 'pubActive': pubActive, + sub: sub, + pub: pub, + pubsub: pubsub, + subActive: subActive, + pubActive: pubActive, }; } public async deliverd(host: string, succeeded: boolean): Promise { - await this.commit(succeeded ? { - 'deliveredInstances': [host], - } : { - 'stalled': [host], - }); + await this.commit( + succeeded + ? { + deliveredInstances: [host], + } + : { + stalled: [host], + }, + ); } public async inbox(host: string): Promise { await this.commit({ - 'inboxInstances': [host], + inboxInstances: [host], }); } } diff --git a/packages/backend/src/services/chart/charts/hashtag.ts b/packages/backend/src/services/chart/charts/hashtag.ts index 31f7fa95d..0211df857 100644 --- a/packages/backend/src/services/chart/charts/hashtag.ts +++ b/packages/backend/src/services/chart/charts/hashtag.ts @@ -1,12 +1,13 @@ -import Chart, { KVs } from '../core.js'; -import { User } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; -import { name, schema } from './entities/hashtag.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import type { User } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; +import { name, schema } from "./entities/hashtag.js"; /** * ハッシュタグに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class HashtagChart extends Chart { constructor() { super(name, schema, true); @@ -20,10 +21,16 @@ export default class HashtagChart extends Chart { return {}; } - public async update(hashtag: string, user: { id: User['id'], host: User['host'] }): Promise { - await this.commit({ - 'local.users': Users.isLocalUser(user) ? [user.id] : [], - 'remote.users': Users.isLocalUser(user) ? [] : [user.id], - }, hashtag); + public async update( + hashtag: string, + user: { id: User["id"]; host: User["host"] }, + ): Promise { + await this.commit( + { + "local.users": Users.isLocalUser(user) ? [user.id] : [], + "remote.users": Users.isLocalUser(user) ? [] : [user.id], + }, + hashtag, + ); } } diff --git a/packages/backend/src/services/chart/charts/instance.ts b/packages/backend/src/services/chart/charts/instance.ts index fe29ba522..d6e3483d8 100644 --- a/packages/backend/src/services/chart/charts/instance.ts +++ b/packages/backend/src/services/chart/charts/instance.ts @@ -1,40 +1,38 @@ -import Chart, { KVs } from '../core.js'; -import { DriveFiles, Followings, Users, Notes } from '@/models/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { Note } from '@/models/entities/note.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { name, schema } from './entities/instance.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { DriveFiles, Followings, Users, Notes } from "@/models/index.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { Note } from "@/models/entities/note.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { name, schema } from "./entities/instance.js"; /** * インスタンスごとのチャート */ -// eslint-disable-next-line import/no-default-export + export default class InstanceChart extends Chart { constructor() { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { - const [ - notesCount, - usersCount, - followingCount, - followersCount, - driveFiles, - ] = await Promise.all([ - Notes.countBy({ userHost: group }), - Users.countBy({ host: group }), - Followings.countBy({ followerHost: group }), - Followings.countBy({ followeeHost: group }), - DriveFiles.countBy({ userHost: group }), - ]); + protected async tickMajor( + group: string, + ): Promise>> { + const [notesCount, usersCount, followingCount, followersCount, driveFiles] = + await Promise.all([ + Notes.countBy({ userHost: group }), + Users.countBy({ host: group }), + Followings.countBy({ followerHost: group }), + Followings.countBy({ followeeHost: group }), + DriveFiles.countBy({ userHost: group }), + ]); return { - 'notes.total': notesCount, - 'users.total': usersCount, - 'following.total': followingCount, - 'followers.total': followersCount, - 'drive.totalFiles': driveFiles, + "notes.total": notesCount, + "users.total": usersCount, + "following.total": followingCount, + "followers.total": followersCount, + "drive.totalFiles": driveFiles, }; } @@ -43,61 +41,102 @@ export default class InstanceChart extends Chart { } public async requestReceived(host: string): Promise { - await this.commit({ - 'requests.received': 1, - }, toPuny(host)); + await this.commit( + { + "requests.received": 1, + }, + toPuny(host), + ); } public async requestSent(host: string, isSucceeded: boolean): Promise { - await this.commit({ - 'requests.succeeded': isSucceeded ? 1 : 0, - 'requests.failed': isSucceeded ? 0 : 1, - }, toPuny(host)); + await this.commit( + { + "requests.succeeded": isSucceeded ? 1 : 0, + "requests.failed": isSucceeded ? 0 : 1, + }, + toPuny(host), + ); } public async newUser(host: string): Promise { - await this.commit({ - 'users.total': 1, - 'users.inc': 1, - }, toPuny(host)); + await this.commit( + { + "users.total": 1, + "users.inc": 1, + }, + toPuny(host), + ); } - public async updateNote(host: string, note: Note, isAdditional: boolean): Promise { - await this.commit({ - 'notes.total': isAdditional ? 1 : -1, - 'notes.inc': isAdditional ? 1 : 0, - 'notes.dec': isAdditional ? 0 : 1, - 'notes.diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, - 'notes.diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0, - 'notes.diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0, - 'notes.diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, - }, toPuny(host)); + public async updateNote( + host: string, + note: Note, + isAdditional: boolean, + ): Promise { + await this.commit( + { + "notes.total": isAdditional ? 1 : -1, + "notes.inc": isAdditional ? 1 : 0, + "notes.dec": isAdditional ? 0 : 1, + "notes.diffs.normal": + note.replyId == null && note.renoteId == null + ? isAdditional + ? 1 + : -1 + : 0, + "notes.diffs.renote": + note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + "notes.diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0, + "notes.diffs.withFile": + note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, + }, + toPuny(host), + ); } - public async updateFollowing(host: string, isAdditional: boolean): Promise { - await this.commit({ - 'following.total': isAdditional ? 1 : -1, - 'following.inc': isAdditional ? 1 : 0, - 'following.dec': isAdditional ? 0 : 1, - }, toPuny(host)); + public async updateFollowing( + host: string, + isAdditional: boolean, + ): Promise { + await this.commit( + { + "following.total": isAdditional ? 1 : -1, + "following.inc": isAdditional ? 1 : 0, + "following.dec": isAdditional ? 0 : 1, + }, + toPuny(host), + ); } - public async updateFollowers(host: string, isAdditional: boolean): Promise { - await this.commit({ - 'followers.total': isAdditional ? 1 : -1, - 'followers.inc': isAdditional ? 1 : 0, - 'followers.dec': isAdditional ? 0 : 1, - }, toPuny(host)); + public async updateFollowers( + host: string, + isAdditional: boolean, + ): Promise { + await this.commit( + { + "followers.total": isAdditional ? 1 : -1, + "followers.inc": isAdditional ? 1 : 0, + "followers.dec": isAdditional ? 0 : 1, + }, + toPuny(host), + ); } - public async updateDrive(file: DriveFile, isAdditional: boolean): Promise { + public async updateDrive( + file: DriveFile, + isAdditional: boolean, + ): Promise { const fileSizeKb = file.size / 1000; - await this.commit({ - 'drive.totalFiles': isAdditional ? 1 : -1, - 'drive.incFiles': isAdditional ? 1 : 0, - 'drive.incUsage': isAdditional ? fileSizeKb : 0, - 'drive.decFiles': isAdditional ? 1 : 0, - 'drive.decUsage': isAdditional ? fileSizeKb : 0, - }, file.userHost); + await this.commit( + { + "drive.totalFiles": isAdditional ? 1 : -1, + "drive.incFiles": isAdditional ? 1 : 0, + "drive.incUsage": isAdditional ? fileSizeKb : 0, + "drive.decFiles": isAdditional ? 1 : 0, + "drive.decUsage": isAdditional ? fileSizeKb : 0, + }, + file.userHost, + ); } } diff --git a/packages/backend/src/services/chart/charts/notes.ts b/packages/backend/src/services/chart/charts/notes.ts index bb14b62f3..9ec347b47 100644 --- a/packages/backend/src/services/chart/charts/notes.ts +++ b/packages/backend/src/services/chart/charts/notes.ts @@ -1,13 +1,14 @@ -import Chart, { KVs } from '../core.js'; -import { Notes } from '@/models/index.js'; -import { Not, IsNull } from 'typeorm'; -import { Note } from '@/models/entities/note.js'; -import { name, schema } from './entities/notes.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { Notes } from "@/models/index.js"; +import { Not, IsNull } from "typeorm"; +import type { Note } from "@/models/entities/note.js"; +import { name, schema } from "./entities/notes.js"; /** * ノートに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class NotesChart extends Chart { constructor() { super(name, schema); @@ -20,8 +21,8 @@ export default class NotesChart extends Chart { ]); return { - 'local.total': localCount, - 'remote.total': remoteCount, + "local.total": localCount, + "remote.total": remoteCount, }; } @@ -30,16 +31,24 @@ export default class NotesChart extends Chart { } public async update(note: Note, isAdditional: boolean): Promise { - const prefix = note.userHost === null ? 'local' : 'remote'; + const prefix = note.userHost === null ? "local" : "remote"; await this.commit({ [`${prefix}.total`]: isAdditional ? 1 : -1, [`${prefix}.inc`]: isAdditional ? 1 : 0, [`${prefix}.dec`]: isAdditional ? 0 : 1, - [`${prefix}.diffs.normal`]: note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, - [`${prefix}.diffs.renote`]: note.renoteId != null ? (isAdditional ? 1 : -1) : 0, - [`${prefix}.diffs.reply`]: note.replyId != null ? (isAdditional ? 1 : -1) : 0, - [`${prefix}.diffs.withFile`]: note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.normal`]: + note.replyId == null && note.renoteId == null + ? isAdditional + ? 1 + : -1 + : 0, + [`${prefix}.diffs.renote`]: + note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.reply`]: + note.replyId != null ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.withFile`]: + note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, }); } } diff --git a/packages/backend/src/services/chart/charts/per-user-drive.ts b/packages/backend/src/services/chart/charts/per-user-drive.ts index 5f75dc688..18589bb84 100644 --- a/packages/backend/src/services/chart/charts/per-user-drive.ts +++ b/packages/backend/src/services/chart/charts/per-user-drive.ts @@ -1,26 +1,29 @@ -import Chart, { KVs } from '../core.js'; -import { DriveFiles } from '@/models/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { name, schema } from './entities/per-user-drive.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { DriveFiles } from "@/models/index.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { name, schema } from "./entities/per-user-drive.js"; /** * ユーザーごとのドライブに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class PerUserDriveChart extends Chart { constructor() { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { + protected async tickMajor( + group: string, + ): Promise>> { const [count, size] = await Promise.all([ DriveFiles.countBy({ userId: group }), DriveFiles.calcDriveUsageOf(group), ]); return { - 'totalCount': count, - 'totalSize': size, + totalCount: count, + totalSize: size, }; } @@ -30,13 +33,16 @@ export default class PerUserDriveChart extends Chart { public async update(file: DriveFile, isAdditional: boolean): Promise { const fileSizeKb = file.size / 1000; - await this.commit({ - 'totalCount': isAdditional ? 1 : -1, - 'totalSize': isAdditional ? fileSizeKb : -fileSizeKb, - 'incCount': isAdditional ? 1 : 0, - 'incSize': isAdditional ? fileSizeKb : 0, - 'decCount': isAdditional ? 0 : 1, - 'decSize': isAdditional ? 0 : fileSizeKb, - }, file.userId); + await this.commit( + { + totalCount: isAdditional ? 1 : -1, + totalSize: isAdditional ? fileSizeKb : -fileSizeKb, + incCount: isAdditional ? 1 : 0, + incSize: isAdditional ? fileSizeKb : 0, + decCount: isAdditional ? 0 : 1, + decSize: isAdditional ? 0 : fileSizeKb, + }, + file.userId, + ); } } diff --git a/packages/backend/src/services/chart/charts/per-user-following.ts b/packages/backend/src/services/chart/charts/per-user-following.ts index 02b149f52..3e8b576f2 100644 --- a/packages/backend/src/services/chart/charts/per-user-following.ts +++ b/packages/backend/src/services/chart/charts/per-user-following.ts @@ -1,19 +1,22 @@ -import Chart, { KVs } from '../core.js'; -import { Followings, Users } from '@/models/index.js'; -import { Not, IsNull } from 'typeorm'; -import { User } from '@/models/entities/user.js'; -import { name, schema } from './entities/per-user-following.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { Followings, Users } from "@/models/index.js"; +import { Not, IsNull } from "typeorm"; +import type { User } from "@/models/entities/user.js"; +import { name, schema } from "./entities/per-user-following.js"; /** * ユーザーごとのフォローに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class PerUserFollowingChart extends Chart { constructor() { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { + protected async tickMajor( + group: string, + ): Promise>> { const [ localFollowingsCount, localFollowersCount, @@ -27,10 +30,10 @@ export default class PerUserFollowingChart extends Chart { ]); return { - 'local.followings.total': localFollowingsCount, - 'local.followers.total': localFollowersCount, - 'remote.followings.total': remoteFollowingsCount, - 'remote.followers.total': remoteFollowersCount, + "local.followings.total": localFollowingsCount, + "local.followers.total": localFollowersCount, + "remote.followings.total": remoteFollowingsCount, + "remote.followers.total": remoteFollowersCount, }; } @@ -38,19 +41,29 @@ export default class PerUserFollowingChart extends Chart { return {}; } - public async update(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }, isFollow: boolean): Promise { - const prefixFollower = Users.isLocalUser(follower) ? 'local' : 'remote'; - const prefixFollowee = Users.isLocalUser(followee) ? 'local' : 'remote'; + public async update( + follower: { id: User["id"]; host: User["host"] }, + followee: { id: User["id"]; host: User["host"] }, + isFollow: boolean, + ): Promise { + const prefixFollower = Users.isLocalUser(follower) ? "local" : "remote"; + const prefixFollowee = Users.isLocalUser(followee) ? "local" : "remote"; - this.commit({ - [`${prefixFollower}.followings.total`]: isFollow ? 1 : -1, - [`${prefixFollower}.followings.inc`]: isFollow ? 1 : 0, - [`${prefixFollower}.followings.dec`]: isFollow ? 0 : 1, - }, follower.id); - this.commit({ - [`${prefixFollowee}.followers.total`]: isFollow ? 1 : -1, - [`${prefixFollowee}.followers.inc`]: isFollow ? 1 : 0, - [`${prefixFollowee}.followers.dec`]: isFollow ? 0 : 1, - }, followee.id); + this.commit( + { + [`${prefixFollower}.followings.total`]: isFollow ? 1 : -1, + [`${prefixFollower}.followings.inc`]: isFollow ? 1 : 0, + [`${prefixFollower}.followings.dec`]: isFollow ? 0 : 1, + }, + follower.id, + ); + this.commit( + { + [`${prefixFollowee}.followers.total`]: isFollow ? 1 : -1, + [`${prefixFollowee}.followers.inc`]: isFollow ? 1 : 0, + [`${prefixFollowee}.followers.dec`]: isFollow ? 0 : 1, + }, + followee.id, + ); } } diff --git a/packages/backend/src/services/chart/charts/per-user-notes.ts b/packages/backend/src/services/chart/charts/per-user-notes.ts index b9191dd08..d0190cefd 100644 --- a/packages/backend/src/services/chart/charts/per-user-notes.ts +++ b/packages/backend/src/services/chart/charts/per-user-notes.ts @@ -1,22 +1,23 @@ -import Chart, { KVs } from '../core.js'; -import { User } from '@/models/entities/user.js'; -import { Notes } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { name, schema } from './entities/per-user-notes.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import type { User } from "@/models/entities/user.js"; +import { Notes } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import { name, schema } from "./entities/per-user-notes.js"; /** * ユーザーごとのノートに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class PerUserNotesChart extends Chart { constructor() { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { - const [count] = await Promise.all([ - Notes.countBy({ userId: group }), - ]); + protected async tickMajor( + group: string, + ): Promise>> { + const [count] = await Promise.all([Notes.countBy({ userId: group })]); return { total: count, @@ -27,15 +28,27 @@ export default class PerUserNotesChart extends Chart { return {}; } - public async update(user: { id: User['id'] }, note: Note, isAdditional: boolean): Promise { - await this.commit({ - 'total': isAdditional ? 1 : -1, - 'inc': isAdditional ? 1 : 0, - 'dec': isAdditional ? 0 : 1, - 'diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, - 'diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0, - 'diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0, - 'diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, - }, user.id); + public async update( + user: { id: User["id"] }, + note: Note, + isAdditional: boolean, + ): Promise { + await this.commit( + { + total: isAdditional ? 1 : -1, + inc: isAdditional ? 1 : 0, + dec: isAdditional ? 0 : 1, + "diffs.normal": + note.replyId == null && note.renoteId == null + ? isAdditional + ? 1 + : -1 + : 0, + "diffs.renote": note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + "diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0, + "diffs.withFile": note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, + }, + user.id, + ); } } diff --git a/packages/backend/src/services/chart/charts/per-user-reactions.ts b/packages/backend/src/services/chart/charts/per-user-reactions.ts index 3a830e118..75def3de0 100644 --- a/packages/backend/src/services/chart/charts/per-user-reactions.ts +++ b/packages/backend/src/services/chart/charts/per-user-reactions.ts @@ -1,19 +1,22 @@ -import Chart, { KVs } from '../core.js'; -import { User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { Users } from '@/models/index.js'; -import { name, schema } from './entities/per-user-reactions.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { Users } from "@/models/index.js"; +import { name, schema } from "./entities/per-user-reactions.js"; /** * ユーザーごとのリアクションに関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class PerUserReactionsChart extends Chart { constructor() { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { + protected async tickMajor( + group: string, + ): Promise>> { return {}; } @@ -21,10 +24,16 @@ export default class PerUserReactionsChart extends Chart { return {}; } - public async update(user: { id: User['id'], host: User['host'] }, note: Note): Promise { - const prefix = Users.isLocalUser(user) ? 'local' : 'remote'; - this.commit({ - [`${prefix}.count`]: 1, - }, note.userId); + public async update( + user: { id: User["id"]; host: User["host"] }, + note: Note, + ): Promise { + const prefix = Users.isLocalUser(user) ? "local" : "remote"; + this.commit( + { + [`${prefix}.count`]: 1, + }, + note.userId, + ); } } diff --git a/packages/backend/src/services/chart/charts/test-grouped.ts b/packages/backend/src/services/chart/charts/test-grouped.ts index d01c9fcbd..6520099fe 100644 --- a/packages/backend/src/services/chart/charts/test-grouped.ts +++ b/packages/backend/src/services/chart/charts/test-grouped.ts @@ -1,10 +1,11 @@ -import Chart, { KVs } from '../core.js'; -import { name, schema } from './entities/test-grouped.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { name, schema } from "./entities/test-grouped.js"; /** * For testing */ -// eslint-disable-next-line import/no-default-export + export default class TestGroupedChart extends Chart { private total = {} as Record; @@ -12,9 +13,11 @@ export default class TestGroupedChart extends Chart { super(name, schema, true); } - protected async tickMajor(group: string): Promise>> { + protected async tickMajor( + group: string, + ): Promise>> { return { - 'foo.total': this.total[group], + "foo.total": this.total[group], }; } @@ -27,9 +30,12 @@ export default class TestGroupedChart extends Chart { this.total[group]++; - await this.commit({ - 'foo.total': 1, - 'foo.inc': 1, - }, group); + await this.commit( + { + "foo.total": 1, + "foo.inc": 1, + }, + group, + ); } } diff --git a/packages/backend/src/services/chart/charts/test-intersection.ts b/packages/backend/src/services/chart/charts/test-intersection.ts index 88b5a715c..0fa973861 100644 --- a/packages/backend/src/services/chart/charts/test-intersection.ts +++ b/packages/backend/src/services/chart/charts/test-intersection.ts @@ -1,10 +1,11 @@ -import Chart, { KVs } from '../core.js'; -import { name, schema } from './entities/test-intersection.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { name, schema } from "./entities/test-intersection.js"; /** * For testing */ -// eslint-disable-next-line import/no-default-export + export default class TestIntersectionChart extends Chart { constructor() { super(name, schema); diff --git a/packages/backend/src/services/chart/charts/test-unique.ts b/packages/backend/src/services/chart/charts/test-unique.ts index d714f1d40..095021622 100644 --- a/packages/backend/src/services/chart/charts/test-unique.ts +++ b/packages/backend/src/services/chart/charts/test-unique.ts @@ -1,10 +1,11 @@ -import Chart, { KVs } from '../core.js'; -import { name, schema } from './entities/test-unique.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { name, schema } from "./entities/test-unique.js"; /** * For testing */ -// eslint-disable-next-line import/no-default-export + export default class TestUniqueChart extends Chart { constructor() { super(name, schema); diff --git a/packages/backend/src/services/chart/charts/test.ts b/packages/backend/src/services/chart/charts/test.ts index adb2b18c8..afdb3bf14 100644 --- a/packages/backend/src/services/chart/charts/test.ts +++ b/packages/backend/src/services/chart/charts/test.ts @@ -1,10 +1,11 @@ -import Chart, { KVs } from '../core.js'; -import { name, schema } from './entities/test.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { name, schema } from "./entities/test.js"; /** * For testing */ -// eslint-disable-next-line import/no-default-export + export default class TestChart extends Chart { public total = 0; // publicにするのはテストのため @@ -14,7 +15,7 @@ export default class TestChart extends Chart { protected async tickMajor(): Promise>> { return { - 'foo.total': this.total, + "foo.total": this.total, }; } @@ -26,8 +27,8 @@ export default class TestChart extends Chart { this.total++; await this.commit({ - 'foo.total': 1, - 'foo.inc': 1, + "foo.total": 1, + "foo.inc": 1, }); } @@ -35,8 +36,8 @@ export default class TestChart extends Chart { this.total--; await this.commit({ - 'foo.total': -1, - 'foo.dec': 1, + "foo.total": -1, + "foo.dec": 1, }); } } diff --git a/packages/backend/src/services/chart/charts/users.ts b/packages/backend/src/services/chart/charts/users.ts index acb16ead8..6fef9ecf7 100644 --- a/packages/backend/src/services/chart/charts/users.ts +++ b/packages/backend/src/services/chart/charts/users.ts @@ -1,13 +1,14 @@ -import Chart, { KVs } from '../core.js'; -import { Users } from '@/models/index.js'; -import { Not, IsNull } from 'typeorm'; -import { User } from '@/models/entities/user.js'; -import { name, schema } from './entities/users.js'; +import type { KVs } from "../core.js"; +import Chart from "../core.js"; +import { Users } from "@/models/index.js"; +import { Not, IsNull } from "typeorm"; +import type { User } from "@/models/entities/user.js"; +import { name, schema } from "./entities/users.js"; /** * ユーザー数に関するチャート */ -// eslint-disable-next-line import/no-default-export + export default class UsersChart extends Chart { constructor() { super(name, schema); @@ -20,8 +21,8 @@ export default class UsersChart extends Chart { ]); return { - 'local.total': localCount, - 'remote.total': remoteCount, + "local.total": localCount, + "remote.total": remoteCount, }; } @@ -29,8 +30,11 @@ export default class UsersChart extends Chart { return {}; } - public async update(user: { id: User['id'], host: User['host'] }, isAdditional: boolean): Promise { - const prefix = Users.isLocalUser(user) ? 'local' : 'remote'; + public async update( + user: { id: User["id"]; host: User["host"] }, + isAdditional: boolean, + ): Promise { + const prefix = Users.isLocalUser(user) ? "local" : "remote"; await this.commit({ [`${prefix}.total`]: isAdditional ? 1 : -1, diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index 2960bac8f..750a6e0ad 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -4,38 +4,54 @@ * Tests located in test/chart */ -import * as nestedProperty from 'nested-property'; -import Logger from '../logger.js'; -import { EntitySchema, Repository, LessThan, Between } from 'typeorm'; -import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/prelude/time.js'; -import { getChartInsertLock } from '@/misc/app-lock.js'; -import { db } from '@/db/postgre.js'; +import * as nestedProperty from "nested-property"; +import Logger from "../logger.js"; +import type { Repository } from "typeorm"; +import { EntitySchema, LessThan, Between } from "typeorm"; +import { + dateUTC, + isTimeSame, + isTimeBefore, + subtractTime, + addTime, +} from "@/prelude/time.js"; +import { getChartInsertLock } from "@/misc/app-lock.js"; +import { db } from "@/db/postgre.js"; -const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test'); +const logger = new Logger("chart", "white", process.env.NODE_ENV !== "test"); -const columnPrefix = '___' as const; -const uniqueTempColumnPrefix = 'unique_temp___' as const; -const columnDot = '_' as const; +const columnPrefix = "___" as const; +const uniqueTempColumnPrefix = "unique_temp___" as const; +const columnDot = "_" as const; -type Schema = Record; + intersection?: string[] | ReadonlyArray; - range?: 'big' | 'small' | 'medium'; + range?: "big" | "small" | "medium"; - // previousな値を引き継ぐかどうか - accumulate?: boolean; -}>; + // previousな値を引き継ぐかどうか + accumulate?: boolean; + } +>; -type KeyToColumnName = T extends `${infer R1}.${infer R2}` ? `${R1}${typeof columnDot}${KeyToColumnName}` : T; +type KeyToColumnName = T extends `${infer R1}.${infer R2}` + ? `${R1}${typeof columnDot}${KeyToColumnName}` + : T; type Columns = { - [K in keyof S as `${typeof columnPrefix}${KeyToColumnName}`]: number; + [K in + keyof S as `${typeof columnPrefix}${KeyToColumnName}`]: number; }; type TempColumnsForUnique = { - [K in keyof S as `${typeof uniqueTempColumnPrefix}${KeyToColumnName}`]: S[K]['uniqueIncrement'] extends true ? string[] : never; + [K in + keyof S as `${typeof uniqueTempColumnPrefix}${KeyToColumnName< + string & K + >}`]: S[K]["uniqueIncrement"] extends true ? string[] : never; }; type RawRecord = { @@ -50,16 +66,17 @@ type RawRecord = { * 集計日時のUnixタイムスタンプ(秒) */ date: number; -} & TempColumnsForUnique & Columns; +} & TempColumnsForUnique & + Columns; const camelToSnake = (str: string): string => { - return str.replace(/([A-Z])/g, s => '_' + s.charAt(0).toLowerCase()); + return str.replace(/([A-Z])/g, (s) => `_${s.charAt(0).toLowerCase()}`); }; const removeDuplicates = (array: any[]) => Array.from(new Set(array)); type Commit = { - [K in keyof S]?: S[K]['uniqueIncrement'] extends true ? string[] : number; + [K in keyof S]?: S[K]["uniqueIncrement"] extends true ? string[] : number; }; export type KVs = { @@ -70,11 +87,19 @@ type ChartResult = { [P in keyof T]: number[]; }; -type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; +type UnionToIntersection = (T extends any ? (x: T) => any : never) extends ( + x: infer R, +) => any + ? R + : never; type UnflattenSingleton = K extends `${infer A}.${infer B}` - ? { [_ in A]: UnflattenSingleton; } - : { [_ in K]: V; }; + ? { + [_ in A]: UnflattenSingleton; + } + : { + [_ in K]: V; + }; type Unflatten> = UnionToIntersection< { @@ -83,24 +108,28 @@ type Unflatten> = UnionToIntersection< >; type ToJsonSchema = { - type: 'object'; + type: "object"; properties: { - [K in keyof S]: S[K] extends number[] ? { type: 'array'; items: { type: 'number'; }; } : ToJsonSchema; - }, + [K in keyof S]: S[K] extends number[] + ? { type: "array"; items: { type: "number" } } + : ToJsonSchema; + }; required: (keyof S)[]; }; -export function getJsonSchema(schema: S): ToJsonSchema>> { +export function getJsonSchema( + schema: S, +): ToJsonSchema>> { const jsonSchema = { - type: 'object', + type: "object", properties: {} as Record, required: [], }; for (const k in schema) { jsonSchema.properties[k] = { - type: 'array', - items: { type: 'number' }, + type: "array", + items: { type: "number" }, }; } @@ -110,7 +139,7 @@ export function getJsonSchema(schema: S): ToJsonSchema { public schema: T; @@ -122,8 +151,16 @@ export default abstract class Chart { // ↓にしたいけどfindOneとかで型エラーになる //private repositoryForHour: Repository>; //private repositoryForDay: Repository>; - private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>; - private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>; + private repositoryForHour: Repository<{ + id: number; + group?: string | null; + date: number; + }>; + private repositoryForDay: Repository<{ + id: number; + group?: string | null; + date: number; + }>; /** * 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用) @@ -135,16 +172,26 @@ export default abstract class Chart { */ protected abstract tickMinor(group: string | null): Promise>>; - private static convertSchemaToColumnDefinitions(schema: Schema): Record { - const columns = {} as Record; + private static convertSchemaToColumnDefinitions( + schema: Schema, + ): Record { + const columns = {} as Record< + string, + { type: string; array?: boolean; default?: any } + >; for (const [k, v] of Object.entries(schema)) { - const name = k.replaceAll('.', columnDot); - const type = v.range === 'big' ? 'bigint' : v.range === 'small' ? 'smallint' : 'integer'; + const name = k.replaceAll(".", columnDot); + const type = + v.range === "big" + ? "bigint" + : v.range === "small" + ? "smallint" + : "integer"; if (v.uniqueIncrement) { columns[uniqueTempColumnPrefix + name] = { - type: 'varchar', + type: "varchar", array: true, - default: '{}', + default: "{}", }; columns[columnPrefix + name] = { type, @@ -164,7 +211,9 @@ export default abstract class Chart { return Math.floor(x.getTime() / 1000); } - private static parseDate(date: Date): [number, number, number, number, number, number, number] { + private static parseDate( + date: Date, + ): [number, number, number, number, number, number, number] { const y = date.getUTCFullYear(); const m = date.getUTCMonth(); const d = date.getUTCDate(); @@ -180,53 +229,66 @@ export default abstract class Chart { return Chart.parseDate(new Date()); } - public static schemaToEntity(name: string, schema: Schema, grouped = false): { - hour: EntitySchema, - day: EntitySchema, + public static schemaToEntity( + name: string, + schema: Schema, + grouped = false, + ): { + hour: EntitySchema; + day: EntitySchema; } { - const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({ - name: - span === 'hour' ? `__chart__${camelToSnake(name)}` : - span === 'day' ? `__chart_day__${camelToSnake(name)}` : - new Error('not happen') as never, - columns: { - id: { - type: 'integer', - primary: true, - generated: true, - }, - date: { - type: 'integer', - }, - ...(grouped ? { - group: { - type: 'varchar', - length: 128, + const createEntity = (span: "hour" | "day"): EntitySchema => + new EntitySchema({ + name: + span === "hour" + ? `__chart__${camelToSnake(name)}` + : span === "day" + ? `__chart_day__${camelToSnake(name)}` + : (new Error("not happen") as never), + columns: { + id: { + type: "integer", + primary: true, + generated: true, }, - } : {}), - ...Chart.convertSchemaToColumnDefinitions(schema), - }, - indices: [{ - columns: grouped ? ['date', 'group'] : ['date'], - unique: true, - }], - uniques: [{ - columns: grouped ? ['date', 'group'] : ['date'], - }], - relations: { - /* TODO + date: { + type: "integer", + }, + ...(grouped + ? { + group: { + type: "varchar", + length: 128, + }, + } + : {}), + ...Chart.convertSchemaToColumnDefinitions(schema), + }, + indices: [ + { + columns: grouped ? ["date", "group"] : ["date"], + unique: true, + }, + ], + uniques: [ + { + columns: grouped ? ["date", "group"] : ["date"], + }, + ], + relations: { + /* TODO group: { target: () => Foo, type: 'many-to-one', onDelete: 'CASCADE', }, */ - }, - }); + }, + }); return { - hour: createEntity('hour'), - day: createEntity('day'), + hour: createEntity("hour"), + day: createEntity("day"), }; } @@ -235,21 +297,36 @@ export default abstract class Chart { this.schema = schema; const { hour, day } = Chart.schemaToEntity(name, schema, grouped); - this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour); - this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day); + this.repositoryForHour = db.getRepository<{ + id: number; + group?: string | null; + date: number; + }>(hour); + this.repositoryForDay = db.getRepository<{ + id: number; + group?: string | null; + date: number; + }>(day); } private convertRawRecord(x: RawRecord): KVs { const kvs = {} as Record; - for (const k of Object.keys(x).filter((k) => k.startsWith(columnPrefix)) as (keyof Columns)[]) { - kvs[(k as string).substr(columnPrefix.length).split(columnDot).join('.')] = x[k]; + for (const k of Object.keys(x).filter((k) => + k.startsWith(columnPrefix), + ) as (keyof Columns)[]) { + kvs[ + (k as string).substr(columnPrefix.length).split(columnDot).join(".") + ] = x[k]; } return kvs as KVs; } private getNewLog(latest: KVs | null): KVs { const log = {} as Record; - for (const [k, v] of Object.entries(this.schema) as ([keyof typeof this['schema'], this['schema'][string]])[]) { + for (const [k, v] of Object.entries(this.schema) as [ + keyof typeof this["schema"], + this["schema"][string], + ][]) { if (v.accumulate && latest) { log[k] = latest[k]; } else { @@ -259,43 +336,60 @@ export default abstract class Chart { return log as KVs; } - private getLatestLog(group: string | null, span: 'hour' | 'day'): Promise | null> { + private getLatestLog( + group: string | null, + span: "hour" | "day", + ): Promise | null> { const repository = - span === 'hour' ? this.repositoryForHour : - span === 'day' ? this.repositoryForDay : - new Error('not happen') as never; + span === "hour" + ? this.repositoryForHour + : span === "day" + ? this.repositoryForDay + : (new Error("not happen") as never); - return repository.findOne({ - where: group ? { - group: group, - } : {}, - order: { - date: -1, - }, - }).then(x => x ?? null) as Promise | null>; + return repository + .findOne({ + where: group + ? { + group: group, + } + : {}, + order: { + date: -1, + }, + }) + .then((x) => x ?? null) as Promise | null>; } /** * 現在(=今のHour or Day)のログをデータベースから探して、あればそれを返し、なければ作成して返します。 */ - private async claimCurrentLog(group: string | null, span: 'hour' | 'day'): Promise> { + private async claimCurrentLog( + group: string | null, + span: "hour" | "day", + ): Promise> { const [y, m, d, h] = Chart.getCurrentDate(); const current = dateUTC( - span === 'hour' ? [y, m, d, h] : - span === 'day' ? [y, m, d] : - new Error('not happen') as never); + span === "hour" + ? [y, m, d, h] + : span === "day" + ? [y, m, d] + : (new Error("not happen") as never), + ); const repository = - span === 'hour' ? this.repositoryForHour : - span === 'day' ? this.repositoryForDay : - new Error('not happen') as never; + span === "hour" + ? this.repositoryForHour + : span === "day" + ? this.repositoryForDay + : (new Error("not happen") as never); // 現在(=今のHour or Day)のログ - const currentLog = await repository.findOneBy({ + const currentLog = (await repository.findOneBy({ date: Chart.dateToTimestamp(current), ...(group ? { group: group } : {}), - }) as RawRecord | undefined; + })) as RawRecord | undefined; // ログがあればそれを返して終了 if (currentLog != null) { @@ -323,37 +417,51 @@ export default abstract class Chart { // 初期ログデータを作成 data = this.getNewLog(null); - logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): Initial commit created`); + logger.info( + `${ + this.name + (group ? `:${group}` : "") + }(${span}): Initial commit created`, + ); } const date = Chart.dateToTimestamp(current); - const lockKey = group ? `${this.name}:${date}:${span}:${group}` : `${this.name}:${date}:${span}`; + const lockKey = group + ? `${this.name}:${date}:${span}:${group}` + : `${this.name}:${date}:${span}`; const unlock = await getChartInsertLock(lockKey); try { // ロック内でもう1回チェックする - const currentLog = await repository.findOneBy({ + const currentLog = (await repository.findOneBy({ date: date, ...(group ? { group: group } : {}), - }) as RawRecord | undefined; + })) as RawRecord | undefined; // ログがあればそれを返して終了 if (currentLog != null) return currentLog; const columns = {} as Record; for (const [k, v] of Object.entries(data)) { - const name = k.replaceAll('.', columnDot); + const name = k.replaceAll(".", columnDot); columns[columnPrefix + name] = v; } // 新規ログ挿入 - log = await repository.insert({ - date: date, - ...(group ? { group: group } : {}), - ...columns, - }).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord; + log = (await repository + .insert({ + date: date, + ...(group ? { group: group } : {}), + ...columns, + }) + .then((x) => + repository.findOneByOrFail(x.identifiers[0]), + )) as RawRecord; - logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`); + logger.info( + `${ + this.name + (group ? `:${group}` : "") + }(${span}): New commit created`, + ); return log; } finally { @@ -363,10 +471,12 @@ export default abstract class Chart { protected commit(diff: Commit, group: string | null = null): void { for (const [k, v] of Object.entries(diff)) { - if (v == null || v === 0 || (Array.isArray(v) && v.length === 0)) delete diff[k]; + if (v == null || v === 0 || (Array.isArray(v) && v.length === 0)) + diff[k] = undefined; } this.buffer.push({ - diff, group, + diff, + group, }); } @@ -382,49 +492,81 @@ export default abstract class Chart { // そのログは本来は 01:00~ のログとしてDBに保存されて欲しいのに、02:00~ のログ扱いになってしまう。 // これを回避するための実装は複雑になりそうなため、一旦保留。 - const update = async (logHour: RawRecord, logDay: RawRecord): Promise => { + const update = async ( + logHour: RawRecord, + logDay: RawRecord, + ): Promise => { const finalDiffs = {} as Record; - for (const diff of this.buffer.filter(q => q.group == null || (q.group === logHour.group)).map(q => q.diff)) { + for (const diff of this.buffer + .filter((q) => q.group == null || q.group === logHour.group) + .map((q) => q.diff)) { for (const [k, v] of Object.entries(diff)) { if (finalDiffs[k] == null) { finalDiffs[k] = v; } else { - if (typeof finalDiffs[k] === 'number') { + if (typeof finalDiffs[k] === "number") { (finalDiffs[k] as number) += v as number; } else { - (finalDiffs[k] as string[]) = (finalDiffs[k] as string[]).concat(v); + (finalDiffs[k] as string[]) = (finalDiffs[k] as string[]).concat( + v, + ); } } } } - const queryForHour: Record, number | (() => string)> = {} as any; - const queryForDay: Record, number | (() => string)> = {} as any; + const queryForHour: Record, number | (() => string)> = + {} as any; + const queryForDay: Record, number | (() => string)> = + {} as any; for (const [k, v] of Object.entries(finalDiffs)) { - if (typeof v === 'number') { - const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; + if (typeof v === "number") { + const name = (columnPrefix + + k.replaceAll(".", columnDot)) as keyof Columns; if (v > 0) queryForHour[name] = () => `"${name}" + ${v}`; if (v < 0) queryForHour[name] = () => `"${name}" - ${Math.abs(v)}`; if (v > 0) queryForDay[name] = () => `"${name}" + ${v}`; if (v < 0) queryForDay[name] = () => `"${name}" - ${Math.abs(v)}`; - } else if (Array.isArray(v) && v.length > 0) { // ユニークインクリメント - const tempColumnName = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + } else if (Array.isArray(v) && v.length > 0) { + // ユニークインクリメント + const tempColumnName = (uniqueTempColumnPrefix + + k.replaceAll(".", columnDot)) as keyof TempColumnsForUnique; // TODO: item をSQLエスケープ - const itemsForHour = v.filter(item => !logHour[tempColumnName].includes(item)).map(item => `"${item}"`); - const itemsForDay = v.filter(item => !logDay[tempColumnName].includes(item)).map(item => `"${item}"`); - if (itemsForHour.length > 0) queryForHour[tempColumnName] = () => `array_cat("${tempColumnName}", '{${itemsForHour.join(',')}}'::varchar[])`; - if (itemsForDay.length > 0) queryForDay[tempColumnName] = () => `array_cat("${tempColumnName}", '{${itemsForDay.join(',')}}'::varchar[])`; + const itemsForHour = v + .filter((item) => !logHour[tempColumnName].includes(item)) + .map((item) => `"${item}"`); + const itemsForDay = v + .filter((item) => !logDay[tempColumnName].includes(item)) + .map((item) => `"${item}"`); + if (itemsForHour.length > 0) + queryForHour[tempColumnName] = () => + `array_cat("${tempColumnName}", '{${itemsForHour.join( + ",", + )}}'::varchar[])`; + if (itemsForDay.length > 0) + queryForDay[tempColumnName] = () => + `array_cat("${tempColumnName}", '{${itemsForDay.join( + ",", + )}}'::varchar[])`; } } // bake unique count for (const [k, v] of Object.entries(finalDiffs)) { if (this.schema[k].uniqueIncrement) { - const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; - const tempColumnName = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; - queryForHour[name] = new Set([...(v as string[]), ...logHour[tempColumnName]]).size; - queryForDay[name] = new Set([...(v as string[]), ...logDay[tempColumnName]]).size; + const name = (columnPrefix + + k.replaceAll(".", columnDot)) as keyof Columns; + const tempColumnName = (uniqueTempColumnPrefix + + k.replaceAll(".", columnDot)) as keyof TempColumnsForUnique; + queryForHour[name] = new Set([ + ...(v as string[]), + ...logHour[tempColumnName], + ]).size; + queryForDay[name] = new Set([ + ...(v as string[]), + ...logDay[tempColumnName], + ]).size; } } @@ -433,22 +575,43 @@ export default abstract class Chart { for (const [k, v] of Object.entries(this.schema)) { const intersection = v.intersection; if (intersection) { - const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; + const name = (columnPrefix + + k.replaceAll(".", columnDot)) as keyof Columns; const firstKey = intersection[0]; - const firstTempColumnName = uniqueTempColumnPrefix + firstKey.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + const firstTempColumnName = (uniqueTempColumnPrefix + + firstKey.replaceAll( + ".", + columnDot, + )) as keyof TempColumnsForUnique; const firstValues = finalDiffs[firstKey] as string[] | undefined; - const currentValuesForHour = new Set([...(firstValues ?? []), ...logHour[firstTempColumnName]]); - const currentValuesForDay = new Set([...(firstValues ?? []), ...logDay[firstTempColumnName]]); + const currentValuesForHour = new Set([ + ...(firstValues ?? []), + ...logHour[firstTempColumnName], + ]); + const currentValuesForDay = new Set([ + ...(firstValues ?? []), + ...logDay[firstTempColumnName], + ]); for (let i = 1; i < intersection.length; i++) { const targetKey = intersection[i]; - const targetTempColumnName = uniqueTempColumnPrefix + targetKey.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + const targetTempColumnName = (uniqueTempColumnPrefix + + targetKey.replaceAll( + ".", + columnDot, + )) as keyof TempColumnsForUnique; const targetValues = finalDiffs[targetKey] as string[] | undefined; - const targetValuesForHour = new Set([...(targetValues ?? []), ...logHour[targetTempColumnName]]); - const targetValuesForDay = new Set([...(targetValues ?? []), ...logDay[targetTempColumnName]]); - currentValuesForHour.forEach(v => { + const targetValuesForHour = new Set([ + ...(targetValues ?? []), + ...logHour[targetTempColumnName], + ]); + const targetValuesForDay = new Set([ + ...(targetValues ?? []), + ...logDay[targetTempColumnName], + ]); + currentValuesForHour.forEach((v) => { if (!targetValuesForHour.has(v)) currentValuesForHour.delete(v); }); - currentValuesForDay.forEach(v => { + currentValuesForDay.forEach((v) => { if (!targetValuesForDay.has(v)) currentValuesForDay.delete(v); }); } @@ -459,41 +622,57 @@ export default abstract class Chart { // ログ更新 await Promise.all([ - this.repositoryForHour.createQueryBuilder() + this.repositoryForHour + .createQueryBuilder() .update() .set(queryForHour as any) - .where('id = :id', { id: logHour.id }) + .where("id = :id", { id: logHour.id }) .execute(), - this.repositoryForDay.createQueryBuilder() + this.repositoryForDay + .createQueryBuilder() .update() .set(queryForDay as any) - .where('id = :id', { id: logDay.id }) + .where("id = :id", { id: logDay.id }) .execute(), ]); - logger.info(`${this.name + (logHour.group ? `:${logHour.group}` : '')}: Updated`); + logger.info( + `${this.name + (logHour.group ? `:${logHour.group}` : "")}: Updated`, + ); // TODO: この一連の処理が始まった後に新たにbufferに入ったものは消さないようにする - this.buffer = this.buffer.filter(q => q.group != null && (q.group !== logHour.group)); + this.buffer = this.buffer.filter( + (q) => q.group != null && q.group !== logHour.group, + ); }; - const groups = removeDuplicates(this.buffer.map(log => log.group)); + const groups = removeDuplicates(this.buffer.map((log) => log.group)); await Promise.all( - groups.map(group => + groups.map((group) => Promise.all([ - this.claimCurrentLog(group, 'hour'), - this.claimCurrentLog(group, 'day'), - ]).then(([logHour, logDay]) => - update(logHour, logDay)))); + this.claimCurrentLog(group, "hour"), + this.claimCurrentLog(group, "day"), + ]).then(([logHour, logDay]) => update(logHour, logDay)), + ), + ); } - public async tick(major: boolean, group: string | null = null): Promise { - const data = major ? await this.tickMajor(group) : await this.tickMinor(group); + public async tick( + major: boolean, + group: string | null = null, + ): Promise { + const data = major + ? await this.tickMajor(group) + : await this.tickMinor(group); const columns = {} as Record, number>; - for (const [k, v] of Object.entries(data) as ([keyof typeof data, number])[]) { - const name = columnPrefix + (k as string).replaceAll('.', columnDot) as keyof Columns; + for (const [k, v] of Object.entries(data) as [ + keyof typeof data, + number, + ][]) { + const name = (columnPrefix + + (k as string).replaceAll(".", columnDot)) as keyof Columns; columns[name] = v; } @@ -501,26 +680,30 @@ export default abstract class Chart { return; } - const update = async (logHour: RawRecord, logDay: RawRecord): Promise => { + const update = async ( + logHour: RawRecord, + logDay: RawRecord, + ): Promise => { await Promise.all([ - this.repositoryForHour.createQueryBuilder() + this.repositoryForHour + .createQueryBuilder() .update() .set(columns) - .where('id = :id', { id: logHour.id }) + .where("id = :id", { id: logHour.id }) .execute(), - this.repositoryForDay.createQueryBuilder() + this.repositoryForDay + .createQueryBuilder() .update() .set(columns) - .where('id = :id', { id: logDay.id }) + .where("id = :id", { id: logDay.id }) .execute(), ]); }; return Promise.all([ - this.claimCurrentLog(group, 'hour'), - this.claimCurrentLog(group, 'day'), - ]).then(([logHour, logDay]) => - update(logHour, logDay)); + this.claimCurrentLog(group, "hour"), + this.claimCurrentLog(group, "day"), + ]).then(([logHour, logDay]) => update(logHour, logDay)); } public resync(group: string | null = null): Promise { @@ -531,13 +714,14 @@ export default abstract class Chart { const current = dateUTC(Chart.getCurrentDate()); // 一日以上前かつ三日以内 - const gt = Chart.dateToTimestamp(current) - (60 * 60 * 24 * 3); - const lt = Chart.dateToTimestamp(current) - (60 * 60 * 24); + const gt = Chart.dateToTimestamp(current) - 60 * 60 * 24 * 3; + const lt = Chart.dateToTimestamp(current) - 60 * 60 * 24; const columns = {} as Record, []>; for (const [k, v] of Object.entries(this.schema)) { if (v.uniqueIncrement) { - const name = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + const name = (uniqueTempColumnPrefix + + k.replaceAll(".", columnDot)) as keyof TempColumnsForUnique; columns[name] = []; } } @@ -547,39 +731,62 @@ export default abstract class Chart { } await Promise.all([ - this.repositoryForHour.createQueryBuilder() + this.repositoryForHour + .createQueryBuilder() .update() .set(columns) - .where('date > :gt', { gt }) - .andWhere('date < :lt', { lt }) + .where("date > :gt", { gt }) + .andWhere("date < :lt", { lt }) .execute(), - this.repositoryForDay.createQueryBuilder() + this.repositoryForDay + .createQueryBuilder() .update() .set(columns) - .where('date > :gt', { gt }) - .andWhere('date < :lt', { lt }) + .where("date > :gt", { gt }) + .andWhere("date < :lt", { lt }) .execute(), ]); } - public async getChartRaw(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise> { - const [y, m, d, h, _m, _s, _ms] = cursor ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) : Chart.getCurrentDate(); - const [y2, m2, d2, h2] = cursor ? Chart.parseDate(addTime(cursor, 1, span)) : [] as never; + public async getChartRaw( + span: "hour" | "day", + amount: number, + cursor: Date | null, + group: string | null = null, + ): Promise> { + const [y, m, d, h, _m, _s, _ms] = cursor + ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) + : Chart.getCurrentDate(); + const [y2, m2, d2, h2] = cursor + ? Chart.parseDate(addTime(cursor, 1, span)) + : ([] as never); const lt = dateUTC([y, m, d, h, _m, _s, _ms]); const gt = - span === 'day' ? subtractTime(cursor ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), amount - 1, 'day') : - span === 'hour' ? subtractTime(cursor ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), amount - 1, 'hour') : - new Error('not happen') as never; + span === "day" + ? subtractTime( + cursor ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), + amount - 1, + "day", + ) + : span === "hour" + ? subtractTime( + cursor ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), + amount - 1, + "hour", + ) + : (new Error("not happen") as never); const repository = - span === 'hour' ? this.repositoryForHour : - span === 'day' ? this.repositoryForDay : - new Error('not happen') as never; + span === "hour" + ? this.repositoryForHour + : span === "day" + ? this.repositoryForDay + : (new Error("not happen") as never); // ログ取得 - let logs = await repository.find({ + let logs = (await repository.find({ where: { date: Between(Chart.dateToTimestamp(gt), Chart.dateToTimestamp(lt)), ...(group ? { group: group } : {}), @@ -587,30 +794,32 @@ export default abstract class Chart { order: { date: -1, }, - }) as RawRecord[]; + })) as RawRecord[]; // 要求された範囲にログがひとつもなかったら if (logs.length === 0) { // もっとも新しいログを持ってくる // (すくなくともひとつログが無いと隙間埋めできないため) - const recentLog = await repository.findOne({ - where: group ? { - group: group, - } : {}, + const recentLog = (await repository.findOne({ + where: group + ? { + group: group, + } + : {}, order: { date: -1, }, - }) as RawRecord | undefined; + })) as RawRecord | undefined; if (recentLog) { logs = [recentLog]; } - // 要求された範囲の最も古い箇所に位置するログが存在しなかったら + // 要求された範囲の最も古い箇所に位置するログが存在しなかったら } else if (!isTimeSame(new Date(logs[logs.length - 1].date * 1000), gt)) { // 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する // (隙間埋めできないため) - const outdatedLog = await repository.findOne({ + const outdatedLog = (await repository.findOne({ where: { date: LessThan(Chart.dateToTimestamp(gt)), ...(group ? { group: group } : {}), @@ -618,7 +827,7 @@ export default abstract class Chart { order: { date: -1, }, - }) as RawRecord | undefined; + })) as RawRecord | undefined; if (outdatedLog) { logs.push(outdatedLog); @@ -627,19 +836,25 @@ export default abstract class Chart { const chart: KVs[] = []; - for (let i = (amount - 1); i >= 0; i--) { + for (let i = amount - 1; i >= 0; i--) { const current = - span === 'hour' ? subtractTime(dateUTC([y, m, d, h]), i, 'hour') : - span === 'day' ? subtractTime(dateUTC([y, m, d]), i, 'day') : - new Error('not happen') as never; + span === "hour" + ? subtractTime(dateUTC([y, m, d, h]), i, "hour") + : span === "day" + ? subtractTime(dateUTC([y, m, d]), i, "day") + : (new Error("not happen") as never); - const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current)); + const log = logs.find((l) => + isTimeSame(new Date(l.date * 1000), current), + ); if (log) { chart.unshift(this.convertRawRecord(log)); } else { // 隙間埋め - const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current)); + const latest = logs.find((l) => + isTimeBefore(new Date(l.date * 1000), current), + ); const data = latest ? this.convertRawRecord(latest) : null; chart.unshift(this.getNewLog(data)); } @@ -654,7 +869,10 @@ export default abstract class Chart { * にする */ for (const record of chart) { - for (const [k, v] of Object.entries(record) as ([keyof typeof record, number])[]) { + for (const [k, v] of Object.entries(record) as [ + keyof typeof record, + number, + ][]) { if (res[k]) { res[k].push(v); } else { @@ -666,7 +884,12 @@ export default abstract class Chart { return res; } - public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise>> { + public async getChart( + span: "hour" | "day", + amount: number, + cursor: Date | null, + group: string | null = null, + ): Promise>> { const result = await this.getChartRaw(span, amount, cursor, group); const object = {}; for (const [k, v] of Object.entries(result)) { diff --git a/packages/backend/src/services/chart/entities.ts b/packages/backend/src/services/chart/entities.ts index a9eeabd63..e203dffdf 100644 --- a/packages/backend/src/services/chart/entities.ts +++ b/packages/backend/src/services/chart/entities.ts @@ -1,39 +1,57 @@ -import { entity as FederationChart } from './charts/entities/federation.js'; -import { entity as NotesChart } from './charts/entities/notes.js'; -import { entity as UsersChart } from './charts/entities/users.js'; -import { entity as ActiveUsersChart } from './charts/entities/active-users.js'; -import { entity as InstanceChart } from './charts/entities/instance.js'; -import { entity as PerUserNotesChart } from './charts/entities/per-user-notes.js'; -import { entity as DriveChart } from './charts/entities/drive.js'; -import { entity as PerUserReactionsChart } from './charts/entities/per-user-reactions.js'; -import { entity as HashtagChart } from './charts/entities/hashtag.js'; -import { entity as PerUserFollowingChart } from './charts/entities/per-user-following.js'; -import { entity as PerUserDriveChart } from './charts/entities/per-user-drive.js'; -import { entity as ApRequestChart } from './charts/entities/ap-request.js'; +import { entity as FederationChart } from "./charts/entities/federation.js"; +import { entity as NotesChart } from "./charts/entities/notes.js"; +import { entity as UsersChart } from "./charts/entities/users.js"; +import { entity as ActiveUsersChart } from "./charts/entities/active-users.js"; +import { entity as InstanceChart } from "./charts/entities/instance.js"; +import { entity as PerUserNotesChart } from "./charts/entities/per-user-notes.js"; +import { entity as DriveChart } from "./charts/entities/drive.js"; +import { entity as PerUserReactionsChart } from "./charts/entities/per-user-reactions.js"; +import { entity as HashtagChart } from "./charts/entities/hashtag.js"; +import { entity as PerUserFollowingChart } from "./charts/entities/per-user-following.js"; +import { entity as PerUserDriveChart } from "./charts/entities/per-user-drive.js"; +import { entity as ApRequestChart } from "./charts/entities/ap-request.js"; -import { entity as TestChart } from './charts/entities/test.js'; -import { entity as TestGroupedChart } from './charts/entities/test-grouped.js'; -import { entity as TestUniqueChart } from './charts/entities/test-unique.js'; -import { entity as TestIntersectionChart } from './charts/entities/test-intersection.js'; +import { entity as TestChart } from "./charts/entities/test.js"; +import { entity as TestGroupedChart } from "./charts/entities/test-grouped.js"; +import { entity as TestUniqueChart } from "./charts/entities/test-unique.js"; +import { entity as TestIntersectionChart } from "./charts/entities/test-intersection.js"; export const entities = [ - FederationChart.hour, FederationChart.day, - NotesChart.hour, NotesChart.day, - UsersChart.hour, UsersChart.day, - ActiveUsersChart.hour, ActiveUsersChart.day, - InstanceChart.hour, InstanceChart.day, - PerUserNotesChart.hour, PerUserNotesChart.day, - DriveChart.hour, DriveChart.day, - PerUserReactionsChart.hour, PerUserReactionsChart.day, - HashtagChart.hour, HashtagChart.day, - PerUserFollowingChart.hour, PerUserFollowingChart.day, - PerUserDriveChart.hour, PerUserDriveChart.day, - ApRequestChart.hour, ApRequestChart.day, + FederationChart.hour, + FederationChart.day, + NotesChart.hour, + NotesChart.day, + UsersChart.hour, + UsersChart.day, + ActiveUsersChart.hour, + ActiveUsersChart.day, + InstanceChart.hour, + InstanceChart.day, + PerUserNotesChart.hour, + PerUserNotesChart.day, + DriveChart.hour, + DriveChart.day, + PerUserReactionsChart.hour, + PerUserReactionsChart.day, + HashtagChart.hour, + HashtagChart.day, + PerUserFollowingChart.hour, + PerUserFollowingChart.day, + PerUserDriveChart.hour, + PerUserDriveChart.day, + ApRequestChart.hour, + ApRequestChart.day, - ...(process.env.NODE_ENV === 'test' ? [ - TestChart.hour, TestChart.day, - TestGroupedChart.hour, TestGroupedChart.day, - TestUniqueChart.hour, TestUniqueChart.day, - TestIntersectionChart.hour, TestIntersectionChart.day, - ] : []), + ...(process.env.NODE_ENV === "test" + ? [ + TestChart.hour, + TestChart.day, + TestGroupedChart.hour, + TestGroupedChart.day, + TestUniqueChart.hour, + TestUniqueChart.day, + TestIntersectionChart.hour, + TestIntersectionChart.day, + ] + : []), ]; diff --git a/packages/backend/src/services/chart/index.ts b/packages/backend/src/services/chart/index.ts index 8bf2d8f65..969cdab6d 100644 --- a/packages/backend/src/services/chart/index.ts +++ b/packages/backend/src/services/chart/index.ts @@ -1,17 +1,17 @@ -import { beforeShutdown } from '@/misc/before-shutdown.js'; +import { beforeShutdown } from "@/misc/before-shutdown.js"; -import FederationChart from './charts/federation.js'; -import NotesChart from './charts/notes.js'; -import UsersChart from './charts/users.js'; -import ActiveUsersChart from './charts/active-users.js'; -import InstanceChart from './charts/instance.js'; -import PerUserNotesChart from './charts/per-user-notes.js'; -import DriveChart from './charts/drive.js'; -import PerUserReactionsChart from './charts/per-user-reactions.js'; -import HashtagChart from './charts/hashtag.js'; -import PerUserFollowingChart from './charts/per-user-following.js'; -import PerUserDriveChart from './charts/per-user-drive.js'; -import ApRequestChart from './charts/ap-request.js'; +import FederationChart from "./charts/federation.js"; +import NotesChart from "./charts/notes.js"; +import UsersChart from "./charts/users.js"; +import ActiveUsersChart from "./charts/active-users.js"; +import InstanceChart from "./charts/instance.js"; +import PerUserNotesChart from "./charts/per-user-notes.js"; +import DriveChart from "./charts/drive.js"; +import PerUserReactionsChart from "./charts/per-user-reactions.js"; +import HashtagChart from "./charts/hashtag.js"; +import PerUserFollowingChart from "./charts/per-user-following.js"; +import PerUserDriveChart from "./charts/per-user-drive.js"; +import ApRequestChart from "./charts/ap-request.js"; export const federationChart = new FederationChart(); export const notesChart = new NotesChart(); @@ -48,4 +48,4 @@ setInterval(() => { } }, 1000 * 60 * 20); -beforeShutdown(() => Promise.all(charts.map(chart => chart.save()))); +beforeShutdown(() => Promise.all(charts.map((chart) => chart.save()))); diff --git a/packages/backend/src/services/create-notification.ts b/packages/backend/src/services/create-notification.ts index d53a4235b..f6545b131 100644 --- a/packages/backend/src/services/create-notification.ts +++ b/packages/backend/src/services/create-notification.ts @@ -1,17 +1,23 @@ -import { publishMainStream } from '@/services/stream.js'; -import { pushNotification } from '@/services/push-notification.js'; -import { Notifications, Mutings, UserProfiles, Users } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { User } from '@/models/entities/user.js'; -import { Notification } from '@/models/entities/notification.js'; -import { sendEmailNotification } from './send-email-notification.js'; +import { publishMainStream } from "@/services/stream.js"; +import { pushNotification } from "@/services/push-notification.js"; +import { + Notifications, + Mutings, + NoteThreadMutings, + UserProfiles, + Users, +} from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { User } from "@/models/entities/user.js"; +import type { Notification } from "@/models/entities/notification.js"; +import { sendEmailNotification } from "./send-email-notification.js"; export async function createNotification( - notifieeId: User['id'], - type: Notification['type'], - data: Partial + notifieeId: User["id"], + type: Notification["type"], + data: Partial, ) { - if (data.notifierId && (notifieeId === data.notifierId)) { + if (data.notifierId && notifieeId === data.notifierId) { return null; } @@ -19,6 +25,17 @@ export async function createNotification( const isMuted = profile?.mutingNotificationTypes.includes(type); + if (data.note != null) { + const threadMute = await NoteThreadMutings.findOneBy({ + userId: notifieeId, + threadId: data.note.threadId || data.note.id, + }); + + if (threadMute) { + return null; + } + } + // Create notification const notification = await Notifications.insert({ id: genId(), @@ -28,13 +45,14 @@ export async function createNotification( // 相手がこの通知をミュートしているようなら、既読を予めつけておく isRead: isMuted, ...data, - } as Partial) - .then(x => Notifications.findOneByOrFail(x.identifiers[0])); + } as Partial).then((x) => + Notifications.findOneByOrFail(x.identifiers[0]), + ); const packed = await Notifications.pack(notification, {}); // Publish notification event - publishMainStream(notifieeId, 'notification', packed); + publishMainStream(notifieeId, "notification", packed); // 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する setTimeout(async () => { @@ -46,16 +64,27 @@ export async function createNotification( const mutings = await Mutings.findBy({ muterId: notifieeId, }); - if (data.notifierId && mutings.map(m => m.muteeId).includes(data.notifierId)) { + if ( + data.notifierId && + mutings.map((m) => m.muteeId).includes(data.notifierId) + ) { return; } //#endregion - publishMainStream(notifieeId, 'unreadNotification', packed); - pushNotification(notifieeId, 'notification', packed); + publishMainStream(notifieeId, "unreadNotification", packed); + pushNotification(notifieeId, "notification", packed); - if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); - if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); + if (type === "follow") + sendEmailNotification.follow( + notifieeId, + await Users.findOneByOrFail({ id: data.notifierId! }), + ); + if (type === "receiveFollowRequest") + sendEmailNotification.receiveFollowRequest( + notifieeId, + await Users.findOneByOrFail({ id: data.notifierId! }), + ); }, 2000); return notification; diff --git a/packages/backend/src/services/create-system-user.ts b/packages/backend/src/services/create-system-user.ts index bae91ec4c..def3ee98f 100644 --- a/packages/backend/src/services/create-system-user.ts +++ b/packages/backend/src/services/create-system-user.ts @@ -1,14 +1,14 @@ -import bcrypt from 'bcryptjs'; -import { v4 as uuid } from 'uuid'; -import generateNativeUserToken from '../server/api/common/generate-native-user-token.js'; -import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; -import { User } from '@/models/entities/user.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { IsNull } from 'typeorm'; -import { genId } from '@/misc/gen-id.js'; -import { UserKeypair } from '@/models/entities/user-keypair.js'; -import { UsedUsername } from '@/models/entities/used-username.js'; -import { db } from '@/db/postgre.js'; +import bcrypt from "bcryptjs"; +import { v4 as uuid } from "uuid"; +import generateNativeUserToken from "../server/api/common/generate-native-user-token.js"; +import { genRsaKeyPair } from "@/misc/gen-key-pair.js"; +import { User } from "@/models/entities/user.js"; +import { UserProfile } from "@/models/entities/user-profile.js"; +import { IsNull } from "typeorm"; +import { genId } from "@/misc/gen-id.js"; +import { UserKeypair } from "@/models/entities/user-keypair.js"; +import { UsedUsername } from "@/models/entities/used-username.js"; +import { db } from "@/db/postgre.js"; export async function createSystemUser(username: string) { const password = uuid(); @@ -25,26 +25,30 @@ export async function createSystemUser(username: string) { let account!: User; // Start transaction - await db.transaction(async transactionalEntityManager => { + await db.transaction(async (transactionalEntityManager) => { const exist = await transactionalEntityManager.findOneBy(User, { usernameLower: username.toLowerCase(), host: IsNull(), }); - if (exist) throw new Error('the user is already exists'); + if (exist) throw new Error("the user is already exists"); - account = await transactionalEntityManager.insert(User, { - id: genId(), - createdAt: new Date(), - username: username, - usernameLower: username.toLowerCase(), - host: null, - token: secret, - isAdmin: false, - isLocked: true, - isExplorable: false, - isBot: true, - }).then(x => transactionalEntityManager.findOneByOrFail(User, x.identifiers[0])); + account = await transactionalEntityManager + .insert(User, { + id: genId(), + createdAt: new Date(), + username: username, + usernameLower: username.toLowerCase(), + host: null, + token: secret, + isAdmin: false, + isLocked: true, + isExplorable: false, + isBot: true, + }) + .then((x) => + transactionalEntityManager.findOneByOrFail(User, x.identifiers[0]), + ); await transactionalEntityManager.insert(UserKeypair, { publicKey: keyPair.publicKey, diff --git a/packages/backend/src/services/delete-account.ts b/packages/backend/src/services/delete-account.ts index 0fdceb671..927776199 100644 --- a/packages/backend/src/services/delete-account.ts +++ b/packages/backend/src/services/delete-account.ts @@ -1,14 +1,14 @@ -import { Users } from '@/models/index.js'; -import { createDeleteAccountJob } from '@/queue/index.js'; -import { publishUserEvent } from './stream.js'; -import { doPostSuspend } from './suspend-user.js'; +import { Users } from "@/models/index.js"; +import { createDeleteAccountJob } from "@/queue/index.js"; +import { publishUserEvent } from "./stream.js"; +import { doPostSuspend } from "./suspend-user.js"; export async function deleteAccount(user: { id: string; host: string | null; }): Promise { // 物理削除する前にDelete activityを送信する - await doPostSuspend(user).catch(e => {}); + await doPostSuspend(user).catch((e) => {}); createDeleteAccountJob(user, { soft: false, @@ -19,5 +19,5 @@ export async function deleteAccount(user: { }); // Terminate streaming - publishUserEvent(user.id, 'terminate', {}); + publishUserEvent(user.id, "terminate", {}); } diff --git a/packages/backend/src/services/detect-sensitive.ts b/packages/backend/src/services/detect-sensitive.ts index 2ade39d52..df695e86d 100644 --- a/packages/backend/src/services/detect-sensitive.ts +++ b/packages/backend/src/services/detect-sensitive.ts @@ -1,35 +1,42 @@ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import * as nsfw from 'nsfwjs'; -import si from 'systeminformation'; +import * as fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import * as nsfw from "nsfwjs"; +import si from "systeminformation"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); -const REQUIRED_CPU_FLAGS = ['avx2', 'fma']; +const REQUIRED_CPU_FLAGS = ["avx2", "fma"]; let isSupportedCpu: undefined | boolean = undefined; let model: nsfw.NSFWJS; -export async function detectSensitive(path: string): Promise { +export async function detectSensitive( + path: string, +): Promise { try { if (isSupportedCpu === undefined) { const cpuFlags = await getCpuFlags(); - isSupportedCpu = REQUIRED_CPU_FLAGS.every(required => cpuFlags.includes(required)); + isSupportedCpu = REQUIRED_CPU_FLAGS.every((required) => + cpuFlags.includes(required), + ); } if (!isSupportedCpu) { - console.error('This CPU cannot use TensorFlow.'); + console.error("This CPU cannot use TensorFlow."); return null; } - const tf = await import('@tensorflow/tfjs-node'); + const tf = await import("@tensorflow/tfjs-node"); - if (model == null) model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 }); + if (model == null) + model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { + size: 299, + }); const buffer = await fs.promises.readFile(path); - const image = await tf.node.decodeImage(buffer, 3) as any; + const image = (await tf.node.decodeImage(buffer, 3)) as any; try { const predictions = await model.classify(image); return predictions; diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 47b19e23a..b25375b94 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -1,30 +1,41 @@ -import * as fs from 'node:fs'; +import * as fs from "node:fs"; -import { v4 as uuid } from 'uuid'; +import { v4 as uuid } from "uuid"; -import S3 from 'aws-sdk/clients/s3.js'; -import sharp from 'sharp'; -import { IsNull } from 'typeorm'; -import { publishMainStream, publishDriveStream } from '@/services/stream.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { contentDisposition } from '@/misc/content-disposition.js'; -import { getFileInfo } from '@/misc/get-file-info.js'; -import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '@/models/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { IRemoteUser, User } from '@/models/entities/user.js'; -import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { getS3 } from './s3.js'; -import { InternalStorage } from './internal-storage.js'; -import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng } from './image-processor.js'; -import { driveLogger } from './logger.js'; -import { GenerateVideoThumbnail } from './generate-video-thumbnail.js'; -import { deleteFile } from './delete-file.js'; +import type S3 from "aws-sdk/clients/s3.js"; +import sharp from "sharp"; +import { IsNull } from "typeorm"; +import { publishMainStream, publishDriveStream } from "@/services/stream.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { contentDisposition } from "@/misc/content-disposition.js"; +import { getFileInfo } from "@/misc/get-file-info.js"; +import { + DriveFiles, + DriveFolders, + Users, + Instances, + UserProfiles, +} from "@/models/index.js"; +import { DriveFile } from "@/models/entities/drive-file.js"; +import type { IRemoteUser, User } from "@/models/entities/user.js"; +import { + driveChart, + perUserDriveChart, + instanceChart, +} from "@/services/chart/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; +import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import { getS3 } from "./s3.js"; +import { InternalStorage } from "./internal-storage.js"; +import type { IImage } from "./image-processor.js"; +import { convertSharpToWebp } from "./image-processor.js"; +import { driveLogger } from "./logger.js"; +import { GenerateVideoThumbnail } from "./generate-video-thumbnail.js"; +import { deleteFile } from "./delete-file.js"; -const logger = driveLogger.createSubLogger('register', 'yellow'); +const logger = driveLogger.createSubLogger("register", "yellow"); /*** * Save file @@ -34,7 +45,14 @@ const logger = driveLogger.createSubLogger('register', 'yellow'); * @param hash Hash for original * @param size Size for original */ -async function save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise { +async function save( + file: DriveFile, + path: string, + name: string, + type: string, + hash: string, + size: number, +): Promise { // thunbnail, webpublic を必要なら生成 const alts = await generateAlts(path, type, !file.uri); @@ -42,29 +60,34 @@ async function save(file: DriveFile, path: string, name: string, type: string, h if (meta.useObjectStorage) { //#region ObjectStorage params - let [ext] = (name.match(/\.([a-zA-Z0-9_-]+)$/) || ['']); + let [ext] = name.match(/\.([a-zA-Z0-9_-]+)$/) || [""]; - if (ext === '') { - if (type === 'image/jpeg') ext = '.jpg'; - if (type === 'image/png') ext = '.png'; - if (type === 'image/webp') ext = '.webp'; - if (type === 'image/apng') ext = '.apng'; - if (type === 'image/avif') ext = '.avif'; - if (type === 'image/vnd.mozilla.apng') ext = '.apng'; + if (ext === "") { + if (type === "image/jpeg") ext = ".jpg"; + if (type === "image/png") ext = ".png"; + if (type === "image/webp") ext = ".webp"; + if (type === "image/apng") ext = ".apng"; + if (type === "image/avif") ext = ".avif"; + if (type === "image/vnd.mozilla.apng") ext = ".apng"; } - // 拡張子からContent-Typeを設定してそうな挙動を示すオブジェクトストレージ (upcloud?) も存在するので、 - // 許可されているファイル形式でしか拡張子をつけない + // Some cloud providers (notably upcloud) will infer the content-type based + // on extension, so we remove extensions from non-browser-safe types. if (!FILE_TYPE_BROWSERSAFE.includes(type)) { - ext = ''; + ext = ""; } - const baseUrl = meta.objectStorageBaseUrl - || `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`; + const baseUrl = + meta.objectStorageBaseUrl || + `${meta.objectStorageUseSSL ? "https" : "http"}://${ + meta.objectStorageEndpoint + }${meta.objectStoragePort ? `:${meta.objectStoragePort}` : ""}/${ + meta.objectStorageBucket + }`; // for original const key = `${meta.objectStoragePrefix}/${uuid()}${ext}`; - const url = `${ baseUrl }/${ key }`; + const url = `${baseUrl}/${key}`; // for alts let webpublicKey: string | null = null; @@ -75,24 +98,30 @@ async function save(file: DriveFile, path: string, name: string, type: string, h //#region Uploads logger.info(`uploading original: ${key}`); - const uploads = [ - upload(key, fs.createReadStream(path), type, name), - ]; + const uploads = [upload(key, fs.createReadStream(path), type, name)]; if (alts.webpublic) { - webpublicKey = `${meta.objectStoragePrefix}/webpublic-${uuid()}.${alts.webpublic.ext}`; - webpublicUrl = `${ baseUrl }/${ webpublicKey }`; + webpublicKey = `${meta.objectStoragePrefix}/webpublic-${uuid()}.${ + alts.webpublic.ext + }`; + webpublicUrl = `${baseUrl}/${webpublicKey}`; logger.info(`uploading webpublic: ${webpublicKey}`); - uploads.push(upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, name)); + uploads.push( + upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, name), + ); } if (alts.thumbnail) { - thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${uuid()}.${alts.thumbnail.ext}`; - thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`; + thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${uuid()}.${ + alts.thumbnail.ext + }`; + thumbnailUrl = `${baseUrl}/${thumbnailKey}`; logger.info(`uploading thumbnail: ${thumbnailKey}`); - uploads.push(upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type)); + uploads.push( + upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type), + ); } await Promise.all(uploads); @@ -111,11 +140,14 @@ async function save(file: DriveFile, path: string, name: string, type: string, h file.size = size; file.storedInternal = false; - return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); - } else { // use internal storage + return await DriveFiles.insert(file).then((x) => + DriveFiles.findOneByOrFail(x.identifiers[0]), + ); + } else { + // use internal storage const accessKey = uuid(); - const thumbnailAccessKey = 'thumbnail-' + uuid(); - const webpublicAccessKey = 'webpublic-' + uuid(); + const thumbnailAccessKey = `thumbnail-${uuid()}`; + const webpublicAccessKey = `webpublic-${uuid()}`; const url = InternalStorage.saveFromPath(accessKey, path); @@ -123,12 +155,18 @@ async function save(file: DriveFile, path: string, name: string, type: string, h let webpublicUrl: string | null = null; if (alts.thumbnail) { - thumbnailUrl = InternalStorage.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data); + thumbnailUrl = InternalStorage.saveFromBuffer( + thumbnailAccessKey, + alts.thumbnail.data, + ); logger.info(`thumbnail stored: ${thumbnailAccessKey}`); } if (alts.webpublic) { - webpublicUrl = InternalStorage.saveFromBuffer(webpublicAccessKey, alts.webpublic.data); + webpublicUrl = InternalStorage.saveFromBuffer( + webpublicAccessKey, + alts.webpublic.data, + ); logger.info(`web stored: ${webpublicAccessKey}`); } @@ -145,7 +183,9 @@ async function save(file: DriveFile, path: string, name: string, type: string, h file.md5 = hash; file.size = size; - return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); + return await DriveFiles.insert(file).then((x) => + DriveFiles.findOneByOrFail(x.identifiers[0]), + ); } } @@ -155,8 +195,12 @@ async function save(file: DriveFile, path: string, name: string, type: string, h * @param type Content-Type for original * @param generateWeb Generate webpublic or not */ -export async function generateAlts(path: string, type: string, generateWeb: boolean) { - if (type.startsWith('video/')) { +export async function generateAlts( + path: string, + type: string, + generateWeb: boolean, +) { + if (type.startsWith("video/")) { try { const thumbnail = await GenerateVideoThumbnail(path); return { @@ -172,8 +216,16 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } } - if (!['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml', 'image/avif'].includes(type)) { - logger.debug('web image and thumbnail not created (not an required file)'); + if ( + ![ + "image/jpeg", + "image/png", + "image/webp", + "image/svg+xml", + "image/avif", + ].includes(type) + ) { + logger.debug("web image and thumbnail not created (not an required file)"); return { webpublic: null, thumbnail: null, @@ -197,10 +249,18 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } satisfyWebpublic = !!( - type !== 'image/svg+xml' && type !== 'image/webp' && - !(metadata.exif || metadata.iptc || metadata.xmp || metadata.tifftagPhotoshop) && - metadata.width && metadata.width <= 2048 && - metadata.height && metadata.height <= 2048 + type !== "image/svg+xml" && + type !== "image/webp" && + !( + metadata.exif || + metadata.iptc || + metadata.xmp || + metadata.tifftagPhotoshop + ) && + metadata.width && + metadata.width <= 2048 && + metadata.height && + metadata.height <= 2048 ); } catch (err) { logger.warn(`sharp failed: ${err}`); @@ -214,26 +274,27 @@ export async function generateAlts(path: string, type: string, generateWeb: bool let webpublic: IImage | null = null; if (generateWeb && !satisfyWebpublic) { - logger.info('creating web image'); + logger.info("creating web image"); try { - if (['image/jpeg'].includes(type)) { - webpublic = await convertSharpToJpeg(img, 2048, 2048); - } else if (['image/webp'].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); - } else if (['image/png'].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); - } else if (['image/svg+xml'].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); + if (["image/jpeg"].includes(type)) { + webpublic = await convertSharpToWebp(img, 2048, 2048); + } else if (["image/webp"].includes(type)) { + webpublic = await convertSharpToWebp(img, 2048, 2048); + } else if (["image/png"].includes(type)) { + webpublic = await convertSharpToWebp(img, 2048, 2048, 100); + } else if (["image/svg+xml"].includes(type)) { + webpublic = await convertSharpToWebp(img, 2048, 2048); } else { - logger.debug('web image not created (not an required image)'); + logger.debug("web image not created (not an required image)"); } } catch (err) { - logger.warn('web image not created (an error occured)', err as Error); + logger.warn("web image not created (an error occured)", err as Error); } } else { - if (satisfyWebpublic) logger.info('web image not created (original satisfies webpublic)'); - else logger.info('web image not created (from remote)'); + if (satisfyWebpublic) + logger.info("web image not created (original satisfies webpublic)"); + else logger.info("web image not created (from remote)"); } // #endregion webpublic @@ -241,13 +302,21 @@ export async function generateAlts(path: string, type: string, generateWeb: bool let thumbnail: IImage | null = null; try { - if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml', 'image/avif'].includes(type)) { - thumbnail = await convertSharpToWebp(img, 498, 280); + if ( + [ + "image/jpeg", + "image/webp", + "image/png", + "image/svg+xml", + "image/avif", + ].includes(type) + ) { + thumbnail = await convertSharpToWebp(img, 996, 560); } else { - logger.debug('thumbnail not created (not an required file)'); + logger.debug("thumbnail not created (not an required file)"); } } catch (err) { - logger.warn('thumbnail not created (an error occured)', err as Error); + logger.warn("thumbnail not created (an error occured)", err as Error); } // #endregion thumbnail @@ -260,9 +329,14 @@ export async function generateAlts(path: string, type: string, generateWeb: bool /** * Upload to ObjectStorage */ -async function upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) { - if (type === 'image/apng') type = 'image/png'; - if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream'; +async function upload( + key: string, + stream: fs.ReadStream | Buffer, + type: string, + filename?: string, +) { + if (type === "image/apng") type = "image/png"; + if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = "application/octet-stream"; const meta = await fetchMeta(); @@ -271,36 +345,43 @@ async function upload(key: string, stream: fs.ReadStream | Buffer, type: string, Key: key, Body: stream, ContentType: type, - CacheControl: 'max-age=31536000, immutable', + CacheControl: "max-age=31536000, immutable", } as S3.PutObjectRequest; - if (filename) params.ContentDisposition = contentDisposition('inline', filename); - if (meta.objectStorageSetPublicRead) params.ACL = 'public-read'; + if (filename) + params.ContentDisposition = contentDisposition("inline", filename); + if (meta.objectStorageSetPublicRead) params.ACL = "public-read"; const s3 = getS3(meta); const upload = s3.upload(params, { - partSize: s3.endpoint.hostname === 'storage.googleapis.com' ? 500 * 1024 * 1024 : 8 * 1024 * 1024, + partSize: + s3.endpoint.hostname === "storage.googleapis.com" + ? 500 * 1024 * 1024 + : 8 * 1024 * 1024, }); const result = await upload.promise(); - if (result) logger.debug(`Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`); + if (result) + logger.debug( + `Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`, + ); } async function deleteOldFile(user: IRemoteUser) { - const q = DriveFiles.createQueryBuilder('file') - .where('file.userId = :userId', { userId: user.id }) - .andWhere('file.isLink = FALSE'); + const q = DriveFiles.createQueryBuilder("file") + .where("file.userId = :userId", { userId: user.id }) + .andWhere("file.isLink = FALSE"); if (user.avatarId) { - q.andWhere('file.id != :avatarId', { avatarId: user.avatarId }); + q.andWhere("file.id != :avatarId", { avatarId: user.avatarId }); } if (user.bannerId) { - q.andWhere('file.id != :bannerId', { bannerId: user.bannerId }); + q.andWhere("file.id != :bannerId", { bannerId: user.bannerId }); } - q.orderBy('file.id', 'ASC'); + q.orderBy("file.id", "ASC"); const oldFile = await q.getOne(); @@ -311,7 +392,11 @@ async function deleteOldFile(user: IRemoteUser) { type AddFileArgs = { /** User who wish to add file */ - user: { id: User['id']; host: User['host']; driveCapacityOverrideMb: User['driveCapacityOverrideMb'] } | null; + user: { + id: User["id"]; + host: User["host"]; + driveCapacityOverrideMb: User["driveCapacityOverrideMb"]; + } | null; /** File path */ path: string; /** Name */ @@ -356,20 +441,35 @@ export async function addFile({ let skipNsfwCheck = false; const instance = await fetchMeta(); if (user == null) skipNsfwCheck = true; - if (instance.sensitiveMediaDetection === 'none') skipNsfwCheck = true; - if (user && instance.sensitiveMediaDetection === 'local' && Users.isRemoteUser(user)) skipNsfwCheck = true; - if (user && instance.sensitiveMediaDetection === 'remote' && Users.isLocalUser(user)) skipNsfwCheck = true; + if (instance.sensitiveMediaDetection === "none") skipNsfwCheck = true; + if ( + user && + instance.sensitiveMediaDetection === "local" && + Users.isRemoteUser(user) + ) + skipNsfwCheck = true; + if ( + user && + instance.sensitiveMediaDetection === "remote" && + Users.isLocalUser(user) + ) + skipNsfwCheck = true; const info = await getFileInfo(path, { skipSensitiveDetection: skipNsfwCheck, sensitiveThreshold: // 感度が高いほどしきい値は低くすることになる - instance.sensitiveMediaDetectionSensitivity === 'veryHigh' ? 0.1 : - instance.sensitiveMediaDetectionSensitivity === 'high' ? 0.3 : - instance.sensitiveMediaDetectionSensitivity === 'low' ? 0.7 : - instance.sensitiveMediaDetectionSensitivity === 'veryLow' ? 0.9 : - 0.5, + instance.sensitiveMediaDetectionSensitivity === "veryHigh" + ? 0.1 + : instance.sensitiveMediaDetectionSensitivity === "high" + ? 0.3 + : instance.sensitiveMediaDetectionSensitivity === "low" + ? 0.7 + : instance.sensitiveMediaDetectionSensitivity === "veryLow" + ? 0.9 + : 0.5, sensitiveThresholdForPorn: 0.75, - enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, + enableSensitiveMediaDetectionForVideos: + instance.enableSensitiveMediaDetectionForVideos, }); logger.info(`${JSON.stringify(info)}`); @@ -379,7 +479,8 @@ export async function addFile({ //} // detect name - const detectedName = name || (info.type.ext ? `untitled.${info.type.ext}` : 'untitled'); + const detectedName = + name || (info.type.ext ? `untitled.${info.type.ext}` : "untitled"); if (user && !force) { // Check if there is a file with the same hash @@ -400,12 +501,21 @@ export async function addFile({ const u = await Users.findOneBy({ id: user.id }); const instance = await fetchMeta(); - let driveCapacity = 1024 * 1024 * (Users.isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb); + let driveCapacity = + 1024 * + 1024 * + (Users.isLocalUser(user) + ? instance.localDriveCapacityMb + : instance.remoteDriveCapacityMb); if (Users.isLocalUser(user) && u?.driveCapacityOverrideMb != null) { driveCapacity = 1024 * 1024 * u.driveCapacityOverrideMb; - logger.debug('drive capacity override applied'); - logger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`); + logger.debug("drive capacity override applied"); + logger.debug( + `overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${ + usage + info.size + }bytes`, + ); } logger.debug(`drive usage is ${usage} (max: ${driveCapacity})`); @@ -413,10 +523,15 @@ export async function addFile({ // If usage limit exceeded if (usage + info.size > driveCapacity) { if (Users.isLocalUser(user)) { - throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.'); + throw new IdentifiableError( + "c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6", + "No free space.", + ); } else { // (アバターまたはバナーを含まず)最も古いファイルを削除する - deleteOldFile(await Users.findOneByOrFail({ id: user.id }) as IRemoteUser); + deleteOldFile( + (await Users.findOneByOrFail({ id: user.id })) as IRemoteUser, + ); } } } @@ -432,7 +547,7 @@ export async function addFile({ userId: user ? user.id : IsNull(), }); - if (driveFolder == null) throw new Error('folder-not-found'); + if (driveFolder == null) throw new Error("folder-not-found"); return driveFolder; }; @@ -444,14 +559,16 @@ export async function addFile({ } = {}; if (info.width) { - properties['width'] = info.width; - properties['height'] = info.height; + properties["width"] = info.width; + properties["height"] = info.height; } if (info.orientation != null) { - properties['orientation'] = info.orientation; + properties["orientation"] = info.orientation; } - const profile = user ? await UserProfiles.findOneBy({ userId: user.id }) : null; + const profile = user + ? await UserProfiles.findOneBy({ userId: user.id }) + : null; const folder = await fetchFolder(); @@ -470,14 +587,16 @@ export async function addFile({ file.maybeSensitive = info.sensitive; file.maybePorn = info.porn; file.isSensitive = user - ? Users.isLocalUser(user) && profile!.alwaysMarkNsfw ? true : - (sensitive !== null && sensitive !== undefined) + ? Users.isLocalUser(user) && profile!.alwaysMarkNsfw + ? true + : sensitive !== null && sensitive !== undefined ? sensitive : false : false; if (info.sensitive && profile!.autoSensitive) file.isSensitive = true; - if (info.sensitive && instance.setSensitiveFlagAutomatically) file.isSensitive = true; + if (info.sensitive && instance.setSensitiveFlagAutomatically) + file.isSensitive = true; if (url !== null) { file.src = url; @@ -486,8 +605,8 @@ export async function addFile({ file.url = url; // ローカルプロキシ用 file.accessKey = uuid(); - file.thumbnailAccessKey = 'thumbnail-' + uuid(); - file.webpublicAccessKey = 'webpublic-' + uuid(); + file.thumbnailAccessKey = `thumbnail-${uuid()}`; + file.webpublicAccessKey = `webpublic-${uuid()}`; } } @@ -503,32 +622,41 @@ export async function addFile({ file.type = info.type.mime; file.storedInternal = false; - file = await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); + file = await DriveFiles.insert(file).then((x) => + DriveFiles.findOneByOrFail(x.identifiers[0]), + ); } catch (err) { // duplicate key error (when already registered) if (isDuplicateKeyValueError(err)) { logger.info(`already registered ${file.uri}`); - file = await DriveFiles.findOneBy({ + file = (await DriveFiles.findOneBy({ uri: file.uri!, userId: user ? user.id : IsNull(), - }) as DriveFile; + })) as DriveFile; } else { logger.error(err as Error); throw err; } } } else { - file = await (save(file, path, detectedName, info.type.mime, info.md5, info.size)); + file = await save( + file, + path, + detectedName, + info.type.mime, + info.md5, + info.size, + ); } logger.succ(`drive file has been created ${file.id}`); if (user) { - DriveFiles.pack(file, { self: true }).then(packedFile => { + DriveFiles.pack(file, { self: true }).then((packedFile) => { // Publish driveFileCreated event - publishMainStream(user.id, 'driveFileCreated', packedFile); - publishDriveStream(user.id, 'fileCreated', packedFile); + publishMainStream(user.id, "driveFileCreated", packedFile); + publishDriveStream(user.id, "fileCreated", packedFile); }); } diff --git a/packages/backend/src/services/drive/delete-file.ts b/packages/backend/src/services/drive/delete-file.ts index 4816a3a31..215270df6 100644 --- a/packages/backend/src/services/drive/delete-file.ts +++ b/packages/backend/src/services/drive/delete-file.ts @@ -1,11 +1,15 @@ -import { DriveFile } from '@/models/entities/drive-file.js'; -import { InternalStorage } from './internal-storage.js'; -import { DriveFiles, Instances } from '@/models/index.js'; -import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index.js'; -import { createDeleteObjectStorageFileJob } from '@/queue/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { getS3 } from './s3.js'; -import { v4 as uuid } from 'uuid'; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { InternalStorage } from "./internal-storage.js"; +import { DriveFiles, Instances } from "@/models/index.js"; +import { + driveChart, + perUserDriveChart, + instanceChart, +} from "@/services/chart/index.js"; +import { createDeleteObjectStorageFileJob } from "@/queue/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import { getS3 } from "./s3.js"; +import { v4 as uuid } from "uuid"; export async function deleteFile(file: DriveFile, isExpired = false) { if (file.storedInternal) { @@ -74,8 +78,8 @@ async function postProcess(file: DriveFile, isExpired = false) { storedInternal: false, // ローカルプロキシ用 accessKey: uuid(), - thumbnailAccessKey: 'thumbnail-' + uuid(), - webpublicAccessKey: 'webpublic-' + uuid(), + thumbnailAccessKey: `thumbnail-${uuid()}`, + webpublicAccessKey: `webpublic-${uuid()}`, }); } else { DriveFiles.delete(file.id); @@ -94,8 +98,10 @@ export async function deleteObjectStorageFile(key: string) { const s3 = getS3(meta); - await s3.deleteObject({ - Bucket: meta.objectStorageBucket!, - Key: key, - }).promise(); + await s3 + .deleteObject({ + Bucket: meta.objectStorageBucket!, + Key: key, + }) + .promise(); } diff --git a/packages/backend/src/services/drive/generate-video-thumbnail.ts b/packages/backend/src/services/drive/generate-video-thumbnail.ts index 6e6666481..356623e79 100644 --- a/packages/backend/src/services/drive/generate-video-thumbnail.ts +++ b/packages/backend/src/services/drive/generate-video-thumbnail.ts @@ -1,7 +1,8 @@ -import * as fs from 'node:fs'; -import { createTempDir } from '@/misc/create-temp.js'; -import { IImage, convertToJpeg } from './image-processor.js'; -import FFmpeg from 'fluent-ffmpeg'; +import * as fs from "node:fs"; +import { createTempDir } from "@/misc/create-temp.js"; +import type { IImage } from "./image-processor.js"; +import { convertToWebp } from "./image-processor.js"; +import FFmpeg from "fluent-ffmpeg"; export async function GenerateVideoThumbnail(source: string): Promise { const [dir, cleanup] = await createTempDir(); @@ -11,18 +12,17 @@ export async function GenerateVideoThumbnail(source: string): Promise { FFmpeg({ source, }) - .on('end', res) - .on('error', rej) - .screenshot({ - folder: dir, - filename: 'out.png', // must have .png extension - count: 1, - timestamps: ['5%'], - }); + .on("end", res) + .on("error", rej) + .screenshot({ + folder: dir, + filename: "out.png", // must have .png extension + count: 1, + timestamps: ["5%"], + }); }); - // JPEGに変換 (Webpでもいいが、MastodonはWebpをサポートせず表示できなくなる) - return await convertToJpeg(`${dir}/out.png`, 498, 280); + return await convertToWebp(`${dir}/out.png`, 996, 560); } finally { cleanup(); } diff --git a/packages/backend/src/services/drive/image-processor.ts b/packages/backend/src/services/drive/image-processor.ts index 2c564ea59..55869f478 100644 --- a/packages/backend/src/services/drive/image-processor.ts +++ b/packages/backend/src/services/drive/image-processor.ts @@ -1,4 +1,4 @@ -import sharp from 'sharp'; +import sharp from "sharp"; export type IImage = { data: Buffer; @@ -6,46 +6,28 @@ export type IImage = { type: string; }; -/** - * Convert to JPEG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToJpeg(path: string, width: number, height: number): Promise { - return convertSharpToJpeg(await sharp(path), width, height); -} - -export async function convertSharpToJpeg(sharp: sharp.Sharp, width: number, height: number): Promise { - const data = await sharp - .resize(width, height, { - fit: 'inside', - withoutEnlargement: true, - }) - .rotate() - .jpeg({ - quality: 85, - progressive: true, - }) - .toBuffer(); - - return { - data, - ext: 'jpg', - type: 'image/jpeg', - }; -} - /** * Convert to WebP * with resize, remove metadata, resolve orientation, stop animation */ -export async function convertToWebp(path: string, width: number, height: number, quality: number = 85): Promise { +export async function convertToWebp( + path: string, + width: number, + height: number, + quality: number = 85, +): Promise { return convertSharpToWebp(await sharp(path), width, height, quality); } -export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number, quality: number = 85): Promise { +export async function convertSharpToWebp( + sharp: sharp.Sharp, + width: number, + height: number, + quality: number = 85, +): Promise { const data = await sharp .resize(width, height, { - fit: 'inside', + fit: "inside", withoutEnlargement: true, }) .rotate() @@ -56,32 +38,7 @@ export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, heig return { data, - ext: 'webp', - type: 'image/webp', - }; -} - -/** - * Convert to PNG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToPng(path: string, width: number, height: number): Promise { - return convertSharpToPng(await sharp(path), width, height); -} - -export async function convertSharpToPng(sharp: sharp.Sharp, width: number, height: number): Promise { - const data = await sharp - .resize(width, height, { - fit: 'inside', - withoutEnlargement: true, - }) - .rotate() - .png() - .toBuffer(); - - return { - data, - ext: 'png', - type: 'image/png', + ext: "webp", + type: "image/webp", }; } diff --git a/packages/backend/src/services/drive/internal-storage.ts b/packages/backend/src/services/drive/internal-storage.ts index 8f76c81ca..bccb123be 100644 --- a/packages/backend/src/services/drive/internal-storage.ts +++ b/packages/backend/src/services/drive/internal-storage.ts @@ -1,16 +1,17 @@ -import * as fs from 'node:fs'; -import * as Path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import config from '@/config/index.js'; +import * as fs from "node:fs"; +import * as Path from "node:path"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import config from "@/config/index.js"; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); export class InternalStorage { - private static readonly path = Path.resolve(_dirname, '../../../../../files'); + private static readonly path = Path.resolve(_dirname, "../../../../../files"); - public static resolvePath = (key: string) => Path.resolve(InternalStorage.path, key); + public static resolvePath = (key: string) => + Path.resolve(InternalStorage.path, key); public static read(key: string) { return fs.createReadStream(InternalStorage.resolvePath(key)); diff --git a/packages/backend/src/services/drive/logger.ts b/packages/backend/src/services/drive/logger.ts index 917a8317e..ebde2d705 100644 --- a/packages/backend/src/services/drive/logger.ts +++ b/packages/backend/src/services/drive/logger.ts @@ -1,3 +1,3 @@ -import Logger from '../logger.js'; +import Logger from "../logger.js"; -export const driveLogger = new Logger('drive', 'blue'); +export const driveLogger = new Logger("drive", "blue"); diff --git a/packages/backend/src/services/drive/s3.ts b/packages/backend/src/services/drive/s3.ts index 80e34be95..ca356e912 100644 --- a/packages/backend/src/services/drive/s3.ts +++ b/packages/backend/src/services/drive/s3.ts @@ -1,12 +1,15 @@ -import { URL } from 'node:url'; -import S3 from 'aws-sdk/clients/s3.js'; -import { Meta } from '@/models/entities/meta.js'; -import { getAgentByUrl } from '@/misc/fetch.js'; +import { URL } from "node:url"; +import S3 from "aws-sdk/clients/s3.js"; +import type { Meta } from "@/models/entities/meta.js"; +import { getAgentByUrl } from "@/misc/fetch.js"; export function getS3(meta: Meta) { - const u = meta.objectStorageEndpoint != null - ? `${meta.objectStorageUseSSL ? 'https://' : 'http://'}${meta.objectStorageEndpoint}` - : `${meta.objectStorageUseSSL ? 'https://' : 'http://'}example.net`; + const u = + meta.objectStorageEndpoint != null + ? `${meta.objectStorageUseSSL ? "https://" : "http://"}${ + meta.objectStorageEndpoint + }` + : `${meta.objectStorageUseSSL ? "https://" : "http://"}example.net`; return new S3({ endpoint: meta.objectStorageEndpoint || undefined, @@ -14,7 +17,7 @@ export function getS3(meta: Meta) { secretAccessKey: meta.objectStorageSecretKey!, region: meta.objectStorageRegion || undefined, sslEnabled: meta.objectStorageUseSSL, - s3ForcePathStyle: !meta.objectStorageEndpoint // AWS with endPoint omitted + s3ForcePathStyle: !meta.objectStorageEndpoint // AWS with endPoint omitted ? false : meta.objectStorageS3ForcePathStyle, httpOptions: { diff --git a/packages/backend/src/services/drive/upload-from-url.ts b/packages/backend/src/services/drive/upload-from-url.ts index 3c5e1aa5c..9d71757e3 100644 --- a/packages/backend/src/services/drive/upload-from-url.ts +++ b/packages/backend/src/services/drive/upload-from-url.ts @@ -1,19 +1,19 @@ -import { URL } from 'node:url'; -import { User } from '@/models/entities/user.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { downloadUrl } from '@/misc/download-url.js'; -import { DriveFolder } from '@/models/entities/drive-folder.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles } from '@/models/index.js'; -import { driveLogger } from './logger.js'; -import { addFile } from './add-file.js'; +import { URL } from "node:url"; +import type { User } from "@/models/entities/user.js"; +import { createTemp } from "@/misc/create-temp.js"; +import { downloadUrl } from "@/misc/download-url.js"; +import type { DriveFolder } from "@/models/entities/drive-folder.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { DriveFiles } from "@/models/index.js"; +import { driveLogger } from "./logger.js"; +import { addFile } from "./add-file.js"; -const logger = driveLogger.createSubLogger('downloader'); +const logger = driveLogger.createSubLogger("downloader"); type Args = { url: string; - user: { id: User['id']; host: User['host'] } | null; - folderId?: DriveFolder['id'] | null; + user: { id: User["id"]; host: User["host"] } | null; + folderId?: DriveFolder["id"] | null; uri?: string | null; sensitive?: boolean; force?: boolean; @@ -35,7 +35,7 @@ export async function uploadFromUrl({ requestIp = null, requestHeaders = null, }: Args): Promise { - let name = new URL(url).pathname.split('/').pop() || null; + let name = new URL(url).pathname.split("/").pop() || null; if (name == null || !DriveFiles.validateFileName(name)) { name = null; } @@ -53,7 +53,20 @@ export async function uploadFromUrl({ // write content at URL to temp file await downloadUrl(url, path); - const driveFile = await addFile({ user, path, name, comment, folderId, force, isLink, url, uri, sensitive, requestIp, requestHeaders }); + const driveFile = await addFile({ + user, + path, + name, + comment, + folderId, + force, + isLink, + url, + uri, + sensitive, + requestIp, + requestHeaders, + }); logger.succ(`Got: ${driveFile.id}`); return driveFile!; } catch (e) { diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 4bf101bb4..79354448f 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -1,22 +1,29 @@ -import { DOMWindow, JSDOM } from 'jsdom'; -import fetch from 'node-fetch'; -import tinycolor from 'tinycolor2'; -import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; -import { Instance } from '@/models/entities/instance.js'; -import { Instances } from '@/models/index.js'; -import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js'; -import Logger from './logger.js'; -import { URL } from 'node:url'; +import { URL } from "node:url"; +import { JSDOM } from "jsdom"; +import fetch from "node-fetch"; +import tinycolor from "tinycolor2"; +import { getJson, getHtml, getAgentByUrl } from "@/misc/fetch.js"; +import type { Instance } from "@/models/entities/instance.js"; +import { Instances } from "@/models/index.js"; +import { getFetchInstanceMetadataLock } from "@/misc/app-lock.js"; +import Logger from "./logger.js"; +import type { DOMWindow } from "jsdom"; -const logger = new Logger('metadata', 'cyan'); +const logger = new Logger("metadata", "cyan"); -export async function fetchInstanceMetadata(instance: Instance, force = false): Promise { +export async function fetchInstanceMetadata( + instance: Instance, + force = false, +): Promise { const unlock = await getFetchInstanceMetadataLock(instance.host); if (!force) { const _instance = await Instances.findOneBy({ host: instance.host }); const now = Date.now(); - if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) { + if ( + _instance?.infoUpdatedAt && + now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24 + ) { unlock(); return; } @@ -49,8 +56,16 @@ export async function fetchInstanceMetadata(instance: Instance, force = false): updates.softwareName = info.software?.name.toLowerCase(); updates.softwareVersion = info.software?.version; updates.openRegistrations = info.openRegistrations; - updates.maintainerName = info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.name || null) : null : null; - updates.maintainerEmail = info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.email || null) : null : null; + updates.maintainerName = info.metadata + ? info.metadata.maintainer + ? info.metadata.maintainer.name || null + : null + : null; + updates.maintainerEmail = info.metadata + ? info.metadata.maintainer + ? info.metadata.maintainer.email || null + : null + : null; } if (name) updates.name = name; @@ -91,34 +106,40 @@ async function fetchNodeinfo(instance: Instance): Promise { logger.info(`Fetching nodeinfo of ${instance.host} ...`); try { - const wellknown = await getJson('https://' + instance.host + '/.well-known/nodeinfo') - .catch(e => { - if (e.statusCode === 404) { - throw new Error('No nodeinfo provided'); - } else { - throw new Error(e.statusCode || e.message); - } - }) as Record; + const wellknown = (await getJson( + `https://${instance.host}/.well-known/nodeinfo`, + ).catch((e) => { + if (e.statusCode === 404) { + throw new Error("No nodeinfo provided"); + } else { + throw new Error(e.statusCode || e.message); + } + })) as Record; if (wellknown.links == null || !Array.isArray(wellknown.links)) { - throw new Error('No wellknown links'); + throw new Error("No wellknown links"); } const links = wellknown.links as any[]; - const lnik1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0'); - const lnik2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0'); - const lnik2_1 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.1'); + const lnik1_0 = links.find( + (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/1.0", + ); + const lnik2_0 = links.find( + (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0", + ); + const lnik2_1 = links.find( + (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1", + ); const link = lnik2_1 || lnik2_0 || lnik1_0; if (link == null) { - throw new Error('No nodeinfo link provided'); + throw new Error("No nodeinfo link provided"); } - const info = await getJson(link.href) - .catch(e => { - throw new Error(e.statusCode || e.message); - }); + const info = await getJson(link.href).catch((e) => { + throw new Error(e.statusCode || e.message); + }); logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`); @@ -130,10 +151,10 @@ async function fetchNodeinfo(instance: Instance): Promise { } } -async function fetchDom(instance: Instance): Promise { +async function fetchDom(instance: Instance): Promise { logger.info(`Fetching HTML of ${instance.host} ...`); - const url = 'https://' + instance.host; + const url = `https://${instance.host}`; const html = await getHtml(url); @@ -143,29 +164,36 @@ async function fetchDom(instance: Instance): Promise { return doc; } -async function fetchManifest(instance: Instance): Promise | null> { - const url = 'https://' + instance.host; +async function fetchManifest( + instance: Instance, +): Promise | null> { + const url = `https://${instance.host}`; - const manifestUrl = url + '/manifest.json'; + const manifestUrl = `${url}/manifest.json`; - const manifest = await getJson(manifestUrl) as Record; + const manifest = (await getJson(manifestUrl)) as Record; return manifest; } -async function fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise { - const url = 'https://' + instance.host; +async function fetchFaviconUrl( + instance: Instance, + doc: DOMWindow["document"] | null, +): Promise { + const url = `https://${instance.host}`; if (doc) { // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 - const href = Array.from(doc.getElementsByTagName('link')).reverse().find(link => link.relList.contains('icon'))?.href; + const href = Array.from(doc.getElementsByTagName("link")) + .reverse() + .find((link) => link.relList.contains("icon"))?.href; if (href) { - return (new URL(href, url)).href; + return new URL(href, url).href; } } - const faviconUrl = url + '/favicon.ico'; + const faviconUrl = `${url}/favicon.ico`; const favicon = await fetch(faviconUrl, { // TODO @@ -180,36 +208,47 @@ async function fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | return null; } -async function fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { - if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) { - const url = 'https://' + instance.host; - return (new URL(manifest.icons[0].src, url)).href; +async function fetchIconUrl( + instance: Instance, + doc: DOMWindow["document"] | null, + manifest: Record | null, +): Promise { + if (manifest?.icons && manifest.icons.length > 0 && manifest.icons[0].src) { + const url = `https://${instance.host}`; + return new URL(manifest.icons[0].src, url).href; } if (doc) { - const url = 'https://' + instance.host; + const url = `https://${instance.host}`; // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 - const links = Array.from(doc.getElementsByTagName('link')).reverse(); + const links = Array.from(doc.getElementsByTagName("link")).reverse(); // https://github.com/misskey-dev/misskey/pull/8220/files/0ec4eba22a914e31b86874f12448f88b3e58dd5a#r796487559 - const href = - [ - links.find(link => link.relList.contains('apple-touch-icon-precomposed'))?.href, - links.find(link => link.relList.contains('apple-touch-icon'))?.href, - links.find(link => link.relList.contains('icon'))?.href, - ] - .find(href => href); + const href = [ + links.find((link) => + link.relList.contains("apple-touch-icon-precomposed"), + )?.href, + links.find((link) => link.relList.contains("apple-touch-icon"))?.href, + links.find((link) => link.relList.contains("icon"))?.href, + ].find((href) => href); if (href) { - return (new URL(href, url)).href; + return new URL(href, url).href; } } return null; } -async function getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { - const themeColor = info?.metadata?.themeColor || doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') || manifest?.theme_color; +async function getThemeColor( + info: NodeInfo | null, + doc: DOMWindow["document"] | null, + manifest: Record | null, +): Promise { + const themeColor = + info?.metadata?.themeColor || + doc?.querySelector('meta[name="theme-color"]')?.getAttribute("content") || + manifest?.theme_color; if (themeColor) { const color = new tinycolor(themeColor); @@ -219,15 +258,21 @@ async function getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | return null; } -async function getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { - if (info && info.metadata) { +async function getSiteName( + info: NodeInfo | null, + doc: DOMWindow["document"] | null, + manifest: Record | null, +): Promise { + if (info?.metadata) { if (info.metadata.nodeName || info.metadata.name) { return info.metadata.nodeName || info.metadata.name; } } if (doc) { - const og = doc.querySelector('meta[property="og:title"]')?.getAttribute('content'); + const og = doc + .querySelector('meta[property="og:title"]') + ?.getAttribute("content"); if (og) { return og; @@ -235,33 +280,41 @@ async function getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | n } if (manifest) { - return manifest?.name || manifest?.short_name; + return manifest.name || manifest.short_name; } return null; } -async function getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { - if (info && info.metadata) { +async function getDescription( + info: NodeInfo | null, + doc: DOMWindow["document"] | null, + manifest: Record | null, +): Promise { + if (info?.metadata) { if (info.metadata.nodeDescription || info.metadata.description) { return info.metadata.nodeDescription || info.metadata.description; } } if (doc) { - const meta = doc.querySelector('meta[name="description"]')?.getAttribute('content'); + const meta = doc + .querySelector('meta[name="description"]') + ?.getAttribute("content"); if (meta) { return meta; } - const og = doc.querySelector('meta[property="og:description"]')?.getAttribute('content'); + const og = doc + .querySelector('meta[property="og:description"]') + ?.getAttribute("content"); if (og) { return og; } } if (manifest) { - return manifest?.name || manifest?.short_name; + return manifest.name || manifest.short_name; } return null; diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index 72c24676b..635d706fc 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -1,26 +1,51 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderAccept from '@/remote/activitypub/renderer/accept.js'; -import renderReject from '@/remote/activitypub/renderer/reject.js'; -import { deliver } from '@/queue/index.js'; -import createFollowRequest from './requests/create.js'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; -import Logger from '../logger.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { User } from '@/models/entities/user.js'; -import { Followings, Users, FollowRequests, Blockings, Instances, UserProfiles } from '@/models/index.js'; -import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { createNotification } from '../create-notification.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; -import { Packed } from '@/misc/schema.js'; -import { getActiveWebhooks } from '@/misc/webhook-cache.js'; -import { webhookDeliver } from '@/queue/index.js'; +import { publishMainStream, publishUserEvent } from "@/services/stream.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderAccept from "@/remote/activitypub/renderer/accept.js"; +import renderReject from "@/remote/activitypub/renderer/reject.js"; +import { deliver } from "@/queue/index.js"; +import createFollowRequest from "./requests/create.js"; +import { registerOrFetchInstanceDoc } from "../register-or-fetch-instance-doc.js"; +import Logger from "../logger.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { User } from "@/models/entities/user.js"; +import { + Followings, + Users, + FollowRequests, + Blockings, + Instances, + UserProfiles, +} from "@/models/index.js"; +import { + instanceChart, + perUserFollowingChart, +} from "@/services/chart/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { createNotification } from "../create-notification.js"; +import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; +import type { Packed } from "@/misc/schema.js"; +import { getActiveWebhooks } from "@/misc/webhook-cache.js"; +import { webhookDeliver } from "@/queue/index.js"; -const logger = new Logger('following/create'); +const logger = new Logger("following/create"); -export async function insertFollowingDoc(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'] }, follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'] }) { +export async function insertFollowingDoc( + followee: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + follower: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, +) { if (follower.id === followee.id) return; let alreadyFollowed = false; @@ -34,12 +59,20 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ // 非正規化 followerHost: follower.host, followerInbox: Users.isRemoteUser(follower) ? follower.inbox : null, - followerSharedInbox: Users.isRemoteUser(follower) ? follower.sharedInbox : null, + followerSharedInbox: Users.isRemoteUser(follower) + ? follower.sharedInbox + : null, followeeHost: followee.host, followeeInbox: Users.isRemoteUser(followee) ? followee.inbox : null, - followeeSharedInbox: Users.isRemoteUser(followee) ? followee.sharedInbox : null, - }).catch(e => { - if (isDuplicateKeyValueError(e) && Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { + followeeSharedInbox: Users.isRemoteUser(followee) + ? followee.sharedInbox + : null, + }).catch((e) => { + if ( + isDuplicateKeyValueError(e) && + Users.isRemoteUser(follower) && + Users.isLocalUser(followee) + ) { logger.info(`Insert duplicated ignore. ${follower.id} => ${followee.id}`); alreadyFollowed = true; } else { @@ -58,8 +91,8 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ followerId: follower.id, }); - // 通知を作成 - createNotification(follower.id, 'followRequestAccepted', { + // Create notification that request was accepted. + createNotification(follower.id, "followRequestAccepted", { notifierId: followee.id, }); } @@ -68,20 +101,20 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ //#region Increment counts await Promise.all([ - Users.increment({ id: follower.id }, 'followingCount', 1), - Users.increment({ id: followee.id }, 'followersCount', 1), + Users.increment({ id: follower.id }, "followingCount", 1), + Users.increment({ id: followee.id }, "followersCount", 1), ]); //#endregion //#region Update instance stats if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - registerOrFetchInstanceDoc(follower.host).then(i => { - Instances.increment({ id: i.id }, 'followingCount', 1); + registerOrFetchInstanceDoc(follower.host).then((i) => { + Instances.increment({ id: i.id }, "followingCount", 1); instanceChart.updateFollowing(i.host, true); }); } else if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { - registerOrFetchInstanceDoc(followee.host).then(i => { - Instances.increment({ id: i.id }, 'followersCount', 1); + registerOrFetchInstanceDoc(followee.host).then((i) => { + Instances.increment({ id: i.id }, "followersCount", 1); instanceChart.updateFollowers(i.host, true); }); } @@ -93,13 +126,23 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ if (Users.isLocalUser(follower)) { Users.pack(followee.id, follower, { detail: true, - }).then(async packed => { - publishUserEvent(follower.id, 'follow', packed as Packed<"UserDetailedNotMe">); - publishMainStream(follower.id, 'follow', packed as Packed<"UserDetailedNotMe">); + }).then(async (packed) => { + publishUserEvent( + follower.id, + "follow", + packed as Packed<"UserDetailedNotMe">, + ); + publishMainStream( + follower.id, + "follow", + packed as Packed<"UserDetailedNotMe">, + ); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === follower.id && x.on.includes("follow"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'follow', { + webhookDeliver(webhook, "follow", { user: packed, }); } @@ -108,25 +151,31 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ // Publish followed event if (Users.isLocalUser(followee)) { - Users.pack(follower.id, followee).then(async packed => { - publishMainStream(followee.id, 'followed', packed); + Users.pack(follower.id, followee).then(async (packed) => { + publishMainStream(followee.id, "followed", packed); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === followee.id && x.on.includes('followed')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === followee.id && x.on.includes("followed"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'followed', { + webhookDeliver(webhook, "followed", { user: packed, }); } }); // 通知を作成 - createNotification(followee.id, 'follow', { + createNotification(followee.id, "follow", { notifierId: follower.id, }); } } -export default async function(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string) { +export default async function ( + _follower: { id: User["id"] }, + _followee: { id: User["id"] }, + requestId?: string, +) { const [follower, followee] = await Promise.all([ Users.findOneByOrFail({ id: _follower.id }), Users.findOneByOrFail({ id: _followee.id }), @@ -146,25 +195,45 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us if (Users.isRemoteUser(follower) && Users.isLocalUser(followee) && blocked) { // リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。 - const content = renderActivity(renderReject(renderFollow(follower, followee, requestId), followee)); - deliver(followee , content, follower.inbox); + const content = renderActivity( + renderReject(renderFollow(follower, followee, requestId), followee), + ); + deliver(followee, content, follower.inbox); return; - } else if (Users.isRemoteUser(follower) && Users.isLocalUser(followee) && blocking) { + } else if ( + Users.isRemoteUser(follower) && + Users.isLocalUser(followee) && + blocking + ) { // リモートフォローを受けてブロックされているはずの場合だったら、ブロック解除しておく。 await Blockings.delete(blocking.id); } else { // それ以外は単純に例外 - if (blocking != null) throw new IdentifiableError('710e8fb0-b8c3-4922-be49-d5d93d8e6a6e', 'blocking'); - if (blocked != null) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked'); + if (blocking != null) + throw new IdentifiableError( + "710e8fb0-b8c3-4922-be49-d5d93d8e6a6e", + "blocking", + ); + if (blocked != null) + throw new IdentifiableError( + "3338392a-f764-498d-8855-db939dcf8c48", + "blocked", + ); } - const followeeProfile = await UserProfiles.findOneByOrFail({ userId: followee.id }); + const followeeProfile = await UserProfiles.findOneByOrFail({ + userId: followee.id, + }); // フォロー対象が鍵アカウントである or // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである // 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく - if (followee.isLocked || (followeeProfile.carefulBot && follower.isBot) || (Users.isLocalUser(follower) && Users.isRemoteUser(followee))) { + if ( + followee.isLocked || + (followeeProfile.carefulBot && follower.isBot) || + (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) + ) { let autoAccept = false; // 鍵アカウントであっても、既にフォローされていた場合はスルー @@ -177,7 +246,11 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us } // フォローしているユーザーは自動承認オプション - if (!autoAccept && (Users.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) { + if ( + !autoAccept && + Users.isLocalUser(followee) && + followeeProfile.autoAcceptFollowed + ) { const followed = await Followings.findOneBy({ followerId: followee.id, followeeId: follower.id, @@ -195,7 +268,9 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us await insertFollowingDoc(followee, follower); if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - const content = renderActivity(renderAccept(renderFollow(follower, followee, requestId), followee)); + const content = renderActivity( + renderAccept(renderFollow(follower, followee, requestId), followee), + ); deliver(followee, content, follower.inbox); } } diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index 91b5a3d61..fae4bd3ce 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -1,26 +1,47 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import renderReject from '@/remote/activitypub/renderer/reject.js'; -import { deliver, webhookDeliver } from '@/queue/index.js'; -import Logger from '../logger.js'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; -import { User } from '@/models/entities/user.js'; -import { Followings, Users, Instances } from '@/models/index.js'; -import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js'; -import { getActiveWebhooks } from '@/misc/webhook-cache.js'; +import { publishMainStream, publishUserEvent } from "@/services/stream.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import renderReject from "@/remote/activitypub/renderer/reject.js"; +import { deliver, webhookDeliver } from "@/queue/index.js"; +import Logger from "../logger.js"; +import { registerOrFetchInstanceDoc } from "../register-or-fetch-instance-doc.js"; +import type { User } from "@/models/entities/user.js"; +import { Followings, Users, Instances } from "@/models/index.js"; +import { + instanceChart, + perUserFollowingChart, +} from "@/services/chart/index.js"; +import { getActiveWebhooks } from "@/misc/webhook-cache.js"; -const logger = new Logger('following/delete'); +const logger = new Logger("following/delete"); -export default async function(follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, silent = false) { +export default async function ( + follower: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + followee: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + silent = false, +) { const following = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); if (following == null) { - logger.warn('フォロー解除がリクエストされましたがフォローしていませんでした'); + logger.warn( + "フォロー解除がリクエストされましたがフォローしていませんでした", + ); return; } @@ -32,13 +53,15 @@ export default async function(follower: { id: User['id']; host: User['host']; ur if (!silent && Users.isLocalUser(follower)) { Users.pack(followee.id, follower, { detail: true, - }).then(async packed => { - publishUserEvent(follower.id, 'unfollow', packed); - publishMainStream(follower.id, 'unfollow', packed); + }).then(async (packed) => { + publishUserEvent(follower.id, "unfollow", packed); + publishMainStream(follower.id, "unfollow", packed); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === follower.id && x.on.includes("unfollow"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'unfollow', { + webhookDeliver(webhook, "unfollow", { user: packed, }); } @@ -46,34 +69,41 @@ export default async function(follower: { id: User['id']; host: User['host']; ur } if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { - const content = renderActivity(renderUndo(renderFollow(follower, followee), follower)); + const content = renderActivity( + renderUndo(renderFollow(follower, followee), follower), + ); deliver(follower, content, followee.inbox); } if (Users.isLocalUser(followee) && Users.isRemoteUser(follower)) { // local user has null host - const content = renderActivity(renderReject(renderFollow(follower, followee), followee)); + const content = renderActivity( + renderReject(renderFollow(follower, followee), followee), + ); deliver(followee, content, follower.inbox); } } -export async function decrementFollowing(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }) { +export async function decrementFollowing( + follower: { id: User["id"]; host: User["host"] }, + followee: { id: User["id"]; host: User["host"] }, +) { //#region Decrement following / followers counts await Promise.all([ - Users.decrement({ id: follower.id }, 'followingCount', 1), - Users.decrement({ id: followee.id }, 'followersCount', 1), + Users.decrement({ id: follower.id }, "followingCount", 1), + Users.decrement({ id: followee.id }, "followersCount", 1), ]); //#endregion //#region Update instance stats if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - registerOrFetchInstanceDoc(follower.host).then(i => { - Instances.decrement({ id: i.id }, 'followingCount', 1); + registerOrFetchInstanceDoc(follower.host).then((i) => { + Instances.decrement({ id: i.id }, "followingCount", 1); instanceChart.updateFollowing(i.host, false); }); } else if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) { - registerOrFetchInstanceDoc(followee.host).then(i => { - Instances.decrement({ id: i.id }, 'followersCount', 1); + registerOrFetchInstanceDoc(followee.host).then((i) => { + Instances.decrement({ id: i.id }, "followersCount", 1); instanceChart.updateFollowers(i.host, false); }); } diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts index 691fca245..7464219bf 100644 --- a/packages/backend/src/services/following/reject.ts +++ b/packages/backend/src/services/following/reject.ts @@ -1,24 +1,29 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderReject from '@/remote/activitypub/renderer/reject.js'; -import { deliver, webhookDeliver } from '@/queue/index.js'; -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { Users, FollowRequests, Followings } from '@/models/index.js'; -import { decrementFollowing } from './delete.js'; -import { getActiveWebhooks } from '@/misc/webhook-cache.js'; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderReject from "@/remote/activitypub/renderer/reject.js"; +import { deliver, webhookDeliver } from "@/queue/index.js"; +import { publishMainStream, publishUserEvent } from "@/services/stream.js"; +import type { ILocalUser, IRemoteUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import { Users, FollowRequests, Followings } from "@/models/index.js"; +import { decrementFollowing } from "./delete.js"; +import { getActiveWebhooks } from "@/misc/webhook-cache.js"; -type Local = ILocalUser | { - id: ILocalUser['id']; - host: ILocalUser['host']; - uri: ILocalUser['uri'] -}; -type Remote = IRemoteUser | { - id: IRemoteUser['id']; - host: IRemoteUser['host']; - uri: IRemoteUser['uri']; - inbox: IRemoteUser['inbox']; -}; +type Local = + | ILocalUser + | { + id: ILocalUser["id"]; + host: ILocalUser["host"]; + uri: ILocalUser["uri"]; + }; +type Remote = + | IRemoteUser + | { + id: IRemoteUser["id"]; + host: IRemoteUser["host"]; + uri: IRemoteUser["uri"]; + inbox: IRemoteUser["inbox"]; + }; type Both = Local | Remote; /** @@ -98,7 +103,12 @@ async function deliverReject(followee: Local, follower: Remote) { followerId: follower.id, }); - const content = renderActivity(renderReject(renderFollow(follower, followee, request?.requestId || undefined), followee)); + const content = renderActivity( + renderReject( + renderFollow(follower, followee, request?.requestId || undefined), + followee, + ), + ); deliver(followee, content, follower.inbox); } @@ -110,12 +120,14 @@ async function publishUnfollow(followee: Both, follower: Local) { detail: true, }); - publishUserEvent(follower.id, 'unfollow', packedFollowee); - publishMainStream(follower.id, 'unfollow', packedFollowee); + publishUserEvent(follower.id, "unfollow", packedFollowee); + publishMainStream(follower.id, "unfollow", packedFollowee); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === follower.id && x.on.includes("unfollow"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'unfollow', { + webhookDeliver(webhook, "unfollow", { user: packedFollowee, }); } diff --git a/packages/backend/src/services/following/requests/accept-all.ts b/packages/backend/src/services/following/requests/accept-all.ts index 5fbb549e0..269243379 100644 --- a/packages/backend/src/services/following/requests/accept-all.ts +++ b/packages/backend/src/services/following/requests/accept-all.ts @@ -1,12 +1,18 @@ -import accept from './accept.js'; -import { User } from '@/models/entities/user.js'; -import { FollowRequests, Users } from '@/models/index.js'; +import accept from "./accept.js"; +import type { User } from "@/models/entities/user.js"; +import { FollowRequests, Users } from "@/models/index.js"; /** - * 指定したユーザー宛てのフォローリクエストをすべて承認 - * @param user ユーザー + * Approve all follow requests for the specified user + * @param user User. */ -export default async function(user: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }) { +export default async function (user: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; +}) { const requests = await FollowRequests.findBy({ followeeId: user.id, }); diff --git a/packages/backend/src/services/following/requests/accept.ts b/packages/backend/src/services/following/requests/accept.ts index 20829f70c..6aa17b09a 100644 --- a/packages/backend/src/services/following/requests/accept.ts +++ b/packages/backend/src/services/following/requests/accept.ts @@ -1,31 +1,49 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderAccept from '@/remote/activitypub/renderer/accept.js'; -import { deliver } from '@/queue/index.js'; -import { publishMainStream } from '@/services/stream.js'; -import { insertFollowingDoc } from '../create.js'; -import { User, ILocalUser, CacheableUser } from '@/models/entities/user.js'; -import { FollowRequests, Users } from '@/models/index.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderAccept from "@/remote/activitypub/renderer/accept.js"; +import { deliver } from "@/queue/index.js"; +import { publishMainStream } from "@/services/stream.js"; +import { insertFollowingDoc } from "../create.js"; +import type { User, CacheableUser } from "@/models/entities/user.js"; +import { ILocalUser } from "@/models/entities/user.js"; +import { FollowRequests, Users } from "@/models/index.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; -export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, follower: CacheableUser) { +export default async function ( + followee: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + follower: CacheableUser, +) { const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); if (request == null) { - throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.'); + throw new IdentifiableError( + "8884c2dd-5795-4ac9-b27e-6a01d38190f9", + "No follow request.", + ); } await insertFollowingDoc(followee, follower); if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - const content = renderActivity(renderAccept(renderFollow(follower, followee, request.requestId!), followee)); + const content = renderActivity( + renderAccept( + renderFollow(follower, followee, request.requestId!), + followee, + ), + ); deliver(followee, content, follower.inbox); } Users.pack(followee.id, followee, { detail: true, - }).then(packed => publishMainStream(followee.id, 'meUpdated', packed)); + }).then((packed) => publishMainStream(followee.id, "meUpdated", packed)); } diff --git a/packages/backend/src/services/following/requests/cancel.ts b/packages/backend/src/services/following/requests/cancel.ts index 56531fa1f..00daae380 100644 --- a/packages/backend/src/services/following/requests/cancel.ts +++ b/packages/backend/src/services/following/requests/cancel.ts @@ -1,17 +1,29 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { deliver } from '@/queue/index.js'; -import { publishMainStream } from '@/services/stream.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { User, ILocalUser } from '@/models/entities/user.js'; -import { Users, FollowRequests } from '@/models/index.js'; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { deliver } from "@/queue/index.js"; +import { publishMainStream } from "@/services/stream.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { User } from "@/models/entities/user.js"; +import { ILocalUser } from "@/models/entities/user.js"; +import { Users, FollowRequests } from "@/models/index.js"; -export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox'] }, follower: { id: User['id']; host: User['host']; uri: User['host'] }) { +export default async function ( + followee: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + }, + follower: { id: User["id"]; host: User["host"]; uri: User["host"] }, +) { if (Users.isRemoteUser(followee)) { - const content = renderActivity(renderUndo(renderFollow(follower, followee), follower)); + const content = renderActivity( + renderUndo(renderFollow(follower, followee), follower), + ); - if (Users.isLocalUser(follower)) { // 本来このチェックは不要だけどTSに怒られるので + if (Users.isLocalUser(follower)) { + // 本来このチェックは不要だけどTSに怒られるので deliver(follower, content, followee.inbox); } } @@ -22,7 +34,10 @@ export default async function(followee: { id: User['id']; host: User['host']; ur }); if (request == null) { - throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'request not found'); + throw new IdentifiableError( + "17447091-ce07-46dd-b331-c1fd4f15b1e7", + "request not found", + ); } await FollowRequests.delete({ @@ -32,5 +47,5 @@ export default async function(followee: { id: User['id']; host: User['host']; ur Users.pack(followee.id, followee, { detail: true, - }).then(packed => publishMainStream(followee.id, 'meUpdated', packed)); + }).then((packed) => publishMainStream(followee.id, "meUpdated", packed)); } diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts index bda2f8f92..0833f2aeb 100644 --- a/packages/backend/src/services/following/requests/create.ts +++ b/packages/backend/src/services/following/requests/create.ts @@ -1,13 +1,29 @@ -import { publishMainStream } from '@/services/stream.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderFollow from '@/remote/activitypub/renderer/follow.js'; -import { deliver } from '@/queue/index.js'; -import { User } from '@/models/entities/user.js'; -import { Blockings, FollowRequests, Users } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { createNotification } from '../../create-notification.js'; +import { publishMainStream } from "@/services/stream.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderFollow from "@/remote/activitypub/renderer/follow.js"; +import { deliver } from "@/queue/index.js"; +import type { User } from "@/models/entities/user.js"; +import { Blockings, FollowRequests, Users } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { createNotification } from "../../create-notification.js"; -export default async function(follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, requestId?: string) { +export default async function ( + follower: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + followee: { + id: User["id"]; + host: User["host"]; + uri: User["host"]; + inbox: User["inbox"]; + sharedInbox: User["sharedInbox"]; + }, + requestId?: string, +) { if (follower.id === followee.id) return; // check blocking @@ -22,8 +38,8 @@ export default async function(follower: { id: User['id']; host: User['host']; ur }), ]); - if (blocking != null) throw new Error('blocking'); - if (blocked != null) throw new Error('blocked'); + if (blocking != null) throw new Error("blocking"); + if (blocked != null) throw new Error("blocked"); const followRequest = await FollowRequests.insert({ id: genId(), @@ -35,22 +51,28 @@ export default async function(follower: { id: User['id']; host: User['host']; ur // 非正規化 followerHost: follower.host, followerInbox: Users.isRemoteUser(follower) ? follower.inbox : undefined, - followerSharedInbox: Users.isRemoteUser(follower) ? follower.sharedInbox : undefined, + followerSharedInbox: Users.isRemoteUser(follower) + ? follower.sharedInbox + : undefined, followeeHost: followee.host, followeeInbox: Users.isRemoteUser(followee) ? followee.inbox : undefined, - followeeSharedInbox: Users.isRemoteUser(followee) ? followee.sharedInbox : undefined, - }).then(x => FollowRequests.findOneByOrFail(x.identifiers[0])); + followeeSharedInbox: Users.isRemoteUser(followee) + ? followee.sharedInbox + : undefined, + }).then((x) => FollowRequests.findOneByOrFail(x.identifiers[0])); // Publish receiveRequest event if (Users.isLocalUser(followee)) { - Users.pack(follower.id, followee).then(packed => publishMainStream(followee.id, 'receiveFollowRequest', packed)); + Users.pack(follower.id, followee).then((packed) => + publishMainStream(followee.id, "receiveFollowRequest", packed), + ); Users.pack(followee.id, followee, { detail: true, - }).then(packed => publishMainStream(followee.id, 'meUpdated', packed)); + }).then((packed) => publishMainStream(followee.id, "meUpdated", packed)); // 通知を作成 - createNotification(followee.id, 'receiveFollowRequest', { + createNotification(followee.id, "receiveFollowRequest", { notifierId: follower.id, followRequestId: followRequest.id, }); diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts index f35392a34..97045a9fa 100644 --- a/packages/backend/src/services/i/pin.ts +++ b/packages/backend/src/services/i/pin.ts @@ -1,22 +1,25 @@ -import config from '@/config/index.js'; -import renderAdd from '@/remote/activitypub/renderer/add.js'; -import renderRemove from '@/remote/activitypub/renderer/remove.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { Notes, UserNotePinings, Users } from '@/models/index.js'; -import { UserNotePining } from '@/models/entities/user-note-pining.js'; -import { genId } from '@/misc/gen-id.js'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; -import { deliverToRelays } from '../relay.js'; +import config from "@/config/index.js"; +import renderAdd from "@/remote/activitypub/renderer/add.js"; +import renderRemove from "@/remote/activitypub/renderer/remove.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { Notes, UserNotePinings, Users } from "@/models/index.js"; +import type { UserNotePining } from "@/models/entities/user-note-pining.js"; +import { genId } from "@/misc/gen-id.js"; +import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js"; +import { deliverToRelays } from "../relay.js"; /** * 指定した投稿をピン留めします * @param user * @param noteId */ -export async function addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { +export async function addPinned( + user: { id: User["id"]; host: User["host"] }, + noteId: Note["id"], +) { // Fetch pinee const note = await Notes.findOneBy({ id: noteId, @@ -24,17 +27,26 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n }); if (note == null) { - throw new IdentifiableError('70c4e51f-5bea-449c-a030-53bee3cce202', 'No such note.'); + throw new IdentifiableError( + "70c4e51f-5bea-449c-a030-53bee3cce202", + "No such note.", + ); } const pinings = await UserNotePinings.findBy({ userId: user.id }); if (pinings.length >= 5) { - throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.'); + throw new IdentifiableError( + "15a018eb-58e5-4da1-93be-330fcc5e4e1a", + "You can not pin notes any more.", + ); } - if (pinings.some(pining => pining.noteId === note.id)) { - throw new IdentifiableError('23f0cf4e-59a3-4276-a91d-61a5891c1514', 'That note has already been pinned.'); + if (pinings.some((pining) => pining.noteId === note.id)) { + throw new IdentifiableError( + "23f0cf4e-59a3-4276-a91d-61a5891c1514", + "That note has already been pinned.", + ); } await UserNotePinings.insert({ @@ -55,7 +67,10 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n * @param user * @param noteId */ -export async function removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { +export async function removePinned( + user: { id: User["id"]; host: User["host"] }, + noteId: Note["id"], +) { // Fetch unpinee const note = await Notes.findOneBy({ id: noteId, @@ -63,7 +78,10 @@ export async function removePinned(user: { id: User['id']; host: User['host']; } }); if (note == null) { - throw new IdentifiableError('b302d4cf-c050-400a-bbb3-be208681f40c', 'No such note.'); + throw new IdentifiableError( + "b302d4cf-c050-400a-bbb3-be208681f40c", + "No such note.", + ); } UserNotePinings.delete({ @@ -77,15 +95,23 @@ export async function removePinned(user: { id: User['id']; host: User['host']; } } } -export async function deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) { +export async function deliverPinnedChange( + userId: User["id"], + noteId: Note["id"], + isAddition: boolean, +) { const user = await Users.findOneBy({ id: userId }); - if (user == null) throw new Error('user not found'); + if (user == null) throw new Error("user not found"); if (!Users.isLocalUser(user)) return; const target = `${config.url}/users/${user.id}/collections/featured`; const item = `${config.url}/notes/${noteId}`; - const content = renderActivity(isAddition ? renderAdd(user, target, item) : renderRemove(user, target, item)); + const content = renderActivity( + isAddition + ? renderAdd(user, target, item) + : renderRemove(user, target, item), + ); deliverToFollowers(user, content); deliverToRelays(user, content); diff --git a/packages/backend/src/services/i/update.ts b/packages/backend/src/services/i/update.ts index 27bd38bd3..cc950ac85 100644 --- a/packages/backend/src/services/i/update.ts +++ b/packages/backend/src/services/i/update.ts @@ -1,18 +1,20 @@ -import renderUpdate from '@/remote/activitypub/renderer/update.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { Users } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { renderPerson } from '@/remote/activitypub/renderer/person.js'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; -import { deliverToRelays } from '../relay.js'; +import renderUpdate from "@/remote/activitypub/renderer/update.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { Users } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import { renderPerson } from "@/remote/activitypub/renderer/person.js"; +import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js"; +import { deliverToRelays } from "../relay.js"; -export async function publishToFollowers(userId: User['id']) { +export async function publishToFollowers(userId: User["id"]) { const user = await Users.findOneBy({ id: userId }); - if (user == null) throw new Error('user not found'); + if (user == null) throw new Error("user not found"); // フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信 if (Users.isLocalUser(user)) { - const content = renderActivity(renderUpdate(await renderPerson(user), user)); + const content = renderActivity( + renderUpdate(await renderPerson(user), user), + ); deliverToFollowers(user, content); deliverToRelays(user, content); } diff --git a/packages/backend/src/services/insert-moderation-log.ts b/packages/backend/src/services/insert-moderation-log.ts index 0a7c472d8..8e2c5b78a 100644 --- a/packages/backend/src/services/insert-moderation-log.ts +++ b/packages/backend/src/services/insert-moderation-log.ts @@ -1,8 +1,12 @@ -import { ModerationLogs } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { User } from '@/models/entities/user.js'; +import { ModerationLogs } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { User } from "@/models/entities/user.js"; -export async function insertModerationLog(moderator: { id: User['id'] }, type: string, info?: Record) { +export async function insertModerationLog( + moderator: { id: User["id"] }, + type: string, + info?: Record, +) { await ModerationLogs.insert({ id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/services/instance-actor.ts b/packages/backend/src/services/instance-actor.ts index bddd0355a..50ce227eb 100644 --- a/packages/backend/src/services/instance-actor.ts +++ b/packages/backend/src/services/instance-actor.ts @@ -1,10 +1,10 @@ -import { createSystemUser } from './create-system-user.js'; -import { ILocalUser } from '@/models/entities/user.js'; -import { Users } from '@/models/index.js'; -import { Cache } from '@/misc/cache.js'; -import { IsNull } from 'typeorm'; +import { createSystemUser } from "./create-system-user.js"; +import type { ILocalUser } from "@/models/entities/user.js"; +import { Users } from "@/models/index.js"; +import { Cache } from "@/misc/cache.js"; +import { IsNull } from "typeorm"; -const ACTOR_USERNAME = 'instance.actor' as const; +const ACTOR_USERNAME = "instance.actor" as const; const cache = new Cache(Infinity); @@ -12,16 +12,16 @@ export async function getInstanceActor(): Promise { const cached = cache.get(null); if (cached) return cached; - const user = await Users.findOneBy({ + const user = (await Users.findOneBy({ host: IsNull(), username: ACTOR_USERNAME, - }) as ILocalUser | undefined; + })) as ILocalUser | undefined; if (user) { cache.set(null, user); return user; } else { - const created = await createSystemUser(ACTOR_USERNAME) as ILocalUser; + const created = (await createSystemUser(ACTOR_USERNAME)) as ILocalUser; cache.set(null, created); return created; } diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index b57272547..86e1d10d3 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -1,18 +1,18 @@ -import cluster from 'node:cluster'; -import chalk from 'chalk'; -import { default as convertColor } from 'color-convert'; -import { format as dateFormat } from 'date-fns'; -import { envOption } from '../env.js'; -import config from '@/config/index.js'; +import cluster from "node:cluster"; +import chalk from "chalk"; +import { default as convertColor } from "color-convert"; +import { format as dateFormat } from "date-fns"; +import { envOption } from "../env.js"; +import config from "@/config/index.js"; -import * as SyslogPro from 'syslog-pro'; +import * as SyslogPro from "syslog-pro"; type Domain = { name: string; color?: string; }; -type Level = 'error' | 'success' | 'warning' | 'debug' | 'info'; +type Level = "error" | "success" | "warning" | "debug" | "info"; export default class Logger { private domain: Domain; @@ -29,7 +29,7 @@ export default class Logger { if (config.syslog) { this.syslogClient = new SyslogPro.RFC5424({ - applacationName: 'Calckey', + applacationName: "Calckey", timestamp: true, encludeStructuredData: true, color: true, @@ -48,81 +48,152 @@ export default class Logger { return logger; } - private log(level: Level, message: string, data?: Record | null, important = false, subDomains: Domain[] = [], store = true): void { + private log( + level: Level, + message: string, + data?: Record | null, + important = false, + subDomains: Domain[] = [], + store = true, + ): void { if (envOption.quiet) return; if (!this.store) store = false; - if (level === 'debug') store = false; + if (level === "debug") store = false; if (this.parentLogger) { - this.parentLogger.log(level, message, data, important, [this.domain].concat(subDomains), store); + this.parentLogger.log( + level, + message, + data, + important, + [this.domain].concat(subDomains), + store, + ); return; } - const time = dateFormat(new Date(), 'HH:mm:ss'); - const worker = cluster.isPrimary ? '*' : cluster.worker.id; + const time = dateFormat(new Date(), "HH:mm:ss"); + const worker = cluster.isPrimary ? "*" : cluster.worker.id; const l = - level === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') : - level === 'warning' ? chalk.yellow('WARN') : - level === 'success' ? important ? chalk.bgGreen.white('DONE') : chalk.green('DONE') : - level === 'debug' ? chalk.gray('VERB') : - level === 'info' ? chalk.blue('INFO') : - null; - const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) : chalk.white(d.name)); + level === "error" + ? important + ? chalk.bgRed.white("ERR ") + : chalk.red("ERR ") + : level === "warning" + ? chalk.yellow("WARN") + : level === "success" + ? important + ? chalk.bgGreen.white("DONE") + : chalk.green("DONE") + : level === "debug" + ? chalk.gray("VERB") + : level === "info" + ? chalk.blue("INFO") + : null; + const domains = [this.domain] + .concat(subDomains) + .map((d) => + d.color + ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) + : chalk.white(d.name), + ); const m = - level === 'error' ? chalk.red(message) : - level === 'warning' ? chalk.yellow(message) : - level === 'success' ? chalk.green(message) : - level === 'debug' ? chalk.gray(message) : - level === 'info' ? message : - null; + level === "error" + ? chalk.red(message) + : level === "warning" + ? chalk.yellow(message) + : level === "success" + ? chalk.green(message) + : level === "debug" + ? chalk.gray(message) + : level === "info" + ? message + : null; - let log = `${l} ${worker}\t[${domains.join(' ')}]\t${m}`; - if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log; + let log = `${l} ${worker}\t[${domains.join(" ")}]\t${m}`; + if (envOption.withLogTime) log = `${chalk.gray(time)} ${log}`; console.log(important ? chalk.bold(log) : log); if (store) { if (this.syslogClient) { const send = - level === 'error' ? this.syslogClient.error : - level === 'warning' ? this.syslogClient.warning : - level === 'success' ? this.syslogClient.info : - level === 'debug' ? this.syslogClient.info : - level === 'info' ? this.syslogClient.info : - null as never; + level === "error" + ? this.syslogClient.error + : level === "warning" + ? this.syslogClient.warning + : level === "success" + ? this.syslogClient.info + : level === "debug" + ? this.syslogClient.info + : level === "info" + ? this.syslogClient.info + : (null as never); - send.bind(this.syslogClient)(message).catch(() => {}); + send + .bind(this.syslogClient)(message) + .catch(() => {}); } } } - public error(x: string | Error, data?: Record | null, important = false): void { // 実行を継続できない状況で使う + public error( + x: string | Error, + data?: Record | null, + important = false, + ): void { + // 実行を継続できない状況で使う if (x instanceof Error) { data = data || {}; data.e = x; - this.log('error', x.toString(), data, important); - } else if (typeof x === 'object') { - this.log('error', `${(x as any).message || (x as any).name || x}`, data, important); + this.log("error", x.toString(), data, important); + } else if (typeof x === "object") { + this.log( + "error", + `${(x as any).message || (x as any).name || x}`, + data, + important, + ); } else { - this.log('error', `${x}`, data, important); + this.log("error", `${x}`, data, important); } } - public warn(message: string, data?: Record | null, important = false): void { // 実行を継続できるが改善すべき状況で使う - this.log('warning', message, data, important); + public warn( + message: string, + data?: Record | null, + important = false, + ): void { + // 実行を継続できるが改善すべき状況で使う + this.log("warning", message, data, important); } - public succ(message: string, data?: Record | null, important = false): void { // 何かに成功した状況で使う - this.log('success', message, data, important); + public succ( + message: string, + data?: Record | null, + important = false, + ): void { + // 何かに成功した状況で使う + this.log("success", message, data, important); } - public debug(message: string, data?: Record | null, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報) - if (process.env.NODE_ENV !== 'production' || envOption.verbose) { - this.log('debug', message, data, important); + public debug( + message: string, + data?: Record | null, + important = false, + ): void { + // デバッグ用に使う(開発者に必要だが利用者に不要な情報) + if (process.env.NODE_ENV !== "production" || envOption.verbose) { + this.log("debug", message, data, important); } } - public info(message: string, data?: Record | null, important = false): void { // それ以外 - this.log('info', message, data, important); + public info( + message: string, + data?: Record | null, + important = false, + ): void { + // それ以外 + this.log("info", message, data, important); } } diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts index e6b320492..506f29996 100644 --- a/packages/backend/src/services/messages/create.ts +++ b/packages/backend/src/services/messages/create.ts @@ -1,19 +1,36 @@ -import { CacheableUser, User } from '@/models/entities/user.js'; -import { UserGroup } from '@/models/entities/user-group.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { MessagingMessages, UserGroupJoinings, Mutings, Users } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { publishMessagingStream, publishMessagingIndexStream, publishMainStream, publishGroupMessagingStream } from '@/services/stream.js'; -import { pushNotification } from '@/services/push-notification.js'; -import { Not } from 'typeorm'; -import { Note } from '@/models/entities/note.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import renderCreate from '@/remote/activitypub/renderer/create.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { deliver } from '@/queue/index.js'; +import type { CacheableUser, User } from "@/models/entities/user.js"; +import type { UserGroup } from "@/models/entities/user-group.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import { + MessagingMessages, + UserGroupJoinings, + Mutings, + Users, +} from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { + publishMessagingStream, + publishMessagingIndexStream, + publishMainStream, + publishGroupMessagingStream, +} from "@/services/stream.js"; +import { pushNotification } from "@/services/push-notification.js"; +import { Not } from "typeorm"; +import type { Note } from "@/models/entities/note.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import renderCreate from "@/remote/activitypub/renderer/create.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { deliver } from "@/queue/index.js"; -export async function createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { +export async function createMessage( + user: { id: User["id"]; host: User["host"] }, + recipientUser: CacheableUser | undefined, + recipientGroup: UserGroup | undefined, + text: string | null | undefined, + file: DriveFile | null, + uri?: string, +) { const message = { id: genId(), createdAt: new Date(), @@ -34,26 +51,38 @@ export async function createMessage(user: { id: User['id']; host: User['host']; if (recipientUser) { if (Users.isLocalUser(user)) { // 自分のストリーム - publishMessagingStream(message.userId, recipientUser.id, 'message', messageObj); - publishMessagingIndexStream(message.userId, 'message', messageObj); - publishMainStream(message.userId, 'messagingMessage', messageObj); + publishMessagingStream( + message.userId, + recipientUser.id, + "message", + messageObj, + ); + publishMessagingIndexStream(message.userId, "message", messageObj); + publishMainStream(message.userId, "messagingMessage", messageObj); } if (Users.isLocalUser(recipientUser)) { // 相手のストリーム - publishMessagingStream(recipientUser.id, message.userId, 'message', messageObj); - publishMessagingIndexStream(recipientUser.id, 'message', messageObj); - publishMainStream(recipientUser.id, 'messagingMessage', messageObj); + publishMessagingStream( + recipientUser.id, + message.userId, + "message", + messageObj, + ); + publishMessagingIndexStream(recipientUser.id, "message", messageObj); + publishMainStream(recipientUser.id, "messagingMessage", messageObj); } } else if (recipientGroup) { // グループのストリーム - publishGroupMessagingStream(recipientGroup.id, 'message', messageObj); + publishGroupMessagingStream(recipientGroup.id, "message", messageObj); // メンバーのストリーム - const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id }); + const joinings = await UserGroupJoinings.findBy({ + userGroupId: recipientGroup.id, + }); for (const joining of joinings) { - publishMessagingIndexStream(joining.userId, 'message', messageObj); - publishMainStream(joining.userId, 'messagingMessage', messageObj); + publishMessagingIndexStream(joining.userId, "message", messageObj); + publishMainStream(joining.userId, "messagingMessage", messageObj); } } @@ -69,38 +98,49 @@ export async function createMessage(user: { id: User['id']; host: User['host']; const mute = await Mutings.findBy({ muterId: recipientUser.id, }); - if (mute.map(m => m.muteeId).includes(user.id)) return; + if (mute.map((m) => m.muteeId).includes(user.id)) return; //#endregion - publishMainStream(recipientUser.id, 'unreadMessagingMessage', messageObj); - pushNotification(recipientUser.id, 'unreadMessagingMessage', messageObj); + publishMainStream(recipientUser.id, "unreadMessagingMessage", messageObj); + pushNotification(recipientUser.id, "unreadMessagingMessage", messageObj); } else if (recipientGroup) { - const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id, userId: Not(user.id) }); + const joinings = await UserGroupJoinings.findBy({ + userGroupId: recipientGroup.id, + userId: Not(user.id), + }); for (const joining of joinings) { if (freshMessage.reads.includes(joining.userId)) return; // 既読 - publishMainStream(joining.userId, 'unreadMessagingMessage', messageObj); - pushNotification(joining.userId, 'unreadMessagingMessage', messageObj); + publishMainStream(joining.userId, "unreadMessagingMessage", messageObj); + pushNotification(joining.userId, "unreadMessagingMessage", messageObj); } } }, 2000); - if (recipientUser && Users.isLocalUser(user) && Users.isRemoteUser(recipientUser)) { + if ( + recipientUser && + Users.isLocalUser(user) && + Users.isRemoteUser(recipientUser) + ) { const note = { id: message.id, createdAt: message.createdAt, - fileIds: message.fileId ? [ message.fileId ] : [], + fileIds: message.fileId ? [message.fileId] : [], text: message.text, userId: message.userId, - visibility: 'specified', - mentions: [ recipientUser ].map(u => u.id), - mentionedRemoteUsers: JSON.stringify([ recipientUser ].map(u => ({ - uri: u.uri, - username: u.username, - host: u.host, - }))), + visibility: "specified", + mentions: [recipientUser].map((u) => u.id), + mentionedRemoteUsers: JSON.stringify( + [recipientUser].map((u) => ({ + uri: u.uri, + username: u.username, + host: u.host, + })), + ), } as Note; - const activity = renderActivity(renderCreate(await renderNote(note, false, true), note)); + const activity = renderActivity( + renderCreate(await renderNote(note, false, true), note), + ); deliver(user, activity, recipientUser.inbox); } diff --git a/packages/backend/src/services/messages/delete.ts b/packages/backend/src/services/messages/delete.ts index 1e7ce1981..77caba80c 100644 --- a/packages/backend/src/services/messages/delete.ts +++ b/packages/backend/src/services/messages/delete.ts @@ -1,11 +1,14 @@ -import config from '@/config/index.js'; -import { MessagingMessages, Users } from '@/models/index.js'; -import { MessagingMessage } from '@/models/entities/messaging-message.js'; -import { publishGroupMessagingStream, publishMessagingStream } from '@/services/stream.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderDelete from '@/remote/activitypub/renderer/delete.js'; -import renderTombstone from '@/remote/activitypub/renderer/tombstone.js'; -import { deliver } from '@/queue/index.js'; +import config from "@/config/index.js"; +import { MessagingMessages, Users } from "@/models/index.js"; +import type { MessagingMessage } from "@/models/entities/messaging-message.js"; +import { + publishGroupMessagingStream, + publishMessagingStream, +} from "@/services/stream.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderDelete from "@/remote/activitypub/renderer/delete.js"; +import renderTombstone from "@/remote/activitypub/renderer/tombstone.js"; +import { deliver } from "@/queue/index.js"; export async function deleteMessage(message: MessagingMessage) { await MessagingMessages.delete(message.id); @@ -17,14 +20,31 @@ async function postDeleteMessage(message: MessagingMessage) { const user = await Users.findOneByOrFail({ id: message.userId }); const recipient = await Users.findOneByOrFail({ id: message.recipientId }); - if (Users.isLocalUser(user)) publishMessagingStream(message.userId, message.recipientId, 'deleted', message.id); - if (Users.isLocalUser(recipient)) publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id); + if (Users.isLocalUser(user)) + publishMessagingStream( + message.userId, + message.recipientId, + "deleted", + message.id, + ); + if (Users.isLocalUser(recipient)) + publishMessagingStream( + message.recipientId, + message.userId, + "deleted", + message.id, + ); if (Users.isLocalUser(user) && Users.isRemoteUser(recipient)) { - const activity = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${message.id}`), user)); + const activity = renderActivity( + renderDelete( + renderTombstone(`${config.url}/notes/${message.id}`), + user, + ), + ); deliver(user, activity, recipient.inbox); } } else if (message.groupId) { - publishGroupMessagingStream(message.groupId, 'deleted', message.id); + publishGroupMessagingStream(message.groupId, "deleted", message.id); } } diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index fa8ba6bf1..210ea7771 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -1,73 +1,96 @@ -import * as mfm from 'mfm-js'; -import es from '../../db/elasticsearch.js'; -import { publishMainStream, publishNotesStream } from '@/services/stream.js'; -import DeliverManager from '@/remote/activitypub/deliver-manager.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import renderCreate from '@/remote/activitypub/renderer/create.js'; -import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { resolveUser } from '@/remote/resolve-user.js'; -import config from '@/config/index.js'; -import { updateHashtags } from '../update-hashtag.js'; -import { concat } from '@/prelude/array.js'; -import { insertNoteUnread } from '@/services/note/unread.js'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; -import { extractMentions } from '@/misc/extract-mentions.js'; -import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; -import { extractHashtags } from '@/misc/extract-hashtags.js'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; -import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings, Blockings, NoteThreadMutings } from '@/models/index.js'; -import { DriveFile } from '@/models/entities/drive-file.js'; -import { App } from '@/models/entities/app.js'; -import { Not, In } from 'typeorm'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { genId } from '@/misc/gen-id.js'; -import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '@/services/chart/index.js'; -import { Poll, IPoll } from '@/models/entities/poll.js'; -import { createNotification } from '../create-notification.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; -import { checkHitAntenna } from '@/misc/check-hit-antenna.js'; -import { checkWordMute } from '@/misc/check-word-mute.js'; -import { addNoteToAntenna } from '../add-note-to-antenna.js'; -import { countSameRenotes } from '@/misc/count-same-renotes.js'; -import { deliverToRelays } from '../relay.js'; -import { Channel } from '@/models/entities/channel.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { getAntennas } from '@/misc/antenna-cache.js'; -import { endedPollNotificationQueue } from '@/queue/queues.js'; -import { webhookDeliver } from '@/queue/index.js'; -import { Cache } from '@/misc/cache.js'; -import { UserProfile } from '@/models/entities/user-profile.js'; -import { db } from '@/db/postgre.js'; -import { getActiveWebhooks } from '@/misc/webhook-cache.js'; +import * as mfm from "mfm-js"; +import es from "../../db/elasticsearch.js"; +import { publishMainStream, publishNotesStream } from "@/services/stream.js"; +import DeliverManager from "@/remote/activitypub/deliver-manager.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import renderCreate from "@/remote/activitypub/renderer/create.js"; +import renderAnnounce from "@/remote/activitypub/renderer/announce.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { resolveUser } from "@/remote/resolve-user.js"; +import config from "@/config/index.js"; +import { updateHashtags } from "../update-hashtag.js"; +import { concat } from "@/prelude/array.js"; +import { insertNoteUnread } from "@/services/note/unread.js"; +import { registerOrFetchInstanceDoc } from "../register-or-fetch-instance-doc.js"; +import { extractMentions } from "@/misc/extract-mentions.js"; +import { extractCustomEmojisFromMfm } from "@/misc/extract-custom-emojis-from-mfm.js"; +import { extractHashtags } from "@/misc/extract-hashtags.js"; +import type { IMentionedRemoteUsers } from "@/models/entities/note.js"; +import { Note } from "@/models/entities/note.js"; +import { + Mutings, + Users, + NoteWatchings, + Notes, + Instances, + UserProfiles, + Antennas, + Followings, + MutedNotes, + Channels, + ChannelFollowings, + Blockings, + NoteThreadMutings, +} from "@/models/index.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; +import type { App } from "@/models/entities/app.js"; +import { Not, In } from "typeorm"; +import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; +import { genId } from "@/misc/gen-id.js"; +import { + notesChart, + perUserNotesChart, + activeUsersChart, + instanceChart, +} from "@/services/chart/index.js"; +import type { IPoll } from "@/models/entities/poll.js"; +import { Poll } from "@/models/entities/poll.js"; +import { createNotification } from "../create-notification.js"; +import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; +import { checkHitAntenna } from "@/misc/check-hit-antenna.js"; +import { checkWordMute } from "@/misc/check-word-mute.js"; +import { addNoteToAntenna } from "../add-note-to-antenna.js"; +import { countSameRenotes } from "@/misc/count-same-renotes.js"; +import { deliverToRelays } from "../relay.js"; +import type { Channel } from "@/models/entities/channel.js"; +import { normalizeForSearch } from "@/misc/normalize-for-search.js"; +import { getAntennas } from "@/misc/antenna-cache.js"; +import { endedPollNotificationQueue } from "@/queue/queues.js"; +import { webhookDeliver } from "@/queue/index.js"; +import { Cache } from "@/misc/cache.js"; +import type { UserProfile } from "@/models/entities/user-profile.js"; +import { db } from "@/db/postgre.js"; +import { getActiveWebhooks } from "@/misc/webhook-cache.js"; -const mutedWordsCache = new Cache<{ userId: UserProfile['userId']; mutedWords: UserProfile['mutedWords']; }[]>(1000 * 60 * 5); +const mutedWordsCache = new Cache< + { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] +>(1000 * 60 * 5); -type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; +type NotificationType = "reply" | "renote" | "quote" | "mention"; class NotificationManager { - private notifier: { id: User['id']; }; + private notifier: { id: User["id"] }; private note: Note; private queue: { - target: ILocalUser['id']; + target: ILocalUser["id"]; reason: NotificationType; }[]; - constructor(notifier: { id: User['id']; }, note: Note) { + constructor(notifier: { id: User["id"] }, note: Note) { this.notifier = notifier; this.note = note; this.queue = []; } - public push(notifiee: ILocalUser['id'], reason: NotificationType) { + public push(notifiee: ILocalUser["id"], reason: NotificationType) { // 自分自身へは通知しない if (this.notifier.id === notifiee) return; - const exist = this.queue.find(x => x.target === notifiee); + const exist = this.queue.find((x) => x.target === notifiee); if (exist) { // 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする - if (reason !== 'mention') { + if (reason !== "mention") { exist.reason = reason; } } else { @@ -85,13 +108,14 @@ class NotificationManager { muterId: x.target, }); - const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId); + const mentioneesMutedUserIds = mentioneeMutes.map((m) => m.muteeId); // 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する if (!mentioneesMutedUserIds.includes(this.notifier.id)) { createNotification(x.target, x.reason, { notifierId: this.notifier.id, noteId: this.note.id, + note: this.note, }); } } @@ -99,10 +123,10 @@ class NotificationManager { } type MinimumUser = { - id: User['id']; - host: User['host']; - username: User['username']; - uri: User['uri']; + id: User["id"]; + host: User["host"]; + username: User["username"]; + uri: User["uri"]; }; type Option = { @@ -126,383 +150,478 @@ type Option = { app?: App | null; }; -export default async (user: { id: User['id']; username: User['username']; host: User['host']; isSilenced: User['isSilenced']; createdAt: User['createdAt']; }, data: Option, silent = false) => new Promise(async (res, rej) => { - // If you reply outside the channel, match the scope of the target. - // TODO (I think it's a process that could be done on the client side, but it's server side for now.) - if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { - if (data.reply.channelId) { - data.channel = await Channels.findOneBy({ id: data.reply.channelId }); - } else { - data.channel = null; - } - } - - // When you reply in a channel, match the scope of the target - // TODO (I think it's a process that could be done on the client side, but it's server side for now.) - if (data.reply && (data.channel == null) && data.reply.channelId) { - data.channel = await Channels.findOneBy({ id: data.reply.channelId }); - } - - if (data.createdAt == null) data.createdAt = new Date(); - if (data.visibility == null) data.visibility = 'public'; - if (data.localOnly == null) data.localOnly = false; - if (data.channel != null) data.visibility = 'public'; - if (data.channel != null) data.visibleUsers = []; - if (data.channel != null) data.localOnly = true; - - // enforce silent clients on server - if (user.isSilenced && data.visibility === 'public' && data.channel == null) { - data.visibility = 'home'; - } - - // Reject if the target of the renote is a public range other than "Home or Entire". - if (data.renote && data.renote.visibility !== 'public' && data.renote.visibility !== 'home' && data.renote.userId !== user.id) { - return rej('Renote target is not public or home'); - } - - // If the target of the renote is not public, make it home. - if (data.renote && data.renote.visibility !== 'public' && data.visibility === 'public') { - data.visibility = 'home'; - } - - // If the target of Renote is followers, make it followers. - if (data.renote && data.renote.visibility === 'followers') { - data.visibility = 'followers'; - } - - // If the reply target is not public, make it home. - if (data.reply && data.reply.visibility !== 'public' && data.visibility === 'public') { - data.visibility = 'home'; - } - - // Renote local only if you Renote local only. - if (data.renote && data.renote.localOnly && data.channel == null) { - data.localOnly = true; - } - - // If you reply to local only, make it local only. - if (data.reply && data.reply.localOnly && data.channel == null) { - data.localOnly = true; - } - - if (data.text) { - data.text = data.text.trim(); - } else { - data.text = null; - } - - let tags = data.apHashtags; - let emojis = data.apEmojis; - let mentionedUsers = data.apMentions; - - // Parse MFM if needed - if (!tags || !emojis || !mentionedUsers) { - const tokens = data.text ? mfm.parse(data.text)! : []; - const cwTokens = data.cw ? mfm.parse(data.cw)! : []; - const choiceTokens = data.poll && data.poll.choices - ? concat(data.poll.choices.map(choice => mfm.parse(choice)!)) - : []; - - const combinedTokens = tokens.concat(cwTokens).concat(choiceTokens); - - tags = data.apHashtags || extractHashtags(combinedTokens); - - emojis = data.apEmojis || extractCustomEmojisFromMfm(combinedTokens); - - mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens); - } - - tags = tags.filter(tag => Array.from(tag || '').length <= 128).splice(0, 32); - - if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) { - mentionedUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId })); - } - - if (data.visibility === 'specified') { - if (data.visibleUsers == null) throw new Error('invalid param'); - - for (const u of data.visibleUsers) { - if (!mentionedUsers.some(x => x.id === u.id)) { - mentionedUsers.push(u); +export default async ( + user: { + id: User["id"]; + username: User["username"]; + host: User["host"]; + isSilenced: User["isSilenced"]; + createdAt: User["createdAt"]; + }, + data: Option, + silent = false, +) => + new Promise(async (res, rej) => { + // If you reply outside the channel, match the scope of the target. + // TODO (I think it's a process that could be done on the client side, but it's server side for now.) + if ( + data.reply && + data.channel && + data.reply.channelId !== data.channel.id + ) { + if (data.reply.channelId) { + data.channel = await Channels.findOneBy({ id: data.reply.channelId }); + } else { + data.channel = null; } } - if (data.reply && !data.visibleUsers.some(x => x.id === data.reply!.userId)) { - data.visibleUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId })); + // When you reply in a channel, match the scope of the target + // TODO (I think it's a process that could be done on the client side, but it's server side for now.) + if (data.reply && data.channel == null && data.reply.channelId) { + data.channel = await Channels.findOneBy({ id: data.reply.channelId }); } - } - const note = await insertNote(user, data, tags, emojis, mentionedUsers); + if (data.createdAt == null) data.createdAt = new Date(); + if (data.visibility == null) data.visibility = "public"; + if (data.localOnly == null) data.localOnly = false; + if (data.channel != null) data.visibility = "public"; + if (data.channel != null) data.visibleUsers = []; + if (data.channel != null) data.localOnly = true; - res(note); + // enforce silent clients on server + if ( + user.isSilenced && + data.visibility === "public" && + data.channel == null + ) { + data.visibility = "home"; + } - // 統計を更新 - notesChart.update(note, true); - perUserNotesChart.update(user, note, true); + // Reject if the target of the renote is a public range other than "Home or Entire". + if ( + data.renote && + data.renote.visibility !== "public" && + data.renote.visibility !== "home" && + data.renote.userId !== user.id + ) { + return rej("Renote target is not public or home"); + } - // Register host - if (Users.isRemoteUser(user)) { - registerOrFetchInstanceDoc(user.host).then(i => { - Instances.increment({ id: i.id }, 'notesCount', 1); - instanceChart.updateNote(i.host, note, true); - }); - } + // If the target of the renote is not public, make it home. + if ( + data.renote && + data.renote.visibility !== "public" && + data.visibility === "public" + ) { + data.visibility = "home"; + } - // ハッシュタグ更新 - if (data.visibility === 'public' || data.visibility === 'home') { - updateHashtags(user, tags); - } + // If the target of Renote is followers, make it followers. + if (data.renote && data.renote.visibility === "followers") { + data.visibility = "followers"; + } - // Increment notes count (user) - incNotesCountOfUser(user); + // If the reply target is not public, make it home. + if ( + data.reply && + data.reply.visibility !== "public" && + data.visibility === "public" + ) { + data.visibility = "home"; + } - // Word mute - mutedWordsCache.fetch(null, () => UserProfiles.find({ - where: { - enableWordMute: true, - }, - select: ['userId', 'mutedWords'], - })).then(us => { - for (const u of us) { - checkWordMute(note, { id: u.userId }, u.mutedWords).then(shouldMute => { - if (shouldMute) { - MutedNotes.insert({ - id: genId(), - userId: u.userId, - noteId: note.id, - reason: 'word', - }); + // Renote local only if you Renote local only. + if (data.renote?.localOnly && data.channel == null) { + data.localOnly = true; + } + + // If you reply to local only, make it local only. + if (data.reply?.localOnly && data.channel == null) { + data.localOnly = true; + } + + if (data.text) { + data.text = data.text.trim(); + } else { + data.text = null; + } + + let tags = data.apHashtags; + let emojis = data.apEmojis; + let mentionedUsers = data.apMentions; + + // Parse MFM if needed + if (!(tags && emojis && mentionedUsers)) { + const tokens = data.text ? mfm.parse(data.text)! : []; + const cwTokens = data.cw ? mfm.parse(data.cw)! : []; + const choiceTokens = data.poll?.choices + ? concat(data.poll.choices.map((choice) => mfm.parse(choice)!)) + : []; + + const combinedTokens = tokens.concat(cwTokens).concat(choiceTokens); + + tags = data.apHashtags || extractHashtags(combinedTokens); + + emojis = data.apEmojis || extractCustomEmojisFromMfm(combinedTokens); + + mentionedUsers = + data.apMentions || (await extractMentionedUsers(user, combinedTokens)); + } + + tags = tags + .filter((tag) => Array.from(tag || "").length <= 128) + .splice(0, 32); + + if ( + data.reply && + user.id !== data.reply.userId && + !mentionedUsers.some((u) => u.id === data.reply!.userId) + ) { + mentionedUsers.push( + await Users.findOneByOrFail({ id: data.reply!.userId }), + ); + } + + if (data.visibility === "specified") { + if (data.visibleUsers == null) throw new Error("invalid param"); + + for (const u of data.visibleUsers) { + if (!mentionedUsers.some((x) => x.id === u.id)) { + mentionedUsers.push(u); + } + } + + if ( + data.reply && + !data.visibleUsers.some((x) => x.id === data.reply!.userId) + ) { + data.visibleUsers.push( + await Users.findOneByOrFail({ id: data.reply!.userId }), + ); + } + } + + const note = await insertNote(user, data, tags, emojis, mentionedUsers); + + res(note); + + // 統計を更新 + notesChart.update(note, true); + perUserNotesChart.update(user, note, true); + + // Register host + if (Users.isRemoteUser(user)) { + registerOrFetchInstanceDoc(user.host).then((i) => { + Instances.increment({ id: i.id }, "notesCount", 1); + instanceChart.updateNote(i.host, note, true); + }); + } + + // ハッシュタグ更新 + if (data.visibility === "public" || data.visibility === "home") { + updateHashtags(user, tags); + } + + // Increment notes count (user) + incNotesCountOfUser(user); + + // Word mute + mutedWordsCache + .fetch(null, () => + UserProfiles.find({ + where: { + enableWordMute: true, + }, + select: ["userId", "mutedWords"], + }), + ) + .then((us) => { + for (const u of us) { + checkWordMute(note, { id: u.userId }, u.mutedWords).then( + (shouldMute) => { + if (shouldMute) { + MutedNotes.insert({ + id: genId(), + userId: u.userId, + noteId: note.id, + reason: "word", + }); + } + }, + ); + } + }); + + // Antenna + for (const antenna of await getAntennas()) { + checkHitAntenna(antenna, note, user).then((hit) => { + if (hit) { + addNoteToAntenna(antenna, note, user); } }); } - }); - // Antenna - for (const antenna of (await getAntennas())) { - checkHitAntenna(antenna, note, user).then(hit => { - if (hit) { - addNoteToAntenna(antenna, note, user); - } - }); - } - - // Channel - if (note.channelId) { - ChannelFollowings.findBy({ followeeId: note.channelId }).then(followings => { - for (const following of followings) { - insertNoteUnread(following.followerId, note, { - isSpecified: false, - isMentioned: false, - }); - } - }); - } - - if (data.reply) { - saveReply(data.reply, note); - } - - // この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき - if (data.renote && (await countSameRenotes(user.id, data.renote.id, note.id) === 0)) { - incRenoteCount(data.renote); - } - - if (data.poll && data.poll.expiresAt) { - const delay = data.poll.expiresAt.getTime() - Date.now(); - endedPollNotificationQueue.add({ - noteId: note.id, - }, { - delay, - removeOnComplete: true, - }); - } - - if (!silent) { - if (Users.isLocalUser(user)) activeUsersChart.write(user); - - // 未読通知を作成 - if (data.visibility === 'specified') { - if (data.visibleUsers == null) throw new Error('invalid param'); - - for (const u of data.visibleUsers) { - // ローカルユーザーのみ - if (!Users.isLocalUser(u)) continue; - - insertNoteUnread(u.id, note, { - isSpecified: true, - isMentioned: false, - }); - } - } else { - for (const u of mentionedUsers) { - // ローカルユーザーのみ - if (!Users.isLocalUser(u)) continue; - - insertNoteUnread(u.id, note, { - isSpecified: false, - isMentioned: true, - }); - } + // Channel + if (note.channelId) { + ChannelFollowings.findBy({ followeeId: note.channelId }).then( + (followings) => { + for (const following of followings) { + insertNoteUnread(following.followerId, note, { + isSpecified: false, + isMentioned: false, + }); + } + }, + ); } - publishNotesStream(note); - - const webhooks = await getActiveWebhooks().then(webhooks => webhooks.filter(x => x.userId === user.id && x.on.includes('note'))); - - for (const webhook of webhooks) { - webhookDeliver(webhook, 'note', { - note: await Notes.pack(note, user), - }); - } - - const nm = new NotificationManager(user, note); - const nmRelatedPromises = []; - - await createMentionedEvents(mentionedUsers, note, nm); - - // If has in reply to note if (data.reply) { - // Fetch watchers - nmRelatedPromises.push(notifyToWatchersOfReplyee(data.reply, user, nm)); + saveReply(data.reply, note); + } - // 通知 - if (data.reply.userHost === null) { - const threadMuted = await NoteThreadMutings.findOneBy({ - userId: data.reply.userId, - threadId: data.reply.threadId || data.reply.id, + // この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき + if ( + data.renote && + (await countSameRenotes(user.id, data.renote.id, note.id)) === 0 + ) { + incRenoteCount(data.renote); + } + + if (data.poll?.expiresAt) { + const delay = data.poll.expiresAt.getTime() - Date.now(); + endedPollNotificationQueue.add( + { + noteId: note.id, + }, + { + delay, + removeOnComplete: true, + }, + ); + } + + if (!silent) { + if (Users.isLocalUser(user)) activeUsersChart.write(user); + + // 未読通知を作成 + if (data.visibility === "specified") { + if (data.visibleUsers == null) throw new Error("invalid param"); + + for (const u of data.visibleUsers) { + // ローカルユーザーのみ + if (!Users.isLocalUser(u)) continue; + + insertNoteUnread(u.id, note, { + isSpecified: true, + isMentioned: false, + }); + } + } else { + for (const u of mentionedUsers) { + // ローカルユーザーのみ + if (!Users.isLocalUser(u)) continue; + + insertNoteUnread(u.id, note, { + isSpecified: false, + isMentioned: true, + }); + } + } + + publishNotesStream(note); + + const webhooks = await getActiveWebhooks().then((webhooks) => + webhooks.filter((x) => x.userId === user.id && x.on.includes("note")), + ); + + for (const webhook of webhooks) { + webhookDeliver(webhook, "note", { + note: await Notes.pack(note, user), }); + } - if (!threadMuted) { - nm.push(data.reply.userId, 'reply'); + const nm = new NotificationManager(user, note); + const nmRelatedPromises = []; - const packedReply = await Notes.pack(note, { id: data.reply.userId }); - publishMainStream(data.reply.userId, 'reply', packedReply); + await createMentionedEvents(mentionedUsers, note, nm); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply')); + // If has in reply to note + if (data.reply) { + // Fetch watchers + nmRelatedPromises.push(notifyToWatchersOfReplyee(data.reply, user, nm)); + + // 通知 + if (data.reply.userHost === null) { + const threadMuted = await NoteThreadMutings.findOneBy({ + userId: data.reply.userId, + threadId: data.reply.threadId || data.reply.id, + }); + + if (!threadMuted) { + nm.push(data.reply.userId, "reply"); + + const packedReply = await Notes.pack(note, { + id: data.reply.userId, + }); + publishMainStream(data.reply.userId, "reply", packedReply); + + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === data.reply!.userId && x.on.includes("reply"), + ); + for (const webhook of webhooks) { + webhookDeliver(webhook, "reply", { + note: packedReply, + }); + } + } + } + } + + // If it is renote + if (data.renote) { + const type = data.text ? "quote" : "renote"; + + // Notify + if (data.renote.userHost === null) { + const threadMuted = await NoteThreadMutings.findOneBy({ + userId: data.renote.userId, + threadId: data.renote.threadId || data.renote.id, + }); + + if (!threadMuted) { + nm.push(data.renote.userId, type); + } + } + + // Fetch watchers + nmRelatedPromises.push( + notifyToWatchersOfRenotee(data.renote, user, nm, type), + ); + + // Publish event + if (user.id !== data.renote.userId && data.renote.userHost === null) { + const packedRenote = await Notes.pack(note, { + id: data.renote.userId, + }); + publishMainStream(data.renote.userId, "renote", packedRenote); + + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === data.renote!.userId && x.on.includes("renote"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'reply', { - note: packedReply, + webhookDeliver(webhook, "renote", { + note: packedRenote, }); } } } + + Promise.all(nmRelatedPromises).then(() => { + nm.deliver(); + }); + + //#region AP deliver + if (Users.isLocalUser(user)) { + (async () => { + const noteActivity = await renderNoteOrRenoteActivity(data, note); + const dm = new DeliverManager(user, noteActivity); + + // メンションされたリモートユーザーに配送 + for (const u of mentionedUsers.filter((u) => Users.isRemoteUser(u))) { + dm.addDirectRecipe(u as IRemoteUser); + } + + // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 + if (data.reply && data.reply.userHost !== null) { + const u = await Users.findOneBy({ id: data.reply.userId }); + if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); + } + + // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送 + if (data.renote && data.renote.userHost !== null) { + const u = await Users.findOneBy({ id: data.renote.userId }); + if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); + } + + // フォロワーに配送 + if (["public", "home", "followers"].includes(note.visibility)) { + dm.addFollowersRecipe(); + } + + if (["public"].includes(note.visibility)) { + deliverToRelays(user, noteActivity); + } + + dm.execute(); + })(); + } + //#endregion } - // If it is renote - if (data.renote) { - const type = data.text ? 'quote' : 'renote'; + if (data.channel) { + Channels.increment({ id: data.channel.id }, "notesCount", 1); + Channels.update(data.channel.id, { + lastNotedAt: new Date(), + }); - // Notify - if (data.renote.userHost === null) { - nm.push(data.renote.userId, type); - } - - // Fetch watchers - nmRelatedPromises.push(notifyToWatchersOfRenotee(data.renote, user, nm, type)); - - // Publish event - if ((user.id !== data.renote.userId) && data.renote.userHost === null) { - const packedRenote = await Notes.pack(note, { id: data.renote.userId }); - publishMainStream(data.renote.userId, 'renote', packedRenote); - - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote')); - for (const webhook of webhooks) { - webhookDeliver(webhook, 'renote', { - note: packedRenote, - }); + const count = await Notes.countBy({ + userId: user.id, + channelId: data.channel.id, + }).then((count) => { + // この処理が行われるのはノート作成後なので、ノートが一つしかなかったら最初の投稿だと判断できる + // TODO: とはいえノートを削除して何回も投稿すればその分だけインクリメントされる雑さもあるのでどうにかしたい + if (count === 1) { + Channels.increment({ id: data.channel!.id }, "usersCount", 1); } - } + }); } - Promise.all(nmRelatedPromises).then(() => { - nm.deliver(); - }); - - //#region AP deliver - if (Users.isLocalUser(user)) { - (async () => { - const noteActivity = await renderNoteOrRenoteActivity(data, note); - const dm = new DeliverManager(user, noteActivity); - - // メンションされたリモートユーザーに配送 - for (const u of mentionedUsers.filter(u => Users.isRemoteUser(u))) { - dm.addDirectRecipe(u as IRemoteUser); - } - - // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 - if (data.reply && data.reply.userHost !== null) { - const u = await Users.findOneBy({ id: data.reply.userId }); - if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); - } - - // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送 - if (data.renote && data.renote.userHost !== null) { - const u = await Users.findOneBy({ id: data.renote.userId }); - if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); - } - - // フォロワーに配送 - if (['public', 'home', 'followers'].includes(note.visibility)) { - dm.addFollowersRecipe(); - } - - if (['public'].includes(note.visibility)) { - deliverToRelays(user, noteActivity); - } - - dm.execute(); - })(); - } - //#endregion - } - - if (data.channel) { - Channels.increment({ id: data.channel.id }, 'notesCount', 1); - Channels.update(data.channel.id, { - lastNotedAt: new Date(), - }); - - const count = await Notes.countBy({ - userId: user.id, - channelId: data.channel.id, - }).then(count => { - // この処理が行われるのはノート作成後なので、ノートが一つしかなかったら最初の投稿だと判断できる - // TODO: とはいえノートを削除して何回も投稿すればその分だけインクリメントされる雑さもあるのでどうにかしたい - if (count === 1) { - Channels.increment({ id: data.channel!.id }, 'usersCount', 1); - } - }); - } - - // Register to search database - index(note); -}); + // Register to search database + index(note); + }); async function renderNoteOrRenoteActivity(data: Option, note: Note) { if (data.localOnly) return null; - const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0) - ? renderAnnounce(data.renote.uri ? data.renote.uri : `${config.url}/notes/${data.renote.id}`, note) - : renderCreate(await renderNote(note, false), note); + const content = + data.renote && + data.text == null && + data.poll == null && + (data.files == null || data.files.length === 0) + ? renderAnnounce( + data.renote.uri + ? data.renote.uri + : `${config.url}/notes/${data.renote.id}`, + note, + ) + : renderCreate(await renderNote(note, false), note); return renderActivity(content); } function incRenoteCount(renote: Note) { - Notes.createQueryBuilder().update() + Notes.createQueryBuilder() + .update() .set({ renoteCount: () => '"renoteCount" + 1', score: () => '"score" + 1', }) - .where('id = :id', { id: renote.id }) + .where("id = :id", { id: renote.id }) .execute(); } -async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) { +async function insertNote( + user: { id: User["id"]; host: User["host"] }, + data: Option, + tags: string[], + emojis: string[], + mentionedUsers: MinimumUser[], +) { const insert = new Note({ id: genId(data.createdAt!), createdAt: data.createdAt!, - fileIds: data.files ? data.files.map(file => file.id) : [], + fileIds: data.files ? data.files.map((file) => file.id) : [], replyId: data.reply ? data.reply.id : null, renoteId: data.renote ? data.renote.id : null, channelId: data.channel ? data.channel.id : null, @@ -515,18 +634,19 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O text: data.text, hasPoll: data.poll != null, cw: data.cw == null ? null : data.cw, - tags: tags.map(tag => normalizeForSearch(tag)), + tags: tags.map((tag) => normalizeForSearch(tag)), emojis, userId: user.id, localOnly: data.localOnly!, visibility: data.visibility as any, - visibleUserIds: data.visibility === 'specified' - ? data.visibleUsers - ? data.visibleUsers.map(u => u.id) - : [] - : [], + visibleUserIds: + data.visibility === "specified" + ? data.visibleUsers + ? data.visibleUsers.map((u) => u.id) + : [] + : [], - attachedFileTypes: data.files ? data.files.map(file => file.type) : [], + attachedFileTypes: data.files ? data.files.map((file) => file.type) : [], // 以下非正規化データ replyUserId: data.reply ? data.reply.userId : null, @@ -541,25 +661,29 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O // Append mentions data if (mentionedUsers.length > 0) { - insert.mentions = mentionedUsers.map(u => u.id); + insert.mentions = mentionedUsers.map((u) => u.id); const profiles = await UserProfiles.findBy({ userId: In(insert.mentions) }); - insert.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => Users.isRemoteUser(u)).map(u => { - const profile = profiles.find(p => p.userId === u.id); - const url = profile != null ? profile.url : null; - return { - uri: u.uri, - url: url == null ? undefined : url, - username: u.username, - host: u.host, - } as IMentionedRemoteUsers[0]; - })); + insert.mentionedRemoteUsers = JSON.stringify( + mentionedUsers + .filter((u) => Users.isRemoteUser(u)) + .map((u) => { + const profile = profiles.find((p) => p.userId === u.id); + const url = profile != null ? profile.url : null; + return { + uri: u.uri, + url: url == null ? undefined : url, + username: u.username, + host: u.host, + } as IMentionedRemoteUsers[0]; + }), + ); } // 投稿を作成 try { if (insert.hasPoll) { // Start transaction - await db.transaction(async transactionalEntityManager => { + await db.transaction(async (transactionalEntityManager) => { await transactionalEntityManager.insert(Note, insert); const poll = new Poll({ @@ -583,8 +707,8 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O } catch (e) { // duplicate key error if (isDuplicateKeyValueError(e)) { - const err = new Error('Duplicated note'); - err.name = 'duplicated'; + const err = new Error("Duplicated note"); + err.name = "duplicated"; throw err; } @@ -598,7 +722,7 @@ function index(note: Note) { if (note.text == null || config.elasticsearch == null) return; es!.index({ - index: config.elasticsearch.index || 'misskey_note', + index: config.elasticsearch.index || "misskey_note", id: note.id.toString(), body: { text: normalizeForSearch(note.text), @@ -608,7 +732,12 @@ function index(note: Note) { }); } -async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType) { +async function notifyToWatchersOfRenotee( + renote: Note, + user: { id: User["id"] }, + nm: NotificationManager, + type: NotificationType, +) { const watchers = await NoteWatchings.findBy({ noteId: renote.id, userId: Not(user.id), @@ -619,19 +748,27 @@ async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; } } } -async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager) { +async function notifyToWatchersOfReplyee( + reply: Note, + user: { id: User["id"] }, + nm: NotificationManager, +) { const watchers = await NoteWatchings.findBy({ noteId: reply.id, userId: Not(user.id), }); for (const watcher of watchers) { - nm.push(watcher.userId, 'reply'); + nm.push(watcher.userId, "reply"); } } -async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) { - for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) { +async function createMentionedEvents( + mentionedUsers: MinimumUser[], + note: Note, + nm: NotificationManager, +) { + for (const u of mentionedUsers.filter((u) => Users.isLocalUser(u))) { const threadMuted = await NoteThreadMutings.findOneBy({ userId: u.id, threadId: note.threadId || note.id, @@ -647,50 +784,60 @@ async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, detail: true, }); - publishMainStream(u.id, 'mention', detailPackedNote); + publishMainStream(u.id, "mention", detailPackedNote); - const webhooks = (await getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention')); + const webhooks = (await getActiveWebhooks()).filter( + (x) => x.userId === u.id && x.on.includes("mention"), + ); for (const webhook of webhooks) { - webhookDeliver(webhook, 'mention', { + webhookDeliver(webhook, "mention", { note: detailPackedNote, }); } } catch (err) { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') continue; + if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") continue; throw err; } // Create notification - nm.push(u.id, 'mention'); + nm.push(u.id, "mention"); } } function saveReply(reply: Note, note: Note) { - Notes.increment({ id: reply.id }, 'repliesCount', 1); + Notes.increment({ id: reply.id }, "repliesCount", 1); } -function incNotesCountOfUser(user: { id: User['id']; }) { - Users.createQueryBuilder().update() +function incNotesCountOfUser(user: { id: User["id"] }) { + Users.createQueryBuilder() + .update() .set({ updatedAt: new Date(), notesCount: () => '"notesCount" + 1', }) - .where('id = :id', { id: user.id }) + .where("id = :id", { id: user.id }) .execute(); } -async function extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise { +async function extractMentionedUsers( + user: { host: User["host"] }, + tokens: mfm.MfmNode[], +): Promise { if (tokens == null) return []; const mentions = extractMentions(tokens); - let mentionedUsers = (await Promise.all(mentions.map(m => - resolveUser(m.username, m.host || user.host).catch(() => null) - ))).filter(x => x != null) as User[]; + let mentionedUsers = ( + await Promise.all( + mentions.map((m) => + resolveUser(m.username, m.host || user.host).catch(() => null), + ), + ) + ).filter((x) => x != null) as User[]; // Drop duplicate users - mentionedUsers = mentionedUsers.filter((u, i, self) => - i === self.findIndex(u2 => u.id === u2.id) + mentionedUsers = mentionedUsers.filter( + (u, i, self) => i === self.findIndex((u2) => u.id === u2.id), ); return mentionedUsers; diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 496320016..392578e2f 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -1,40 +1,54 @@ -import { Brackets, In } from 'typeorm'; -import { publishNoteStream } from '@/services/stream.js'; -import renderDelete from '@/remote/activitypub/renderer/delete.js'; -import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderTombstone from '@/remote/activitypub/renderer/tombstone.js'; -import config from '@/config/index.js'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; -import { Notes, Users, Instances } from '@/models/index.js'; -import { notesChart, perUserNotesChart, instanceChart } from '@/services/chart/index.js'; -import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver-manager.js'; -import { countSameRenotes } from '@/misc/count-same-renotes.js'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; -import { deliverToRelays } from '../relay.js'; +import { Brackets, In } from "typeorm"; +import { publishNoteStream } from "@/services/stream.js"; +import renderDelete from "@/remote/activitypub/renderer/delete.js"; +import renderAnnounce from "@/remote/activitypub/renderer/announce.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderTombstone from "@/remote/activitypub/renderer/tombstone.js"; +import config from "@/config/index.js"; +import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; +import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js"; +import { Notes, Users, Instances } from "@/models/index.js"; +import { + notesChart, + perUserNotesChart, + instanceChart, +} from "@/services/chart/index.js"; +import { + deliverToFollowers, + deliverToUser, +} from "@/remote/activitypub/deliver-manager.js"; +import { countSameRenotes } from "@/misc/count-same-renotes.js"; +import { registerOrFetchInstanceDoc } from "../register-or-fetch-instance-doc.js"; +import { deliverToRelays } from "../relay.js"; /** * 投稿を削除します。 * @param user 投稿者 * @param note 投稿 */ -export default async function(user: { id: User['id']; uri: User['uri']; host: User['host']; }, note: Note, quiet = false) { +export default async function ( + user: { id: User["id"]; uri: User["uri"]; host: User["host"] }, + note: Note, + quiet = false, +) { const deletedAt = new Date(); // この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき - if (note.renoteId && (await countSameRenotes(user.id, note.renoteId, note.id)) === 0) { - Notes.decrement({ id: note.renoteId }, 'renoteCount', 1); - Notes.decrement({ id: note.renoteId }, 'score', 1); + if ( + note.renoteId && + (await countSameRenotes(user.id, note.renoteId, note.id)) === 0 + ) { + Notes.decrement({ id: note.renoteId }, "renoteCount", 1); + Notes.decrement({ id: note.renoteId }, "score", 1); } if (note.replyId) { - await Notes.decrement({ id: note.replyId }, 'repliesCount', 1); + await Notes.decrement({ id: note.replyId }, "repliesCount", 1); } if (!quiet) { - publishNoteStream(note.id, 'deleted', { + publishNoteStream(note.id, "deleted", { deletedAt: deletedAt, }); @@ -43,25 +57,48 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us let renote: Note | null = null; // if deletd note is renote - if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { + if ( + note.renoteId && + note.text == null && + !note.hasPoll && + (note.fileIds == null || note.fileIds.length === 0) + ) { renote = await Notes.findOneBy({ id: note.renoteId, }); } - const content = renderActivity(renote - ? renderUndo(renderAnnounce(renote.uri || `${config.url}/notes/${renote.id}`, note), user) - : renderDelete(renderTombstone(`${config.url}/notes/${note.id}`), user)); + const content = renderActivity( + renote + ? renderUndo( + renderAnnounce( + renote.uri || `${config.url}/notes/${renote.id}`, + note, + ), + user, + ) + : renderDelete( + renderTombstone(`${config.url}/notes/${note.id}`), + user, + ), + ); deliverToConcerned(user, note, content); } // also deliever delete activity to cascaded notes - const cascadingNotes = (await findCascadingNotes(note)).filter(note => !note.localOnly); // filter out local-only notes + const cascadingNotes = (await findCascadingNotes(note)).filter( + (note) => !note.localOnly, + ); // filter out local-only notes for (const cascadingNote of cascadingNotes) { if (!cascadingNote.user) continue; if (!Users.isLocalUser(cascadingNote.user)) continue; - const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${cascadingNote.id}`), cascadingNote.user)); + const content = renderActivity( + renderDelete( + renderTombstone(`${config.url}/notes/${cascadingNote.id}`), + cascadingNote.user, + ), + ); deliverToConcerned(cascadingNote.user, cascadingNote, content); } //#endregion @@ -71,8 +108,8 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us perUserNotesChart.update(user, note, false); if (Users.isRemoteUser(user)) { - registerOrFetchInstanceDoc(user.host).then(i => { - Instances.decrement({ id: i.id }, 'notesCount', 1); + registerOrFetchInstanceDoc(user.host).then((i) => { + Instances.decrement({ id: i.id }, "notesCount", 1); instanceChart.updateNote(i.host, note, false); }); } @@ -88,13 +125,16 @@ async function findCascadingNotes(note: Note) { const cascadingNotes: Note[] = []; const recursive = async (noteId: string) => { - const query = Notes.createQueryBuilder('note') - .where('note.replyId = :noteId', { noteId }) - .orWhere(new Brackets(q => { - q.where('note.renoteId = :noteId', { noteId }) - .andWhere('note.text IS NOT NULL'); - })) - .leftJoinAndSelect('note.user', 'user'); + const query = Notes.createQueryBuilder("note") + .where("note.replyId = :noteId", { noteId }) + .orWhere( + new Brackets((q) => { + q.where("note.renoteId = :noteId", { noteId }).andWhere( + "note.text IS NOT NULL", + ); + }), + ) + .leftJoinAndSelect("note.user", "user"); const replies = await query.getMany(); for (const reply of replies) { cascadingNotes.push(reply); @@ -103,18 +143,18 @@ async function findCascadingNotes(note: Note) { }; await recursive(note.id); - return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users + return cascadingNotes.filter((note) => note.userHost === null); // filter out non-local users } async function getMentionedRemoteUsers(note: Note) { const where = [] as any[]; // mention / reply / dm - const uris = (JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers).map(x => x.uri); + const uris = ( + JSON.parse(note.mentionedRemoteUsers) as IMentionedRemoteUsers + ).map((x) => x.uri); if (uris.length > 0) { - where.push( - { uri: In(uris) }, - ); + where.push({ uri: In(uris) }); } // renote / quote @@ -126,12 +166,16 @@ async function getMentionedRemoteUsers(note: Note) { if (where.length === 0) return []; - return await Users.find({ + return (await Users.find({ where, - }) as IRemoteUser[]; + })) as IRemoteUser[]; } -async function deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) { +async function deliverToConcerned( + user: { id: ILocalUser["id"]; host: null }, + note: Note, + content: any, +) { deliverToFollowers(user, content); deliverToRelays(user, content); const remoteUsers = await getMentionedRemoteUsers(note); diff --git a/packages/backend/src/services/note/polls/update.ts b/packages/backend/src/services/note/polls/update.ts index 68cbb9835..e02d48d05 100644 --- a/packages/backend/src/services/note/polls/update.ts +++ b/packages/backend/src/services/note/polls/update.ts @@ -1,20 +1,22 @@ -import renderUpdate from '@/remote/activitypub/renderer/update.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import renderNote from '@/remote/activitypub/renderer/note.js'; -import { Users, Notes } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; -import { deliverToRelays } from '../../relay.js'; +import renderUpdate from "@/remote/activitypub/renderer/update.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import renderNote from "@/remote/activitypub/renderer/note.js"; +import { Users, Notes } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; +import { deliverToFollowers } from "@/remote/activitypub/deliver-manager.js"; +import { deliverToRelays } from "../../relay.js"; -export async function deliverQuestionUpdate(noteId: Note['id']) { +export async function deliverQuestionUpdate(noteId: Note["id"]) { const note = await Notes.findOneBy({ id: noteId }); - if (note == null) throw new Error('note not found'); + if (note == null) throw new Error("note not found"); const user = await Users.findOneBy({ id: note.userId }); - if (user == null) throw new Error('note not found'); + if (user == null) throw new Error("note not found"); if (Users.isLocalUser(user)) { - const content = renderActivity(renderUpdate(await renderNote(note, false), user)); + const content = renderActivity( + renderUpdate(await renderNote(note, false), user), + ); deliverToFollowers(user, content); deliverToRelays(user, content); } diff --git a/packages/backend/src/services/note/polls/vote.ts b/packages/backend/src/services/note/polls/vote.ts index 84d98769d..582af0b17 100644 --- a/packages/backend/src/services/note/polls/vote.ts +++ b/packages/backend/src/services/note/polls/vote.ts @@ -1,18 +1,23 @@ -import { publishNoteStream } from '@/services/stream.js'; -import { CacheableUser, User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { PollVotes, NoteWatchings, Polls, Blockings } from '@/models/index.js'; -import { Not } from 'typeorm'; -import { genId } from '@/misc/gen-id.js'; -import { createNotification } from '../../create-notification.js'; +import { publishNoteStream } from "@/services/stream.js"; +import type { CacheableUser } from "@/models/entities/user.js"; +import { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { PollVotes, NoteWatchings, Polls, Blockings } from "@/models/index.js"; +import { Not } from "typeorm"; +import { genId } from "@/misc/gen-id.js"; +import { createNotification } from "../../create-notification.js"; -export default async function(user: CacheableUser, note: Note, choice: number) { +export default async function ( + user: CacheableUser, + note: Note, + choice: number, +) { const poll = await Polls.findOneBy({ noteId: note.id }); - if (poll == null) throw new Error('poll not found'); + if (poll == null) throw new Error("poll not found"); // Check whether is valid choice - if (poll.choices[choice] == null) throw new Error('invalid choice param'); + if (poll.choices[choice] == null) throw new Error("invalid choice param"); // Check blocking if (note.userId !== user.id) { @@ -21,7 +26,7 @@ export default async function(user: CacheableUser, note: Note, choice: number) { blockeeId: user.id, }); if (block) { - throw new Error('blocked'); + throw new Error("blocked"); } } @@ -32,11 +37,11 @@ export default async function(user: CacheableUser, note: Note, choice: number) { }); if (poll.multiple) { - if (exist.some(x => x.choice === choice)) { - throw new Error('already voted'); + if (exist.some((x) => x.choice === choice)) { + throw new Error("already voted"); } } else if (exist.length !== 0) { - throw new Error('already voted'); + throw new Error("already voted"); } // Create vote @@ -50,15 +55,17 @@ export default async function(user: CacheableUser, note: Note, choice: number) { // Increment votes count const index = choice + 1; // In SQL, array index is 1 based - await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`); + await Polls.query( + `UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`, + ); - publishNoteStream(note.id, 'pollVoted', { + publishNoteStream(note.id, "pollVoted", { choice: choice, userId: user.id, }); // Notify - createNotification(note.userId, 'pollVote', { + createNotification(note.userId, "pollVote", { notifierId: user.id, noteId: note.id, choice: choice, @@ -68,10 +75,9 @@ export default async function(user: CacheableUser, note: Note, choice: number) { NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), - }) - .then(watchers => { + }).then((watchers) => { for (const watcher of watchers) { - createNotification(watcher.userId, 'pollVote', { + createNotification(watcher.userId, "pollVote", { notifierId: user.id, noteId: note.id, choice: choice, diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index 83d302826..1a3c52eb5 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -1,21 +1,32 @@ -import { publishNoteStream } from '@/services/stream.js'; -import { renderLike } from '@/remote/activitypub/renderer/like.js'; -import DeliverManager from '@/remote/activitypub/deliver-manager.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import { toDbReaction, decodeReaction } from '@/misc/reaction-lib.js'; -import { User, IRemoteUser } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { NoteReactions, Users, NoteWatchings, Notes, Emojis, Blockings } from '@/models/index.js'; -import { IsNull, Not } from 'typeorm'; -import { perUserReactionsChart } from '@/services/chart/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { createNotification } from '../../create-notification.js'; -import deleteReaction from './delete.js'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; -import { NoteReaction } from '@/models/entities/note-reaction.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { publishNoteStream } from "@/services/stream.js"; +import { renderLike } from "@/remote/activitypub/renderer/like.js"; +import DeliverManager from "@/remote/activitypub/deliver-manager.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import { toDbReaction, decodeReaction } from "@/misc/reaction-lib.js"; +import type { User, IRemoteUser } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { + NoteReactions, + Users, + NoteWatchings, + Notes, + Emojis, + Blockings, +} from "@/models/index.js"; +import { IsNull, Not } from "typeorm"; +import { perUserReactionsChart } from "@/services/chart/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { createNotification } from "../../create-notification.js"; +import deleteReaction from "./delete.js"; +import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; +import type { NoteReaction } from "@/models/entities/note-reaction.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; -export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => { +export default async ( + user: { id: User["id"]; host: User["host"] }, + note: Note, + reaction?: string, +) => { // Check blocking if (note.userId !== user.id) { const block = await Blockings.findOneBy({ @@ -23,13 +34,16 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, blockeeId: user.id, }); if (block) { - throw new IdentifiableError('e70412a4-7197-4726-8e74-f3e0deb92aa7'); + throw new IdentifiableError("e70412a4-7197-4726-8e74-f3e0deb92aa7"); } } // check visibility - if (!await Notes.isVisibleForMe(note, user.id)) { - throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.'); + if (!(await Notes.isVisibleForMe(note, user.id))) { + throw new IdentifiableError( + "68e9d2d1-48bf-42c2-b90a-b20e09fd3d48", + "Note not accessible for you.", + ); } // TODO: cache @@ -59,7 +73,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, await NoteReactions.insert(record); } else { // 同じリアクションがすでにされていたらエラー - throw new IdentifiableError('51c42bb4-931a-456b-bff7-e5a8a70dd298'); + throw new IdentifiableError("51c42bb4-931a-456b-bff7-e5a8a70dd298"); } } else { throw e; @@ -68,12 +82,13 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, // Increment reactions count const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`; - await Notes.createQueryBuilder().update() + await Notes.createQueryBuilder() + .update() .set({ reactions: () => sql, score: () => '"score" + 1', }) - .where('id = :id', { id: note.id }) + .where("id = :id", { id: note.id }) .execute(); perUserReactionsChart.update(user, note); @@ -86,22 +101,28 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, name: decodedReaction.name, host: decodedReaction.host ?? IsNull(), }, - select: ['name', 'host', 'originalUrl', 'publicUrl'], + select: ["name", "host", "originalUrl", "publicUrl"], }); - publishNoteStream(note.id, 'reacted', { + publishNoteStream(note.id, "reacted", { reaction: decodedReaction.reaction, - emoji: emoji != null ? { - name: emoji.host ? `${emoji.name}@${emoji.host}` : `${emoji.name}@.`, - url: emoji.publicUrl || emoji.originalUrl, // || emoji.originalUrl してるのは後方互換性のため - } : null, + emoji: + emoji != null + ? { + name: emoji.host + ? `${emoji.name}@${emoji.host}` + : `${emoji.name}@.`, + url: emoji.publicUrl || emoji.originalUrl, // || emoji.originalUrl してるのは後方互換性のため + } + : null, userId: user.id, }); // リアクションされたユーザーがローカルユーザーなら通知を作成 if (note.userHost === null) { - createNotification(note.userId, 'reaction', { + createNotification(note.userId, "reaction", { notifierId: user.id, + note: note, noteId: note.id, reaction: reaction, }); @@ -111,10 +132,11 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), - }).then(watchers => { + }).then((watchers) => { for (const watcher of watchers) { - createNotification(watcher.userId, 'reaction', { + createNotification(watcher.userId, "reaction", { notifierId: user.id, + note: note, noteId: note.id, reaction: reaction, }); @@ -130,11 +152,13 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, dm.addDirectRecipe(reactee as IRemoteUser); } - if (['public', 'home', 'followers'].includes(note.visibility)) { + if (["public", "home", "followers"].includes(note.visibility)) { dm.addFollowersRecipe(); - } else if (note.visibility === 'specified') { - const visibleUsers = await Promise.all(note.visibleUserIds.map(id => Users.findOneBy({ id }))); - for (const u of visibleUsers.filter(u => u && Users.isRemoteUser(u))) { + } else if (note.visibility === "specified") { + const visibleUsers = await Promise.all( + note.visibleUserIds.map((id) => Users.findOneBy({ id })), + ); + for (const u of visibleUsers.filter((u) => u && Users.isRemoteUser(u))) { dm.addDirectRecipe(u as IRemoteUser); } } diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index a7cbcb1c1..82648249e 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -1,15 +1,18 @@ -import { publishNoteStream } from '@/services/stream.js'; -import { renderLike } from '@/remote/activitypub/renderer/like.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { renderActivity } from '@/remote/activitypub/renderer/index.js'; -import DeliverManager from '@/remote/activitypub/deliver-manager.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { User, IRemoteUser } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { NoteReactions, Users, Notes } from '@/models/index.js'; -import { decodeReaction } from '@/misc/reaction-lib.js'; +import { publishNoteStream } from "@/services/stream.js"; +import { renderLike } from "@/remote/activitypub/renderer/like.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { renderActivity } from "@/remote/activitypub/renderer/index.js"; +import DeliverManager from "@/remote/activitypub/deliver-manager.js"; +import { IdentifiableError } from "@/misc/identifiable-error.js"; +import type { User, IRemoteUser } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { NoteReactions, Users, Notes } from "@/models/index.js"; +import { decodeReaction } from "@/misc/reaction-lib.js"; -export default async (user: { id: User['id']; host: User['host']; }, note: Note) => { +export default async ( + user: { id: User["id"]; host: User["host"] }, + note: Note, +) => { // if already unreacted const exist = await NoteReactions.findOneBy({ noteId: note.id, @@ -17,35 +20,44 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note) }); if (exist == null) { - throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'not reacted'); + throw new IdentifiableError( + "60527ec9-b4cb-4a88-a6bd-32d3ad26817d", + "not reacted", + ); } // Delete reaction const result = await NoteReactions.delete(exist.id); if (result.affected !== 1) { - throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'not reacted'); + throw new IdentifiableError( + "60527ec9-b4cb-4a88-a6bd-32d3ad26817d", + "not reacted", + ); } // Decrement reactions count const sql = `jsonb_set("reactions", '{${exist.reaction}}', (COALESCE("reactions"->>'${exist.reaction}', '0')::int - 1)::text::jsonb)`; - await Notes.createQueryBuilder().update() + await Notes.createQueryBuilder() + .update() .set({ reactions: () => sql, }) - .where('id = :id', { id: note.id }) + .where("id = :id", { id: note.id }) .execute(); - Notes.decrement({ id: note.id }, 'score', 1); + Notes.decrement({ id: note.id }, "score", 1); - publishNoteStream(note.id, 'unreacted', { + publishNoteStream(note.id, "unreacted", { reaction: decodeReaction(exist.reaction).reaction, userId: user.id, }); //#region 配信 if (Users.isLocalUser(user) && !note.localOnly) { - const content = renderActivity(renderUndo(await renderLike(exist, note), user)); + const content = renderActivity( + renderUndo(await renderLike(exist, note), user), + ); const dm = new DeliverManager(user, content); if (note.userHost !== null) { const reactee = await Users.findOneBy({ id: note.userId }); diff --git a/packages/backend/src/services/note/read.ts b/packages/backend/src/services/note/read.ts index 915a9e9ee..53188f15f 100644 --- a/packages/backend/src/services/note/read.ts +++ b/packages/backend/src/services/note/read.ts @@ -1,48 +1,66 @@ -import { publishMainStream } from '@/services/stream.js'; -import { Note } from '@/models/entities/note.js'; -import { User } from '@/models/entities/user.js'; -import { NoteUnreads, AntennaNotes, Users, Followings, ChannelFollowings } from '@/models/index.js'; -import { Not, IsNull, In } from 'typeorm'; -import { Channel } from '@/models/entities/channel.js'; -import { checkHitAntenna } from '@/misc/check-hit-antenna.js'; -import { getAntennas } from '@/misc/antenna-cache.js'; -import { readNotificationByQuery } from '@/server/api/common/read-notification.js'; -import { Packed } from '@/misc/schema.js'; +import { publishMainStream } from "@/services/stream.js"; +import type { Note } from "@/models/entities/note.js"; +import type { User } from "@/models/entities/user.js"; +import { + NoteUnreads, + AntennaNotes, + Users, + Followings, + ChannelFollowings, +} from "@/models/index.js"; +import { Not, IsNull, In } from "typeorm"; +import type { Channel } from "@/models/entities/channel.js"; +import { checkHitAntenna } from "@/misc/check-hit-antenna.js"; +import { getAntennas } from "@/misc/antenna-cache.js"; +import { readNotificationByQuery } from "@/server/api/common/read-notification.js"; +import type { Packed } from "@/misc/schema.js"; /** * Mark notes as read */ -export default async function( - userId: User['id'], - notes: (Note | Packed<'Note'>)[], +export default async function ( + userId: User["id"], + notes: (Note | Packed<"Note">)[], info?: { - following: Set; - followingChannels: Set; - } + following: Set; + followingChannels: Set; + }, ) { - const following = info?.following ? info.following : new Set((await Followings.find({ - where: { - followerId: userId, - }, - select: ['followeeId'], - })).map(x => x.followeeId)); - const followingChannels = info?.followingChannels ? info.followingChannels : new Set((await ChannelFollowings.find({ - where: { - followerId: userId, - }, - select: ['followeeId'], - })).map(x => x.followeeId)); + const following = info?.following + ? info.following + : new Set( + ( + await Followings.find({ + where: { + followerId: userId, + }, + select: ["followeeId"], + }) + ).map((x) => x.followeeId), + ); + const followingChannels = info?.followingChannels + ? info.followingChannels + : new Set( + ( + await ChannelFollowings.find({ + where: { + followerId: userId, + }, + select: ["followeeId"], + }) + ).map((x) => x.followeeId), + ); - const myAntennas = (await getAntennas()).filter(a => a.userId === userId); - const readMentions: (Note | Packed<'Note'>)[] = []; - const readSpecifiedNotes: (Note | Packed<'Note'>)[] = []; - const readChannelNotes: (Note | Packed<'Note'>)[] = []; - const readAntennaNotes: (Note | Packed<'Note'>)[] = []; + const myAntennas = (await getAntennas()).filter((a) => a.userId === userId); + const readMentions: (Note | Packed<"Note">)[] = []; + const readSpecifiedNotes: (Note | Packed<"Note">)[] = []; + const readChannelNotes: (Note | Packed<"Note">)[] = []; + const readAntennaNotes: (Note | Packed<"Note">)[] = []; for (const note of notes) { - if (note.mentions && note.mentions.includes(userId)) { + if (note.mentions?.includes(userId)) { readMentions.push(note); - } else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) { + } else if (note.visibleUserIds?.includes(userId)) { readSpecifiedNotes.push(note); } @@ -50,20 +68,37 @@ export default async function( readChannelNotes.push(note); } - if (note.user != null) { // たぶんnullになることは無いはずだけど一応 + if (note.user != null) { + // たぶんnullになることは無いはずだけど一応 for (const antenna of myAntennas) { - if (await checkHitAntenna(antenna, note, note.user, undefined, Array.from(following))) { + if ( + await checkHitAntenna( + antenna, + note, + note.user, + undefined, + Array.from(following), + ) + ) { readAntennaNotes.push(note); } } } } - if ((readMentions.length > 0) || (readSpecifiedNotes.length > 0) || (readChannelNotes.length > 0)) { + if ( + readMentions.length > 0 || + readSpecifiedNotes.length > 0 || + readChannelNotes.length > 0 + ) { // Remove the record await NoteUnreads.delete({ userId: userId, - noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id), ...readChannelNotes.map(n => n.id)]), + noteId: In([ + ...readMentions.map((n) => n.id), + ...readSpecifiedNotes.map((n) => n.id), + ...readChannelNotes.map((n) => n.id), + ]), }); // TODO: ↓まとめてクエリしたい @@ -71,45 +106,51 @@ export default async function( NoteUnreads.countBy({ userId: userId, isMentioned: true, - }).then(mentionsCount => { + }).then((mentionsCount) => { if (mentionsCount === 0) { // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadMentions'); + publishMainStream(userId, "readAllUnreadMentions"); } }); NoteUnreads.countBy({ userId: userId, isSpecified: true, - }).then(specifiedCount => { + }).then((specifiedCount) => { if (specifiedCount === 0) { // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); + publishMainStream(userId, "readAllUnreadSpecifiedNotes"); } }); NoteUnreads.countBy({ userId: userId, noteChannelId: Not(IsNull()), - }).then(channelNoteCount => { + }).then((channelNoteCount) => { if (channelNoteCount === 0) { // 全て既読になったイベントを発行 - publishMainStream(userId, 'readAllChannels'); + publishMainStream(userId, "readAllChannels"); } }); readNotificationByQuery(userId, { - noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id)]), + noteId: In([ + ...readMentions.map((n) => n.id), + ...readSpecifiedNotes.map((n) => n.id), + ]), }); } if (readAntennaNotes.length > 0) { - await AntennaNotes.update({ - antennaId: In(myAntennas.map(a => a.id)), - noteId: In(readAntennaNotes.map(n => n.id)), - }, { - read: true, - }); + await AntennaNotes.update( + { + antennaId: In(myAntennas.map((a) => a.id)), + noteId: In(readAntennaNotes.map((n) => n.id)), + }, + { + read: true, + }, + ); // TODO: まとめてクエリしたい for (const antenna of myAntennas) { @@ -119,13 +160,13 @@ export default async function( }); if (count === 0) { - publishMainStream(userId, 'readAntenna', antenna); + publishMainStream(userId, "readAntenna", antenna); } } - Users.getHasUnreadAntenna(userId).then(unread => { + Users.getHasUnreadAntenna(userId).then((unread) => { if (!unread) { - publishMainStream(userId, 'readAllAntennas'); + publishMainStream(userId, "readAllAntennas"); } }); } diff --git a/packages/backend/src/services/note/unread.ts b/packages/backend/src/services/note/unread.ts index d9ed711e0..275b230d4 100644 --- a/packages/backend/src/services/note/unread.ts +++ b/packages/backend/src/services/note/unread.ts @@ -1,20 +1,24 @@ -import { Note } from '@/models/entities/note.js'; -import { publishMainStream } from '@/services/stream.js'; -import { User } from '@/models/entities/user.js'; -import { Mutings, NoteThreadMutings, NoteUnreads } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; +import type { Note } from "@/models/entities/note.js"; +import { publishMainStream } from "@/services/stream.js"; +import type { User } from "@/models/entities/user.js"; +import { Mutings, NoteThreadMutings, NoteUnreads } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; -export async function insertNoteUnread(userId: User['id'], note: Note, params: { - // NOTE: isSpecifiedがtrueならisMentionedは必ずfalse - isSpecified: boolean; - isMentioned: boolean; -}) { +export async function insertNoteUnread( + userId: User["id"], + note: Note, + params: { + // NOTE: isSpecifiedがtrueならisMentionedは必ずfalse + isSpecified: boolean; + isMentioned: boolean; + }, +) { //#region ミュートしているなら無視 // TODO: 現在の仕様ではChannelにミュートは適用されないのでよしなにケアする const mute = await Mutings.findBy({ muterId: userId, }); - if (mute.map(m => m.muteeId).includes(note.userId)) return; + if (mute.map((m) => m.muteeId).includes(note.userId)) return; //#endregion // スレッドミュート @@ -43,13 +47,13 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: { if (exist == null) return; if (params.isMentioned) { - publishMainStream(userId, 'unreadMention', note.id); + publishMainStream(userId, "unreadMention", note.id); } if (params.isSpecified) { - publishMainStream(userId, 'unreadSpecifiedNote', note.id); + publishMainStream(userId, "unreadSpecifiedNote", note.id); } if (note.channelId) { - publishMainStream(userId, 'unreadChannel', note.id); + publishMainStream(userId, "unreadChannel", note.id); } }, 2000); } diff --git a/packages/backend/src/services/note/unwatch.ts b/packages/backend/src/services/note/unwatch.ts index 3964b2ba5..b4da5e86d 100644 --- a/packages/backend/src/services/note/unwatch.ts +++ b/packages/backend/src/services/note/unwatch.ts @@ -1,8 +1,8 @@ -import { User } from '@/models/entities/user.js'; -import { NoteWatchings } from '@/models/index.js'; -import { Note } from '@/models/entities/note.js'; +import type { User } from "@/models/entities/user.js"; +import { NoteWatchings } from "@/models/index.js"; +import type { Note } from "@/models/entities/note.js"; -export default async (me: User['id'], note: Note) => { +export default async (me: User["id"], note: Note) => { await NoteWatchings.delete({ noteId: note.id, userId: me, diff --git a/packages/backend/src/services/note/watch.ts b/packages/backend/src/services/note/watch.ts index 2210c44a7..2a99dd694 100644 --- a/packages/backend/src/services/note/watch.ts +++ b/packages/backend/src/services/note/watch.ts @@ -1,10 +1,10 @@ -import { User } from '@/models/entities/user.js'; -import { Note } from '@/models/entities/note.js'; -import { NoteWatchings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { NoteWatching } from '@/models/entities/note-watching.js'; +import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; +import { NoteWatchings } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import type { NoteWatching } from "@/models/entities/note-watching.js"; -export default async (me: User['id'], note: Note) => { +export default async (me: User["id"], note: Note) => { // 自分の投稿はwatchできない if (me === note.userId) { return; diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 393a23d05..0e51ad967 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -1,50 +1,61 @@ -import push from 'web-push'; -import config from '@/config/index.js'; -import { SwSubscriptions } from '@/models/index.js'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Packed } from '@/misc/schema.js'; -import { getNoteSummary } from '@/misc/get-note-summary.js'; +import push from "web-push"; +import config from "@/config/index.js"; +import { SwSubscriptions } from "@/models/index.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import type { Packed } from "@/misc/schema.js"; +import { getNoteSummary } from "@/misc/get-note-summary.js"; // Defined also packages/sw/types.ts#L14-L21 type pushNotificationsTypes = { - 'notification': Packed<'Notification'>; - 'unreadMessagingMessage': Packed<'MessagingMessage'>; - 'readNotifications': { notificationIds: string[] }; - 'readAllNotifications': undefined; - 'readAllMessagingMessages': undefined; - 'readAllMessagingMessagesOfARoom': { userId: string } | { groupId: string }; + notification: Packed<"Notification">; + unreadMessagingMessage: Packed<"MessagingMessage">; + readNotifications: { notificationIds: string[] }; + readAllNotifications: undefined; + readAllMessagingMessages: undefined; + readAllMessagingMessagesOfARoom: { userId: string } | { groupId: string }; }; // プッシュメッセージサーバーには文字数制限があるため、内容を削減します -function truncateNotification(notification: Packed<'Notification'>): any { +function truncateNotification(notification: Packed<"Notification">): any { if (notification.note) { return { ...notification, note: { ...notification.note, // textをgetNoteSummaryしたものに置き換える - text: getNoteSummary(notification.type === 'renote' ? notification.note.renote as Packed<'Note'> : notification.note), + text: getNoteSummary( + notification.type === "renote" + ? (notification.note.renote as Packed<"Note">) + : notification.note, + ), cw: undefined, reply: undefined, renote: undefined, user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる - } + }, }; } return notification; } -export async function pushNotification(userId: string, type: T, body: pushNotificationsTypes[T]) { +export async function pushNotification( + userId: string, + type: T, + body: pushNotificationsTypes[T], +) { const meta = await fetchMeta(); - if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return; + if ( + !meta.enableServiceWorker || + meta.swPublicKey == null || + meta.swPrivateKey == null + ) + return; // アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録 - push.setVapidDetails(config.url, - meta.swPublicKey, - meta.swPrivateKey); + push.setVapidDetails(config.url, meta.swPublicKey, meta.swPrivateKey); // Fetch const subscriptions = await SwSubscriptions.findBy({ @@ -60,26 +71,35 @@ export async function pushNotification(u }, }; - push.sendNotification(pushSubscription, JSON.stringify({ - type, - body: type === 'notification' ? truncateNotification(body as Packed<'Notification'>) : body, - userId, - dateTime: (new Date()).getTime(), - }), { - proxy: config.proxy, - }).catch((err: any) => { - //swLogger.info(err.statusCode); - //swLogger.info(err.headers); - //swLogger.info(err.body); + push + .sendNotification( + pushSubscription, + JSON.stringify({ + type, + body: + type === "notification" + ? truncateNotification(body as Packed<"Notification">) + : body, + userId, + dateTime: new Date().getTime(), + }), + { + proxy: config.proxy, + }, + ) + .catch((err: any) => { + //swLogger.info(err.statusCode); + //swLogger.info(err.headers); + //swLogger.info(err.body); - if (err.statusCode === 410) { - SwSubscriptions.delete({ - userId: userId, - endpoint: subscription.endpoint, - auth: subscription.auth, - publickey: subscription.publickey, - }); - } - }); + if (err.statusCode === 410) { + SwSubscriptions.delete({ + userId: userId, + endpoint: subscription.endpoint, + auth: subscription.auth, + publickey: subscription.publickey, + }); + } + }); } } diff --git a/packages/backend/src/services/register-or-fetch-instance-doc.ts b/packages/backend/src/services/register-or-fetch-instance-doc.ts index df7d125d0..4c3570e90 100644 --- a/packages/backend/src/services/register-or-fetch-instance-doc.ts +++ b/packages/backend/src/services/register-or-fetch-instance-doc.ts @@ -1,12 +1,14 @@ -import { Instance } from '@/models/entities/instance.js'; -import { Instances } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { toPuny } from '@/misc/convert-host.js'; -import { Cache } from '@/misc/cache.js'; +import type { Instance } from "@/models/entities/instance.js"; +import { Instances } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { toPuny } from "@/misc/convert-host.js"; +import { Cache } from "@/misc/cache.js"; const cache = new Cache(1000 * 60 * 60); -export async function registerOrFetchInstanceDoc(host: string): Promise { +export async function registerOrFetchInstanceDoc( + host: string, +): Promise { host = toPuny(host); const cached = cache.get(host); @@ -20,7 +22,7 @@ export async function registerOrFetchInstanceDoc(host: string): Promise Instances.findOneByOrFail(x.identifiers[0])); + }).then((x) => Instances.findOneByOrFail(x.identifiers[0])); cache.set(host, i); return i; diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index a05645f09..244e05c03 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -1,16 +1,19 @@ -import { IsNull } from 'typeorm'; -import { renderFollowRelay } from '@/remote/activitypub/renderer/follow-relay.js'; -import { renderActivity, attachLdSignature } from '@/remote/activitypub/renderer/index.js'; -import renderUndo from '@/remote/activitypub/renderer/undo.js'; -import { deliver } from '@/queue/index.js'; -import { ILocalUser, User } from '@/models/entities/user.js'; -import { Users, Relays } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { Cache } from '@/misc/cache.js'; -import { Relay } from '@/models/entities/relay.js'; -import { createSystemUser } from './create-system-user.js'; +import { IsNull } from "typeorm"; +import { renderFollowRelay } from "@/remote/activitypub/renderer/follow-relay.js"; +import { + renderActivity, + attachLdSignature, +} from "@/remote/activitypub/renderer/index.js"; +import renderUndo from "@/remote/activitypub/renderer/undo.js"; +import { deliver } from "@/queue/index.js"; +import type { ILocalUser, User } from "@/models/entities/user.js"; +import { Users, Relays } from "@/models/index.js"; +import { genId } from "@/misc/gen-id.js"; +import { Cache } from "@/misc/cache.js"; +import type { Relay } from "@/models/entities/relay.js"; +import { createSystemUser } from "./create-system-user.js"; -const ACTOR_USERNAME = 'relay.actor' as const; +const ACTOR_USERNAME = "relay.actor" as const; const relaysCache = new Cache(1000 * 60 * 10); @@ -30,8 +33,8 @@ export async function addRelay(inbox: string) { const relay = await Relays.insert({ id: genId(), inbox, - status: 'requesting', - }).then(x => Relays.findOneByOrFail(x.identifiers[0])); + status: "requesting", + }).then((x) => Relays.findOneByOrFail(x.identifiers[0])); const relayActor = await getRelayActor(); const follow = await renderFollowRelay(relay, relayActor); @@ -47,7 +50,7 @@ export async function removeRelay(inbox: string) { }); if (relay == null) { - throw new Error('relay not found'); + throw new Error("relay not found"); } const relayActor = await getRelayActor(); @@ -66,7 +69,7 @@ export async function listRelay() { export async function relayAccepted(id: string) { const result = await Relays.update(id, { - status: 'accepted', + status: "accepted", }); return JSON.stringify(result); @@ -74,24 +77,29 @@ export async function relayAccepted(id: string) { export async function relayRejected(id: string) { const result = await Relays.update(id, { - status: 'rejected', + status: "rejected", }); return JSON.stringify(result); } -export async function deliverToRelays(user: { id: User['id']; host: null; }, activity: any) { +export async function deliverToRelays( + user: { id: User["id"]; host: null }, + activity: any, +) { if (activity == null) return; - const relays = await relaysCache.fetch(null, () => Relays.findBy({ - status: 'accepted', - })); + const relays = await relaysCache.fetch(null, () => + Relays.findBy({ + status: "accepted", + }), + ); if (relays.length === 0) return; // TODO //const copy = structuredClone(activity); const copy = JSON.parse(JSON.stringify(activity)); - if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public']; + if (!copy.to) copy.to = ["https://www.w3.org/ns/activitystreams#Public"]; const signed = await attachLdSignature(copy, user); diff --git a/packages/backend/src/services/send-email-notification.ts b/packages/backend/src/services/send-email-notification.ts index 4a2f94b42..14a9754fe 100644 --- a/packages/backend/src/services/send-email-notification.ts +++ b/packages/backend/src/services/send-email-notification.ts @@ -1,14 +1,14 @@ -import { UserProfiles } from '@/models/index.js'; -import { User } from '@/models/entities/user.js'; -import { sendEmail } from './send-email.js'; -import { I18n } from '@/misc/i18n.js'; -import * as Acct from '@/misc/acct.js'; +import { UserProfiles } from "@/models/index.js"; +import type { User } from "@/models/entities/user.js"; +import { sendEmail } from "./send-email.js"; +import { I18n } from "@/misc/i18n.js"; +import * as Acct from "@/misc/acct.js"; // TODO //const locales = await import('../../../../locales/index.js'); // TODO: locale ファイルをクライアント用とサーバー用で分けたい -async function follow(userId: User['id'], follower: User) { +async function follow(userId: User["id"], follower: User) { /* const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return; @@ -19,7 +19,7 @@ async function follow(userId: User['id'], follower: User) { */ } -async function receiveFollowRequest(userId: User['id'], follower: User) { +async function receiveFollowRequest(userId: User["id"], follower: User) { /* const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return; diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts index 7487cb659..87a0d5e33 100644 --- a/packages/backend/src/services/send-email.ts +++ b/packages/backend/src/services/send-email.ts @@ -1,17 +1,22 @@ -import * as nodemailer from 'nodemailer'; -import { fetchMeta } from '@/misc/fetch-meta.js'; -import Logger from './logger.js'; -import config from '@/config/index.js'; +import * as nodemailer from "nodemailer"; +import { fetchMeta } from "@/misc/fetch-meta.js"; +import Logger from "./logger.js"; +import config from "@/config/index.js"; -export const logger = new Logger('email'); +export const logger = new Logger("email"); -export async function sendEmail(to: string, subject: string, html: string, text: string) { +export async function sendEmail( + to: string, + subject: string, + html: string, + text: string, +) { const meta = await fetchMeta(true); const iconUrl = `${config.url}/static-assets/mi-white.png`; const emailSettingUrl = `${config.url}/settings/email`; - const enableAuth = meta.smtpUser != null && meta.smtpUser !== ''; + const enableAuth = meta.smtpUser != null && meta.smtpUser !== ""; const transporter = nodemailer.createTransport({ host: meta.smtpHost, @@ -19,10 +24,12 @@ export async function sendEmail(to: string, subject: string, html: string, text: secure: meta.smtpSecure, ignoreTLS: !enableAuth, proxy: config.proxySmtp, - auth: enableAuth ? { - user: meta.smtpUser, - pass: meta.smtpPass, - } : undefined, + auth: enableAuth + ? { + user: meta.smtpUser, + pass: meta.smtpPass, + } + : undefined, } as any); try { @@ -36,7 +43,7 @@ export async function sendEmail(to: string, subject: string, html: string, text: - ${ subject } + ${subject} diff --git a/packages/client/src/components/MkChart.vue b/packages/client/src/components/MkChart.vue index c4706d53d..701deafae 100644 --- a/packages/client/src/components/MkChart.vue +++ b/packages/client/src/components/MkChart.vue @@ -8,11 +8,6 @@ + diff --git a/packages/client/src/components/MkCode.core.vue b/packages/client/src/components/MkCode.core.vue index b07402882..934e0a158 100644 --- a/packages/client/src/components/MkCode.core.vue +++ b/packages/client/src/components/MkCode.core.vue @@ -1,4 +1,3 @@ - + + diff --git a/packages/client/src/widgets/widget.ts b/packages/client/src/widgets/widget.ts index 8bd56a596..1afc296de 100644 --- a/packages/client/src/widgets/widget.ts +++ b/packages/client/src/widgets/widget.ts @@ -1,8 +1,8 @@ -import { reactive, watch } from 'vue'; -import { throttle } from 'throttle-debounce'; -import { Form, GetFormResultType } from '@/scripts/form'; -import * as os from '@/os'; -import { deepClone } from '@/scripts/clone'; +import { reactive, watch } from "vue"; +import { throttle } from "throttle-debounce"; +import { Form, GetFormResultType } from "@/scripts/form"; +import * as os from "@/os"; +import { deepClone } from "@/scripts/clone"; export type Widget

> = { id: string; @@ -14,7 +14,7 @@ export type WidgetComponentProps

> = { }; export type WidgetComponentEmits

> = { - (ev: 'updateProps', props: P); + (ev: "updateProps", props: P); }; export type WidgetComponentExpose = { @@ -23,7 +23,9 @@ export type WidgetComponentExpose = { configure: () => void; }; -export const useWidgetPropsManager = >( +export const useWidgetPropsManager = < + F extends Form & Record, +>( name: string, propsDef: F, props: Readonly>>, @@ -33,21 +35,27 @@ export const useWidgetPropsManager = void; configure: () => void; } => { - const widgetProps = reactive(props.widget ? deepClone(props.widget.data) : {}); + const widgetProps = reactive( + props.widget ? deepClone(props.widget.data) : {}, + ); const mergeProps = () => { for (const prop of Object.keys(propsDef)) { - if (typeof widgetProps[prop] === 'undefined') { + if (typeof widgetProps[prop] === "undefined") { widgetProps[prop] = propsDef[prop].default; } } }; - watch(widgetProps, () => { - mergeProps(); - }, { deep: true, immediate: true }); + watch( + widgetProps, + () => { + mergeProps(); + }, + { deep: true, immediate: true }, + ); const save = throttle(3000, () => { - emit('updateProps', widgetProps); + emit("updateProps", widgetProps); }); const configure = async () => { diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 86109f600..2d292dbfb 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -40,7 +40,6 @@ }, "compileOnSave": false, "include": [ - ".eslintrc.js", "./**/*.ts", "./**/*.vue" ] diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts index f23c62113..dfc6a3b66 100644 --- a/packages/client/vite.config.ts +++ b/packages/client/vite.config.ts @@ -46,10 +46,10 @@ export default defineConfig(({ command, mode }) => { build: { target: [ - 'chrome100', - 'firefox100', - 'safari15', - 'es2017', // TODO: そのうち消す + 'chrome108', + 'firefox109', + 'safari16', + 'es2022', ], manifest: 'manifest.json', rollupOptions: { @@ -63,11 +63,15 @@ export default defineConfig(({ command, mode }) => { }, }, cssCodeSplit: true, + assetsInlineLimit: 0, outDir: __dirname + '/../../built/_client_dist_', assetsDir: '.', emptyOutDir: false, - sourcemap: process.env.NODE_ENV !== 'production', + sourcemap: process.env.NODE_ENV === 'development', reportCompressedSize: false, }, + optimizeDeps: { + auto: true, + }, }; }); diff --git a/packages/client/vite.json5.ts b/packages/client/vite.json5.ts index 0a37fbff4..e1612d2e8 100644 --- a/packages/client/vite.json5.ts +++ b/packages/client/vite.json5.ts @@ -12,7 +12,6 @@ export default function json5(options: RollupJsonOptions = {}): Plugin { return { name: 'json5', - // eslint-disable-next-line no-shadow transform(json, id) { if (id.slice(-6) !== '.json5' || !filter(id)) return null; diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js deleted file mode 100644 index 5a6a9c5af..000000000 --- a/packages/shared/.eslintrc.js +++ /dev/null @@ -1,81 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - 'import' - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript' - ], - rules: { - 'indent': ['warn', 'tab', { - 'SwitchCase': 1, - 'MemberExpression': 1, - 'flatTernaryExpressions': true, - 'ArrayExpression': 'first', - 'ObjectExpression': 'first', - }], - 'eol-last': ['error', 'always'], - 'semi': ['error', 'always'], - 'semi-spacing': ['error', { 'before': false, 'after': true }], - 'quotes': ['warn', 'single'], - 'comma-dangle': ['warn', 'always-multiline'], - 'keyword-spacing': ['error', { - 'before': true, - 'after': true, - }], - 'key-spacing': ['error', { - 'beforeColon': false, - 'afterColon': true, - }], - 'arrow-spacing': ['error', { - 'before': true, - 'after': true, - }], - 'padded-blocks': ['error', 'never'], - /* TODO: path aliasを使わないとwarnする - 'no-restricted-imports': ['warn', { - 'patterns': [ - ] - }], - */ - 'eqeqeq': ['error', 'always', { 'null': 'ignore' }], - 'no-multi-spaces': ['error'], - 'no-var': ['error'], - 'prefer-arrow-callback': ['error'], - 'no-throw-literal': ['warn'], - 'no-param-reassign': ['warn'], - 'no-constant-condition': ['warn'], - 'no-empty-pattern': ['warn'], - 'no-async-promise-executor': ['off'], - 'no-useless-escape': ['off'], - 'no-multiple-empty-lines': ['error', { 'max': 1 }], - 'no-control-regex': ['warn'], - 'no-empty': ['warn'], - 'no-inner-declarations': ['off'], - 'no-sparse-arrays': ['off'], - 'nonblock-statement-body-position': ['error', 'beside'], - 'object-curly-spacing': ['error', 'always'], - 'space-infix-ops': ['error'], - 'space-before-blocks': ['error', 'always'], - '@typescript-eslint/no-unnecessary-condition': ['warn'], - '@typescript-eslint/no-var-requires': ['warn'], - '@typescript-eslint/no-inferrable-types': ['warn'], - '@typescript-eslint/no-empty-function': ['off'], - '@typescript-eslint/no-non-null-assertion': ['warn'], - '@typescript-eslint/explicit-function-return-type': ['warn'], - '@typescript-eslint/no-misused-promises': ['error', { - 'checksVoidReturn': false, - }], - '@typescript-eslint/consistent-type-imports': 'error', - 'import/no-unresolved': ['off'], - 'import/no-default-export': ['warn'], - 'import/order': ['warn', { - 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - }] - }, -}; diff --git a/packages/sw/.eslintrc.js b/packages/sw/.eslintrc.js deleted file mode 100644 index 9d56daca8..000000000 --- a/packages/sw/.eslintrc.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - root: true, - env: { - "node": false - }, - parserOptions: { - "parser": "@typescript-eslint/parser", - tsconfigRootDir: __dirname, - //project: ['./tsconfig.json'], - }, - extends: [ - //"../shared/.eslintrc.js", - ], - globals: { - "require": false, - "_DEV_": false, - "_LANGS_": false, - "_VERSION_": false, - "_ENV_": false, - "_PERF_PREFIX_": false, - } -} diff --git a/packages/sw/.swcrc b/packages/sw/.swcrc new file mode 100644 index 000000000..1d6d3b496 --- /dev/null +++ b/packages/sw/.swcrc @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "dynamicImport": true, + "decorators": true + }, + "transform": { + "decoratorMetadata": true + }, + "experimental": { + "keepImportAssertions": true + }, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + }, + "target": "es2022" + }, + "minify": false +} diff --git a/packages/sw/build.js b/packages/sw/build.js deleted file mode 100644 index c2a72fa4e..000000000 --- a/packages/sw/build.js +++ /dev/null @@ -1,37 +0,0 @@ -const esbuild = require('esbuild'); -const locales = require('../../locales'); -const meta = require('../../package.json'); -const watch = process.argv[2]?.includes('watch'); - -console.log('Starting SW building...'); - -esbuild.build({ - entryPoints: [ `${__dirname}/src/sw.ts` ], - bundle: true, - format: 'esm', - treeShaking: true, - minify: process.env.NODE_ENV === 'production', - absWorkingDir: __dirname, - outbase: `${__dirname}/src`, - outdir: `${__dirname}/../../built/_sw_dist_`, - loader: { - '.ts': 'ts' - }, - tsconfig: `${__dirname}/tsconfig.json`, - define: { - _VERSION_: JSON.stringify(meta.version), - _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), - _ENV_: JSON.stringify(process.env.NODE_ENV), - _DEV_: process.env.NODE_ENV !== 'production', - _PERF_PREFIX_: JSON.stringify('Calckey:'), - }, - watch: watch ? { - onRebuild(error, result) { - if (error) console.error('SW: watch build failed:', error); - else console.log('SW: watch build succeeded:', result); - }, - } : false, -}).then(result => { - if (watch) console.log('watching...'); - else console.log('done,', JSON.stringify(result)); -}); diff --git a/packages/sw/package.json b/packages/sw/package.json index 3b3f3d350..cf4ec5bff 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -2,16 +2,21 @@ "name": "sw", "private": true, "scripts": { - "watch": "node build.js watch", - "build": "node build.js", - "lint": "eslint --quiet src/**/*.{ts}" + "build": "pnpm swc src -d built -D", + "watch": "pnpm swc src -d built -D -w", + "lint": "pnpm rome check \"src/**/*.ts\"" }, "dependencies": { - "calckey-js": "^0.0.17", - "esbuild": "^0.15.14", + "@swc/cli": "^0.1.59", + "@swc/core": "^1.3.26", + "calckey-js": "^0.0.20", "idb-keyval": "^6.2.0" }, + "optionalDependencies": { + "@swc/core-android-arm64": "1.3.11" + }, "devDependencies": { - "eslint": "^8.30.0" + "swc-loader": "^0.2.3", + "webpack": "^5.75.0" } } diff --git a/packages/sw/src/filters/user.ts b/packages/sw/src/filters/user.ts index 03aa95aac..782194d16 100644 --- a/packages/sw/src/filters/user.ts +++ b/packages/sw/src/filters/user.ts @@ -1,5 +1,5 @@ -import * as misskey from 'calckey-js'; -import * as Acct from 'calckey-js/built/acct'; +import * as misskey from "calckey-js"; +import * as Acct from "calckey-js/built/acct"; export const acct = (user: misskey.Acct) => { return Acct.toString(user); @@ -10,5 +10,5 @@ export const userName = (user: misskey.entities.User) => { }; export const userPage = (user: misskey.Acct, path?, absolute = false) => { - return `${absolute ? origin : ''}/@${acct(user)}${(path ? `/${path}` : '')}`; + return `${absolute ? origin : ""}/@${acct(user)}${path ? `/${path}` : ""}`; }; diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 619a5e6b4..01b9ab588 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -3,31 +3,36 @@ */ declare var self: ServiceWorkerGlobalScope; -import { swLang } from '@/scripts/lang'; -import { cli } from '@/scripts/operations'; -import { pushNotificationDataMap } from '@/types'; -import getUserName from '@/scripts/get-user-name'; -import { I18n } from '@/scripts/i18n'; -import { getAccountFromId } from '@/scripts/get-account-from-id'; -import { char2fileName } from '@/scripts/twemoji-base'; -import * as url from '@/scripts/url'; +import { swLang } from "@/scripts/lang"; +import { cli } from "@/scripts/operations"; +import { pushNotificationDataMap } from "@/types"; +import getUserName from "@/scripts/get-user-name"; +import { I18n } from "@/scripts/i18n"; +import { getAccountFromId } from "@/scripts/get-account-from-id"; +import { char2fileName } from "@/scripts/twemoji-base"; +import * as url from "@/scripts/url"; -const iconUrl = (name: string) => `/static-assets/notification-badges/${name}.png`; +const iconUrl = (name: string) => + `/static-assets/notification-badges/${name}.png`; -export async function createNotification(data: pushNotificationDataMap[K]) { +export async function createNotification< + K extends keyof pushNotificationDataMap, +>(data: pushNotificationDataMap[K]) { const n = await composeNotification(data); if (n) { return self.registration.showNotification(...n); } else { - console.error('Could not compose notification', data); + console.error("Could not compose notification", data); return createEmptyNotification(); } } -async function composeNotification(data: pushNotificationDataMap[K]): Promise<[string, NotificationOptions] | null> { +async function composeNotification( + data: pushNotificationDataMap[K], +): Promise<[string, NotificationOptions] | null> { if (!swLang.i18n) swLang.fetchLocale(); - const i18n = await swLang.i18n as I18n; + const i18n = (await swLang.i18n) as I18n; const { t } = i18n; switch (data.type) { /* @@ -38,110 +43,144 @@ async function composeNotification(data data }]; */ - case 'notification': + case "notification": switch (data.body.type) { - case 'follow': + case "follow": // users/showの型定義をswos.apiへ当てはめるのが困難なのでapiFetch.requestを直接使用 const account = await getAccountFromId(data.userId); if (!account) return null; - const userDetail = await cli.request('users/show', { userId: data.body.userId }, account.token); - return [t('_notification.youWereFollowed'), { - body: getUserName(data.body.user), - icon: data.body.user.avatarUrl, - badge: iconUrl('user-plus'), - data, - actions: userDetail.isFollowing ? [] : [ - { - action: 'follow', - title: t('_notification._actions.followBack') - } - ], - }]; + const userDetail = await cli.request( + "users/show", + { userId: data.body.userId }, + account.token, + ); + return [ + t("_notification.youWereFollowed"), + { + body: getUserName(data.body.user), + icon: data.body.user.avatarUrl, + badge: iconUrl("user-plus"), + data, + actions: userDetail.isFollowing + ? [] + : [ + { + action: "follow", + title: t("_notification._actions.followBack"), + }, + ], + }, + ]; - case 'mention': - return [t('_notification.youGotMention', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge: iconUrl('at'), - data, - actions: [ - { - action: 'reply', - title: t('_notification._actions.reply') - } - ], - }]; + case "mention": + return [ + t("_notification.youGotMention", { + name: getUserName(data.body.user), + }), + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge: iconUrl("at"), + data, + actions: [ + { + action: "reply", + title: t("_notification._actions.reply"), + }, + ], + }, + ]; - case 'reply': - return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge: iconUrl('reply'), - data, - actions: [ - { - action: 'reply', - title: t('_notification._actions.reply') - } - ], - }]; + case "reply": + return [ + t("_notification.youGotReply", { + name: getUserName(data.body.user), + }), + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge: iconUrl("reply"), + data, + actions: [ + { + action: "reply", + title: t("_notification._actions.reply"), + }, + ], + }, + ]; - case 'renote': - return [t('_notification.youRenoted', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge: iconUrl('retweet'), - data, - actions: [ - { - action: 'showUser', - title: getUserName(data.body.user) - } - ], - }]; + case "renote": + return [ + t("_notification.youRenoted", { + name: getUserName(data.body.user), + }), + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge: iconUrl("retweet"), + data, + actions: [ + { + action: "showUser", + title: getUserName(data.body.user), + }, + ], + }, + ]; - case 'quote': - return [t('_notification.youGotQuote', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge: iconUrl('quote-right'), - data, - actions: [ - { - action: 'reply', - title: t('_notification._actions.reply') - }, - ...((data.body.note.visibility === 'public' || data.body.note.visibility === 'home') ? [ - { - action: 'renote', - title: t('_notification._actions.renote') - } - ] : []) - ], - }]; + case "quote": + return [ + t("_notification.youGotQuote", { + name: getUserName(data.body.user), + }), + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge: iconUrl("quote-right"), + data, + actions: [ + { + action: "reply", + title: t("_notification._actions.reply"), + }, + ...(data.body.note.visibility === "public" || + data.body.note.visibility === "home" + ? [ + { + action: "renote", + title: t("_notification._actions.renote"), + }, + ] + : []), + ], + }, + ]; - case 'reaction': + case "reaction": let reaction = data.body.reaction; let badge: string | undefined; - if (reaction.startsWith(':')) { + if (reaction.startsWith(":")) { // カスタム絵文字の場合 - const customEmoji = data.body.note.emojis.find(x => x.name === reaction.substr(1, reaction.length - 2)); + const customEmoji = data.body.note.emojis.find( + (x) => x.name === reaction.substr(1, reaction.length - 2), + ); if (customEmoji) { - if (reaction.includes('@')) { - reaction = `:${reaction.substr(1, reaction.indexOf('@') - 1)}:`; + if (reaction.includes("@")) { + reaction = `:${reaction.substr(1, reaction.indexOf("@") - 1)}:`; } const u = new URL(customEmoji.url); if (u.href.startsWith(`${origin}/proxy/`)) { // もう既にproxyっぽそうだったらsearchParams付けるだけ - u.searchParams.set('badge', '1'); + u.searchParams.set("badge", "1"); badge = u.href; } else { - const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので + const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので badge = `${origin}/proxy/${dummy}?${url.query({ url: u.href, - badge: '1' + badge: "1", })}`; } } @@ -150,138 +189,180 @@ async function composeNotification(data badge = `/twemoji-badge/${char2fileName(reaction)}.png`; } - - if (badge ? await fetch(badge).then(res => res.status !== 200).catch(() => true) : true) { - badge = iconUrl('plus'); + if ( + badge + ? await fetch(badge) + .then((res) => res.status !== 200) + .catch(() => true) + : true + ) { + badge = iconUrl("plus"); } - return [`${reaction} ${getUserName(data.body.user)}`, { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge, - data, - actions: [ - { - action: 'showUser', - title: getUserName(data.body.user) - } - ], - }]; + return [ + `${reaction} ${getUserName(data.body.user)}`, + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge, + data, + actions: [ + { + action: "showUser", + title: getUserName(data.body.user), + }, + ], + }, + ]; - case 'pollVote': - return [t('_notification.youGotPoll', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', - icon: data.body.user.avatarUrl, - badge: iconUrl('poll-h'), - data, - }]; + case "pollVote": + return [ + t("_notification.youGotPoll", { + name: getUserName(data.body.user), + }), + { + body: data.body.note.text || "", + icon: data.body.user.avatarUrl, + badge: iconUrl("poll-h"), + data, + }, + ]; - case 'pollEnded': - return [t('_notification.pollEnded'), { - body: data.body.note.text || '', - badge: iconUrl('clipboard-check-solid'), - data, - }]; + case "pollEnded": + return [ + t("_notification.pollEnded"), + { + body: data.body.note.text || "", + badge: iconUrl("clipboard-check-solid"), + data, + }, + ]; - case 'receiveFollowRequest': - return [t('_notification.youReceivedFollowRequest'), { - body: getUserName(data.body.user), - icon: data.body.user.avatarUrl, - badge: iconUrl('clock'), - data, - actions: [ - { - action: 'accept', - title: t('accept') - }, - { - action: 'reject', - title: t('reject') - } - ], - }]; + case "receiveFollowRequest": + return [ + t("_notification.youReceivedFollowRequest"), + { + body: getUserName(data.body.user), + icon: data.body.user.avatarUrl, + badge: iconUrl("clock"), + data, + actions: [ + { + action: "accept", + title: t("accept"), + }, + { + action: "reject", + title: t("reject"), + }, + ], + }, + ]; - case 'followRequestAccepted': - return [t('_notification.yourFollowRequestAccepted'), { - body: getUserName(data.body.user), - icon: data.body.user.avatarUrl, - badge: iconUrl('check'), - data, - }]; + case "followRequestAccepted": + return [ + t("_notification.yourFollowRequestAccepted"), + { + body: getUserName(data.body.user), + icon: data.body.user.avatarUrl, + badge: iconUrl("check"), + data, + }, + ]; - case 'groupInvited': - return [t('_notification.youWereInvitedToGroup', { userName: getUserName(data.body.user) }), { - body: data.body.invitation.group.name, - badge: iconUrl('id-card-alt'), - data, - actions: [ - { - action: 'accept', - title: t('accept') - }, - { - action: 'reject', - title: t('reject') - } - ], - }]; + case "groupInvited": + return [ + t("_notification.youWereInvitedToGroup", { + userName: getUserName(data.body.user), + }), + { + body: data.body.invitation.group.name, + badge: iconUrl("id-card-alt"), + data, + actions: [ + { + action: "accept", + title: t("accept"), + }, + { + action: "reject", + title: t("reject"), + }, + ], + }, + ]; - case 'app': - return [data.body.header || data.body.body, { + case "app": + return [ + data.body.header || data.body.body, + { body: data.body.header && data.body.body, icon: data.body.icon, - data - }]; + data, + }, + ]; default: return null; } - case 'unreadMessagingMessage': + case "unreadMessagingMessage": if (data.body.groupId === null) { - return [t('_notification.youGotMessagingMessageFromUser', { name: getUserName(data.body.user) }), { + return [ + t("_notification.youGotMessagingMessageFromUser", { + name: getUserName(data.body.user), + }), + { + icon: data.body.user.avatarUrl, + badge: iconUrl("comments"), + tag: `messaging:user:${data.body.userId}`, + data, + renotify: true, + }, + ]; + } + return [ + t("_notification.youGotMessagingMessageFromGroup", { + name: data.body.group.name, + }), + { icon: data.body.user.avatarUrl, - badge: iconUrl('comments'), - tag: `messaging:user:${data.body.userId}`, + badge: iconUrl("comments"), + tag: `messaging:group:${data.body.groupId}`, data, renotify: true, - }]; - } - return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group.name }), { - icon: data.body.user.avatarUrl, - badge: iconUrl('comments'), - tag: `messaging:group:${data.body.groupId}`, - data, - renotify: true, - }]; + }, + ]; default: return null; } } export async function createEmptyNotification() { - return new Promise(async res => { + return new Promise(async (res) => { if (!swLang.i18n) swLang.fetchLocale(); - const i18n = await swLang.i18n as I18n; + const i18n = (await swLang.i18n) as I18n; const { t } = i18n; await self.registration.showNotification( - t('_notification.emptyPushNotificationMessage'), + t("_notification.emptyPushNotificationMessage"), { silent: true, - badge: iconUrl('null'), - tag: 'read_notification', - } + badge: iconUrl("null"), + tag: "read_notification", + }, ); res(); setTimeout(async () => { - for (const n of - [ - ...(await self.registration.getNotifications({ tag: 'user_visible_auto_notification' })), - ...(await self.registration.getNotifications({ tag: 'read_notification' })) - ] - ) { + for (const n of [ + ...(await self.registration.getNotifications({ + tag: "user_visible_auto_notification", + })), + ...(await self.registration.getNotifications({ + tag: "read_notification", + })), + ]) { n.close(); } }, 1000); diff --git a/packages/sw/src/scripts/get-account-from-id.ts b/packages/sw/src/scripts/get-account-from-id.ts index be4cfaeba..24f5e590e 100644 --- a/packages/sw/src/scripts/get-account-from-id.ts +++ b/packages/sw/src/scripts/get-account-from-id.ts @@ -1,7 +1,7 @@ -import { get } from 'idb-keyval'; +import { get } from "idb-keyval"; export async function getAccountFromId(id: string) { - const accounts = await get('accounts') as { token: string; id: string; }[]; - if (!accounts) console.log('Accounts are not recorded'); - return accounts.find(e => e.id === id); + const accounts = (await get("accounts")) as { token: string; id: string }[]; + if (!accounts) console.log("Accounts are not recorded"); + return accounts.find((e) => e.id === id); } diff --git a/packages/sw/src/scripts/get-user-name.ts b/packages/sw/src/scripts/get-user-name.ts index d499ea020..0f8916de8 100644 --- a/packages/sw/src/scripts/get-user-name.ts +++ b/packages/sw/src/scripts/get-user-name.ts @@ -1,3 +1,6 @@ -export default function(user: { name?: string | null, username: string }): string { +export default function (user: { + name?: string | null; + username: string; +}): string { return user.name || user.username; } diff --git a/packages/sw/src/scripts/i18n.ts b/packages/sw/src/scripts/i18n.ts index 3fe88e551..06fe83f31 100644 --- a/packages/sw/src/scripts/i18n.ts +++ b/packages/sw/src/scripts/i18n.ts @@ -13,7 +13,9 @@ export class I18n> { // なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも public t(key: string, args?: Record): string { try { - let str = key.split('.').reduce((o, i) => o[i], this.ts) as unknown as string; + let str = key + .split(".") + .reduce((o, i) => o[i], this.ts) as unknown as string; if (args) { for (const [k, v] of Object.entries(args)) { diff --git a/packages/sw/src/scripts/lang.ts b/packages/sw/src/scripts/lang.ts index 2d05404ef..da4f31526 100644 --- a/packages/sw/src/scripts/lang.ts +++ b/packages/sw/src/scripts/lang.ts @@ -3,27 +3,27 @@ */ declare var self: ServiceWorkerGlobalScope; -import { get, set } from 'idb-keyval'; -import { I18n } from '@/scripts/i18n'; +import { get, set } from "idb-keyval"; +import { I18n } from "@/scripts/i18n"; class SwLang { public cacheName = `mk-cache-${_VERSION_}`; - public lang: Promise = get('lang').then(async prelang => { - if (!prelang) return 'en-US'; + public lang: Promise = get("lang").then(async (prelang) => { + if (!prelang) return "en-US"; return prelang; }); public setLang(newLang: string) { this.lang = Promise.resolve(newLang); - set('lang', newLang); + set("lang", newLang); return this.fetchLocale(); } public i18n: Promise> | null = null; public fetchLocale() { - return this.i18n = this._fetch(); + return (this.i18n = this._fetch()); } private async _fetch() { @@ -35,9 +35,9 @@ class SwLang { if (!localeRes || _DEV_) { localeRes = await fetch(localeUrl); const clone = localeRes?.clone(); - if (!clone?.clone().ok) Error('locale fetching error'); + if (!clone?.clone().ok) Error("locale fetching error"); - caches.open(this.cacheName).then(cache => cache.put(localeUrl, clone)); + caches.open(this.cacheName).then((cache) => cache.put(localeUrl, clone)); } return new I18n(await localeRes.json()); diff --git a/packages/sw/src/scripts/login-id.ts b/packages/sw/src/scripts/login-id.ts index 0f9c6be4a..0fe345780 100644 --- a/packages/sw/src/scripts/login-id.ts +++ b/packages/sw/src/scripts/login-id.ts @@ -1,11 +1,11 @@ export function getUrlWithLoginId(url: string, loginId: string) { const u = new URL(url, origin); - u.searchParams.append('loginId', loginId); + u.searchParams.append("loginId", loginId); return u.toString(); } export function getUrlWithoutLoginId(url: string) { const u = new URL(url); - u.searchParams.delete('loginId'); + u.searchParams.delete("loginId"); return u.toString(); } diff --git a/packages/sw/src/scripts/notification-read.ts b/packages/sw/src/scripts/notification-read.ts index 5c1de8908..5b2030d98 100644 --- a/packages/sw/src/scripts/notification-read.ts +++ b/packages/sw/src/scripts/notification-read.ts @@ -1,27 +1,27 @@ declare var self: ServiceWorkerGlobalScope; -import { get } from 'idb-keyval'; -import { pushNotificationDataMap } from '@/types'; -import { api } from '@/scripts/operations'; +import { get } from "idb-keyval"; +import { pushNotificationDataMap } from "@/types"; +import { api } from "@/scripts/operations"; type Accounts = { [x: string]: { - queue: string[], - timeout: number | null - } + queue: string[]; + timeout: number | null; + }; }; class SwNotificationReadManager { private accounts: Accounts = {}; public async construct() { - const accounts = await get('accounts'); - if (!accounts) Error('Accounts are not recorded'); + const accounts = await get("accounts"); + if (!accounts) Error("Accounts are not recorded"); this.accounts = accounts.reduce((acc, e) => { acc[e.id] = { queue: [], - timeout: null + timeout: null, }; return acc; }, {} as Accounts); @@ -30,8 +30,10 @@ class SwNotificationReadManager { } // プッシュ通知の既読をサーバーに送信 - public async read(data: pushNotificationDataMap[K]) { - if (data.type !== 'notification' || !(data.userId in this.accounts)) return; + public async read( + data: pushNotificationDataMap[K], + ) { + if (data.type !== "notification" || !(data.userId in this.accounts)) return; const account = this.accounts[data.userId]; @@ -41,7 +43,7 @@ class SwNotificationReadManager { if (account.timeout) clearTimeout(account.timeout); const notificationIds = account.queue; account.queue = []; - await api('notifications/read', data.userId, { notificationIds }); + await api("notifications/read", data.userId, { notificationIds }); return; } @@ -52,9 +54,9 @@ class SwNotificationReadManager { const notificationIds = account.queue; account.queue = []; - api('notifications/read', data.userId, { notificationIds }); + api("notifications/read", data.userId, { notificationIds }); }, 200); } } -export const swNotificationRead = (new SwNotificationReadManager()).construct(); +export const swNotificationRead = new SwNotificationReadManager().construct(); diff --git a/packages/sw/src/scripts/operations.ts b/packages/sw/src/scripts/operations.ts index 7a1d66bd1..a192a9bd7 100644 --- a/packages/sw/src/scripts/operations.ts +++ b/packages/sw/src/scripts/operations.ts @@ -4,15 +4,22 @@ */ declare var self: ServiceWorkerGlobalScope; -import * as Misskey from 'calckey-js'; -import { SwMessage, swMessageOrderType } from '@/types'; -import { acct as getAcct } from '@/filters/user'; -import { getAccountFromId } from '@/scripts/get-account-from-id'; -import { getUrlWithLoginId } from '@/scripts/login-id'; +import * as Misskey from "calckey-js"; +import { SwMessage, swMessageOrderType } from "@/types"; +import { acct as getAcct } from "@/filters/user"; +import { getAccountFromId } from "@/scripts/get-account-from-id"; +import { getUrlWithLoginId } from "@/scripts/login-id"; -export const cli = new Misskey.api.APIClient({ origin, fetch: (...args) => fetch(...args) }); +export const cli = new Misskey.api.APIClient({ + origin, + fetch: (...args) => fetch(...args), +}); -export async function api(endpoint: E, userId: string, options?: Misskey.Endpoints[E]['req']) { +export async function api( + endpoint: E, + userId: string, + options?: Misskey.Endpoints[E]["req"], +) { const account = await getAccountFromId(userId); if (!account) return; @@ -21,38 +28,53 @@ export async function api(endpoint: E, userId // rendered acctからユーザーを開く export function openUser(acct: string, loginId: string) { - return openClient('push', `/@${acct}`, loginId, { acct }); + return openClient("push", `/@${acct}`, loginId, { acct }); } // noteIdからノートを開く export function openNote(noteId: string, loginId: string) { - return openClient('push', `/notes/${noteId}`, loginId, { noteId }); + return openClient("push", `/notes/${noteId}`, loginId, { noteId }); } export async function openChat(body: any, loginId: string) { if (body.groupId === null) { - return openClient('push', `/my/messaging/${getAcct(body.user)}`, loginId, { body }); + return openClient("push", `/my/messaging/${getAcct(body.user)}`, loginId, { + body, + }); } else { - return openClient('push', `/my/messaging/group/${body.groupId}`, loginId, { body }); + return openClient("push", `/my/messaging/group/${body.groupId}`, loginId, { + body, + }); } } // post-formのオプションから投稿フォームを開く export async function openPost(options: any, loginId: string) { // クエリを作成しておく - let url = `/share?`; + let url = "/share?"; if (options.initialText) url += `text=${options.initialText}&`; if (options.reply) url += `replyId=${options.reply.id}&`; if (options.renote) url += `renoteId=${options.renote.id}&`; - return openClient('post', url, loginId, { options }); + return openClient("post", url, loginId, { options }); } -export async function openClient(order: swMessageOrderType, url: string, loginId: string, query: any = {}) { +export async function openClient( + order: swMessageOrderType, + url: string, + loginId: string, + query: any = {}, +) { const client = await findClient(); if (client) { - client.postMessage({ type: 'order', ...query, order, loginId, url } as SwMessage); + client.postMessage({ + type: "order", + ...query, + order, + loginId, + url, + } as SwMessage); return client; } @@ -61,10 +83,10 @@ export async function openClient(order: swMessageOrderType, url: string, loginId export async function findClient() { const clients = await self.clients.matchAll({ - type: 'window' + type: "window", }); for (const c of clients) { - if (c.url.indexOf('?zen') < 0) return c; + if (c.url.indexOf("?zen") < 0) return c; } return null; } diff --git a/packages/sw/src/scripts/twemoji-base.ts b/packages/sw/src/scripts/twemoji-base.ts index 638aae328..0e45a527e 100644 --- a/packages/sw/src/scripts/twemoji-base.ts +++ b/packages/sw/src/scripts/twemoji-base.ts @@ -1,10 +1,10 @@ -export const twemojiSvgBase = '/twemoji'; +export const twemojiSvgBase = "/twemoji"; export function char2fileName(char: string): string { - let codes = Array.from(char).map(x => x.codePointAt(0)?.toString(16)); - if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f'); - codes = codes.filter(x => x && x.length); - return codes.join('-'); + let codes = Array.from(char).map((x) => x.codePointAt(0)?.toString(16)); + if (!codes.includes("200d")) codes = codes.filter((x) => x !== "fe0f"); + codes = codes.filter((x) => x?.length); + return codes.join("-"); } export function char2filePath(char: string): string { diff --git a/packages/sw/src/scripts/url.ts b/packages/sw/src/scripts/url.ts index c7f2b7c1e..a11f5e28b 100644 --- a/packages/sw/src/scripts/url.ts +++ b/packages/sw/src/scripts/url.ts @@ -1,13 +1,15 @@ export function query(obj: {}): string { const params = Object.entries(obj) - .filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined) - .reduce((a, [k, v]) => (a[k] = v, a), {} as Record); + .filter(([, v]) => (Array.isArray(v) ? v.length : v !== undefined)) + .reduce((a, [k, v]) => ((a[k] = v), a), {} as Record); return Object.entries(params) .map((e) => `${e[0]}=${encodeURIComponent(e[1])}`) - .join('&'); + .join("&"); } export function appendQuery(url: string, query: string): string { - return `${url}${/\?/.test(url) ? url.endsWith('?') ? '' : '&' : '?'}${query}`; + return `${url}${ + /\?/.test(url) ? (url.endsWith("?") ? "" : "&") : "?" + }${query}`; } diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index 019ceece1..0733400fc 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -1,214 +1,276 @@ declare var self: ServiceWorkerGlobalScope; -import { createEmptyNotification, createNotification } from '@/scripts/create-notification'; -import { swLang } from '@/scripts/lang'; -import { swNotificationRead } from '@/scripts/notification-read'; -import { pushNotificationDataMap } from '@/types'; -import * as swos from '@/scripts/operations'; -import { acct as getAcct } from '@/filters/user'; +import { + createEmptyNotification, + createNotification, +} from "@/scripts/create-notification"; +import { swLang } from "@/scripts/lang"; +import { swNotificationRead } from "@/scripts/notification-read"; +import { pushNotificationDataMap } from "@/types"; +import * as swos from "@/scripts/operations"; +import { acct as getAcct } from "@/filters/user"; -self.addEventListener('install', ev => { +self.addEventListener("install", (ev) => { ev.waitUntil(self.skipWaiting()); }); -self.addEventListener('activate', ev => { +self.addEventListener("activate", (ev) => { ev.waitUntil( - caches.keys() - .then(cacheNames => Promise.all( - cacheNames - .filter((v) => v !== swLang.cacheName) - .map(name => caches.delete(name)) - )) - .then(() => self.clients.claim()) + caches + .keys() + .then((cacheNames) => + Promise.all( + cacheNames + .filter((v) => v !== swLang.cacheName) + .map((name) => caches.delete(name)), + ), + ) + .then(() => self.clients.claim()), ); }); -self.addEventListener('fetch', ev => { +self.addEventListener("fetch", (ev) => { let isHTMLRequest = false; - if (ev.request.headers.get('sec-fetch-dest') === 'document') { + if (ev.request.headers.get("sec-fetch-dest") === "document") { isHTMLRequest = true; - } else if (ev.request.headers.get('accept')?.includes('/html')) { + } else if (ev.request.headers.get("accept")?.includes("/html")) { isHTMLRequest = true; - } else if (ev.request.url.endsWith('/')) { + } else if (ev.request.url.endsWith("/")) { isHTMLRequest = true; } if (!isHTMLRequest) return; ev.respondWith( - fetch(ev.request) - .catch(() => new Response(`Offline. Service Worker @${_VERSION_}`, { status: 200 })) + fetch(ev.request).catch( + () => + new Response(`Offline. Service Worker @${_VERSION_}`, { status: 200 }), + ), ); }); -self.addEventListener('push', ev => { +self.addEventListener("push", (ev) => { // クライアント取得 - ev.waitUntil(self.clients.matchAll({ - includeUncontrolled: true, - type: 'window' - }).then(async (clients: readonly WindowClient[]) => { - const data: pushNotificationDataMap[K] = ev.data?.json(); + ev.waitUntil( + self.clients + .matchAll({ + includeUncontrolled: true, + type: "window", + }) + .then( + async ( + clients: readonly WindowClient[], + ) => { + const data: pushNotificationDataMap[K] = ev.data?.json(); - switch (data.type) { - // case 'driveFileCreated': - case 'notification': - case 'unreadMessagingMessage': - // 1日以上経過している場合は無視 - if ((new Date()).getTime() - data.dateTime > 1000 * 60 * 60 * 24) break; + switch (data.type) { + // case 'driveFileCreated': + case "notification": + case "unreadMessagingMessage": + // 1日以上経過している場合は無視 + if (new Date().getTime() - data.dateTime > 1000 * 60 * 60 * 24) + break; - // クライアントがあったらストリームに接続しているということなので通知しない - if (clients.length !== 0) break; + // クライアントがあったらストリームに接続しているということなので通知しない + if (clients.length !== 0) break; - return createNotification(data); - case 'readAllNotifications': - for (const n of await self.registration.getNotifications()) { - if (n?.data?.type === 'notification') n.close(); - } - break; - case 'readAllMessagingMessages': - for (const n of await self.registration.getNotifications()) { - if (n?.data?.type === 'unreadMessagingMessage') n.close(); - } - break; - case 'readNotifications': - for (const n of await self.registration.getNotifications()) { - if (data.body?.notificationIds?.includes(n.data.body.id)) { - n.close(); + return createNotification(data); + case "readAllNotifications": + for (const n of await self.registration.getNotifications()) { + if (n?.data?.type === "notification") n.close(); + } + break; + case "readAllMessagingMessages": + for (const n of await self.registration.getNotifications()) { + if (n?.data?.type === "unreadMessagingMessage") n.close(); + } + break; + case "readNotifications": + for (const n of await self.registration.getNotifications()) { + if (data.body?.notificationIds?.includes(n.data.body.id)) { + n.close(); + } + } + break; + case "readAllMessagingMessagesOfARoom": + for (const n of await self.registration.getNotifications()) { + if ( + n.data.type === "unreadMessagingMessage" && + ("userId" in data.body + ? data.body.userId === n.data.body.userId + : data.body.groupId === n.data.body.groupId) + ) { + n.close(); + } + } + break; } - } - break; - case 'readAllMessagingMessagesOfARoom': - for (const n of await self.registration.getNotifications()) { - if (n.data.type === 'unreadMessagingMessage' - && ('userId' in data.body - ? data.body.userId === n.data.body.userId - : data.body.groupId === n.data.body.groupId) - ) { - n.close(); - } - } - break; - } - return createEmptyNotification(); - })); + return createEmptyNotification(); + }, + ), + ); }); -self.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => { - ev.waitUntil((async () => { - if (_DEV_) { - console.log('notificationclick', ev.action, ev.notification.data); - } +self.addEventListener( + "notificationclick", + ( + ev: ServiceWorkerGlobalScopeEventMap["notificationclick"], + ) => { + ev.waitUntil( + (async () => { + if (_DEV_) { + console.log("notificationclick", ev.action, ev.notification.data); + } - const { action, notification } = ev; - const data: pushNotificationDataMap[K] = notification.data; - const { userId: id } = data; - let client: WindowClient | null = null; + const { action, notification } = ev; + const data: pushNotificationDataMap[K] = notification.data; + const { userId: id } = data; + let client: WindowClient | null = null; - switch (data.type) { - case 'notification': - switch (action) { - case 'follow': - if ('userId' in data.body) await swos.api('following/create', id, { userId: data.body.userId }); - break; - case 'showUser': - if ('user' in data.body) client = await swos.openUser(getAcct(data.body.user), id); - break; - case 'reply': - if ('note' in data.body) client = await swos.openPost({ reply: data.body.note }, id); - break; - case 'renote': - if ('note' in data.body) await swos.api('notes/create', id, { renoteId: data.body.note.id }); - break; - case 'accept': - switch (data.body.type) { - case 'receiveFollowRequest': - await swos.api('following/requests/accept', id, { userId: data.body.userId }); + switch (data.type) { + case "notification": + switch (action) { + case "follow": + if ("userId" in data.body) + await swos.api("following/create", id, { + userId: data.body.userId, + }); break; - case 'groupInvited': - await swos.api('users/groups/invitations/accept', id, { invitationId: data.body.invitation.id }); - break; - } - break; - case 'reject': - switch (data.body.type) { - case 'receiveFollowRequest': - await swos.api('following/requests/reject', id, { userId: data.body.userId }); - break; - case 'groupInvited': - await swos.api('users/groups/invitations/reject', id, { invitationId: data.body.invitation.id }); - break; - } - break; - case 'showFollowRequests': - client = await swos.openClient('push', '/my/follow-requests', id); - break; - default: - switch (data.body.type) { - case 'receiveFollowRequest': - client = await swos.openClient('push', '/my/follow-requests', id); - break; - case 'groupInvited': - client = await swos.openClient('push', '/my/groups', id); - break; - case 'reaction': - client = await swos.openNote(data.body.note.id, id); - break; - default: - if ('note' in data.body) { - client = await swos.openNote(data.body.note.id, id); - } else if ('user' in data.body) { + case "showUser": + if ("user" in data.body) client = await swos.openUser(getAcct(data.body.user), id); + break; + case "reply": + if ("note" in data.body) + client = await swos.openPost({ reply: data.body.note }, id); + break; + case "renote": + if ("note" in data.body) + await swos.api("notes/create", id, { + renoteId: data.body.note.id, + }); + break; + case "accept": + switch (data.body.type) { + case "receiveFollowRequest": + await swos.api("following/requests/accept", id, { + userId: data.body.userId, + }); + break; + case "groupInvited": + await swos.api("users/groups/invitations/accept", id, { + invitationId: data.body.invitation.id, + }); + break; } break; + case "reject": + switch (data.body.type) { + case "receiveFollowRequest": + await swos.api("following/requests/reject", id, { + userId: data.body.userId, + }); + break; + case "groupInvited": + await swos.api("users/groups/invitations/reject", id, { + invitationId: data.body.invitation.id, + }); + break; + } + break; + case "showFollowRequests": + client = await swos.openClient( + "push", + "/my/follow-requests", + id, + ); + break; + default: + switch (data.body.type) { + case "receiveFollowRequest": + client = await swos.openClient( + "push", + "/my/follow-requests", + id, + ); + break; + case "groupInvited": + client = await swos.openClient("push", "/my/groups", id); + break; + case "reaction": + client = await swos.openNote(data.body.note.id, id); + break; + default: + if ("note" in data.body) { + client = await swos.openNote(data.body.note.id, id); + } else if ("user" in data.body) { + client = await swos.openUser(getAcct(data.body.user), id); + } + break; + } } + break; + case "unreadMessagingMessage": + client = await swos.openChat(data.body, id); + break; } - break; - case 'unreadMessagingMessage': - client = await swos.openChat(data.body, id); - break; - } - if (client) { - client.focus(); - } - if (data.type === 'notification') { - swNotificationRead.then(that => that.read(data)); - } - - notification.close(); - - })()); -}); - -self.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => { - const data: pushNotificationDataMap[K] = ev.notification.data; - - if (data.type === 'notification') { - swNotificationRead.then(that => that.read(data)); - } -}); - -self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => { - ev.waitUntil((async () => { - switch (ev.data) { - case 'clear': - // Cache Storage全削除 - await caches.keys() - .then(cacheNames => Promise.all( - cacheNames.map(name => caches.delete(name)) - )); - return; // TODO - } - - if (typeof ev.data === 'object') { - // E.g. '[object Array]' → 'array' - const otype = Object.prototype.toString.call(ev.data).slice(8, -1).toLowerCase(); - - if (otype === 'object') { - if (ev.data.msg === 'initialize') { - swLang.setLang(ev.data.lang); + if (client) { + client.focus(); } - } + if (data.type === "notification") { + swNotificationRead.then((that) => that.read(data)); + } + + notification.close(); + })(), + ); + }, +); + +self.addEventListener( + "notificationclose", + ( + ev: ServiceWorkerGlobalScopeEventMap["notificationclose"], + ) => { + const data: pushNotificationDataMap[K] = ev.notification.data; + + if (data.type === "notification") { + swNotificationRead.then((that) => that.read(data)); } - })()); -}); + }, +); + +self.addEventListener( + "message", + (ev: ServiceWorkerGlobalScopeEventMap["message"]) => { + ev.waitUntil( + (async () => { + switch (ev.data) { + case "clear": + // Cache Storage全削除 + await caches + .keys() + .then((cacheNames) => + Promise.all(cacheNames.map((name) => caches.delete(name))), + ); + return; // TODO + } + + if (typeof ev.data === "object") { + // E.g. '[object Array]' → 'array' + const otype = Object.prototype.toString + .call(ev.data) + .slice(8, -1) + .toLowerCase(); + + if (otype === "object") { + if (ev.data.msg === "initialize") { + swLang.setLang(ev.data.lang); + } + } + } + })(), + ); + }, +); diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts index bc6fc2ec0..984076dbe 100644 --- a/packages/sw/src/types.ts +++ b/packages/sw/src/types.ts @@ -1,9 +1,9 @@ -import * as Misskey from 'calckey-js'; +import * as Misskey from "calckey-js"; -export type swMessageOrderType = 'post' | 'push'; +export type swMessageOrderType = "post" | "push"; export type SwMessage = { - type: 'order'; + type: "order"; order: swMessageOrderType; loginId: string; url: string; @@ -20,7 +20,9 @@ type pushNotificationDataSourceMap = { readAllMessagingMessagesOfARoom: { userId: string } | { groupId: string }; }; -export type pushNotificationData = { +export type pushNotificationData< + K extends keyof pushNotificationDataSourceMap, +> = { type: K; body: pushNotificationDataSourceMap[K]; userId: string; diff --git a/packages/sw/tsconfig.json b/packages/sw/tsconfig.json index c3a845f12..fad2ae567 100644 --- a/packages/sw/tsconfig.json +++ b/packages/sw/tsconfig.json @@ -34,6 +34,6 @@ }, "compileOnSave": false, "include": [ - "./**/*.ts" + "./**/*.ts", "./**/*.d.ts", "./**/*.tsx", "./**/*.vue" ] } diff --git a/patrons.json b/patrons.json index 4c7d960ef..ee849a5bd 100644 --- a/patrons.json +++ b/patrons.json @@ -10,6 +10,10 @@ "@griff@stop.voring.me", "@cafkafk@ck.cafkafk.com", "@privateger@plasmatrap.com", - "@self@neo.voidworks.cc" + "@self@neo.voidworks.cc", + "@effy@social.effy.space", + "@Kio@kitsunes.club", + "@twann@tech.lgbt", + "$[sparkle Interkosmos Link]" ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 000000000..34a4ffc06 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,13179 @@ +lockfileVersion: 5.4 + +overrides: + chokidar: ^3.3.1 + lodash: ^4.17.21 + +importers: + + .: + specifiers: + '@bull-board/api': ^4.10.2 + '@bull-board/ui': ^4.10.2 + '@tensorflow/tfjs': ^3.21.0 + '@types/gulp': 4.0.10 + '@types/gulp-rename': 2.0.1 + calckey-js: ^0.0.20 + cross-env: 7.0.3 + cypress: 10.11.0 + execa: 5.1.1 + gulp: 4.0.2 + gulp-cssnano: 2.1.3 + gulp-rename: 2.0.0 + gulp-replace: 1.1.4 + gulp-terser: 2.1.0 + install-peers: ^1.0.4 + js-yaml: 4.1.0 + long: ^5.2.1 + phosphor-icons: ^1.4.2 + rome: ^11.0.0 + seedrandom: ^3.0.5 + start-server-and-test: 1.15.2 + typescript: 4.9.4 + dependencies: + '@bull-board/api': 4.10.2 + '@bull-board/ui': 4.10.2 + '@tensorflow/tfjs': 3.21.0_seedrandom@3.0.5 + calckey-js: 0.0.20 + execa: 5.1.1 + gulp: 4.0.2 + gulp-cssnano: 2.1.3 + gulp-rename: 2.0.0 + gulp-replace: 1.1.4 + gulp-terser: 2.1.0 + js-yaml: 4.1.0 + long: 5.2.1 + phosphor-icons: 1.4.2 + seedrandom: 3.0.5 + devDependencies: + '@types/gulp': 4.0.10 + '@types/gulp-rename': 2.0.1 + cross-env: 7.0.3 + cypress: 10.11.0 + install-peers: 1.0.4 + rome: 11.0.0 + start-server-and-test: 1.15.2 + typescript: 4.9.4 + + packages/backend: + specifiers: + '@bull-board/api': ^4.6.4 + '@bull-board/koa': ^4.6.4 + '@bull-board/ui': ^4.6.4 + '@discordapp/twemoji': 14.0.2 + '@elastic/elasticsearch': 7.17.0 + '@koa/cors': 3.4.3 + '@koa/multer': 3.0.0 + '@koa/router': 9.0.1 + '@peertube/http-signature': 1.7.0 + '@redocly/openapi-core': 1.0.0-beta.120 + '@sinonjs/fake-timers': 9.1.2 + '@swc/cli': ^0.1.59 + '@swc/core': ^1.3.26 + '@swc/core-android-arm64': 1.3.11 + '@syuilo/aiscript': 0.11.1 + '@tensorflow/tfjs': ^4.2.0 + '@tensorflow/tfjs-node': 3.21.1 + '@types/bcryptjs': 2.4.2 + '@types/bull': 3.15.9 + '@types/cbor': 6.0.0 + '@types/escape-regexp': 0.0.1 + '@types/fluent-ffmpeg': 2.1.20 + '@types/js-yaml': 4.0.5 + '@types/jsdom': 20.0.1 + '@types/jsonld': 1.5.8 + '@types/jsrsasign': 10.5.4 + '@types/koa': 2.13.5 + '@types/koa-bodyparser': 4.3.10 + '@types/koa-cors': 0.0.2 + '@types/koa-favicon': 2.0.21 + '@types/koa-logger': 3.1.2 + '@types/koa-mount': 4.0.2 + '@types/koa-send': 4.1.3 + '@types/koa-views': 7.0.0 + '@types/koa__cors': 3.3.0 + '@types/koa__multer': 2.0.4 + '@types/koa__router': 8.0.11 + '@types/mocha': 9.1.1 + '@types/node': 18.11.18 + '@types/node-fetch': 3.0.3 + '@types/nodemailer': 6.4.7 + '@types/oauth': 0.9.1 + '@types/pug': 2.0.6 + '@types/punycode': 2.1.0 + '@types/qrcode': 1.5.0 + '@types/random-seed': 0.3.3 + '@types/ratelimiter': 3.4.4 + '@types/redis': 4.0.11 + '@types/rename': 1.0.4 + '@types/sanitize-html': 2.8.0 + '@types/semver': 7.3.13 + '@types/sharp': 0.31.1 + '@types/sinonjs__fake-timers': 8.1.2 + '@types/speakeasy': 2.0.7 + '@types/tinycolor2': 1.4.3 + '@types/tmp': 0.2.3 + '@types/uuid': 8.3.4 + '@types/web-push': 3.3.2 + '@types/websocket': 1.0.5 + '@types/ws': 8.5.3 + ajv: 8.11.2 + archiver: 5.3.1 + autobind-decorator: 2.4.0 + autwh: 0.1.0 + aws-sdk: 2.1277.0 + bcryptjs: 2.4.3 + blurhash: 1.1.5 + bull: 4.10.2 + cacheable-lookup: 7.0.0 + calckey-js: ^0.0.20 + cbor: 8.1.0 + chalk: 5.2.0 + chalk-template: 0.4.0 + chokidar: ^3.3.1 + cli-highlight: 2.1.11 + color-convert: 2.0.1 + content-disposition: 0.5.4 + cross-env: 7.0.3 + date-fns: 2.29.3 + deep-email-validator: 0.1.21 + escape-regexp: 0.0.1 + eslint: ^8.31.0 + execa: 6.1.0 + feed: 4.2.2 + file-type: 17.1.6 + fluent-ffmpeg: 2.1.2 + got: 12.5.3 + hpagent: 0.1.2 + ioredis: 5.2.4 + ip-cidr: 3.0.11 + is-svg: 4.3.2 + js-yaml: 4.1.0 + jsdom: 20.0.3 + json5: 2.2.3 + json5-loader: 4.0.1 + jsonld: 6.0.0 + jsrsasign: 10.6.1 + koa: 2.13.4 + koa-bodyparser: 4.3.0 + koa-favicon: 2.1.0 + koa-json-body: 5.3.0 + koa-logger: 3.2.1 + koa-mount: 4.0.0 + koa-send: 5.0.1 + koa-slow: 2.1.0 + koa-views: 7.0.2 + mfm-js: 0.23.2 + mime-types: 2.1.35 + mocha: 10.2.0 + multer: 1.4.4-lts.1 + nested-property: 4.0.0 + node-fetch: 3.3.0 + nodemailer: 6.8.0 + nsfwjs: 2.4.2 + oauth: ^0.10.0 + os-utils: 0.0.14 + parse5: 7.1.2 + pg: 8.8.0 + private-ip: 2.3.4 + probe-image-size: 7.2.3 + promise-limit: 2.7.0 + pug: 3.0.2 + punycode: 2.1.1 + pureimage: 0.3.15 + qrcode: 1.5.1 + random-seed: 0.3.0 + ratelimiter: 3.4.1 + re2: 1.18.0 + redis-lock: 0.1.4 + reflect-metadata: 0.1.13 + rename: 1.0.4 + rndstr: 1.0.0 + rss-parser: 3.12.0 + s-age: 1.1.2 + sanitize-html: 2.8.1 + seedrandom: ^3.0.5 + semver: 7.3.8 + sharp: 0.31.3 + speakeasy: 2.0.0 + strict-event-emitter-types: 2.0.0 + stringz: 2.1.0 + summaly: 2.7.0 + swc-loader: ^0.2.3 + syslog-pro: 1.0.0 + systeminformation: 5.16.9 + tesseract.js: ^3.0.3 + tinycolor2: 1.5.2 + tmp: 0.2.1 + ts-loader: 9.4.2 + ts-node: 10.9.1 + tsconfig-paths: 4.1.2 + twemoji-parser: 14.0.0 + typeorm: 0.3.11 + typescript: 4.9.4 + ulid: 2.3.0 + unzipper: 0.10.11 + uuid: 9.0.0 + web-push: 3.5.0 + webpack: ^5.75.0 + websocket: 1.0.34 + ws: 8.11.0 + xev: 3.0.2 + dependencies: + '@bull-board/api': 4.10.2 + '@bull-board/koa': 4.10.2_6tybghmia4wsnt33xeid7y4rby + '@bull-board/ui': 4.10.2 + '@discordapp/twemoji': 14.0.2 + '@elastic/elasticsearch': 7.17.0 + '@koa/cors': 3.4.3 + '@koa/multer': 3.0.0_multer@1.4.4-lts.1 + '@koa/router': 9.0.1 + '@peertube/http-signature': 1.7.0 + '@redocly/openapi-core': 1.0.0-beta.120 + '@sinonjs/fake-timers': 9.1.2 + '@swc/cli': 0.1.59_cr4os3zuq4gmhe2qzzjtw2pxeu + '@swc/core': 1.3.26 + '@syuilo/aiscript': 0.11.1 + '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5 + ajv: 8.11.2 + archiver: 5.3.1 + autobind-decorator: 2.4.0 + autwh: 0.1.0 + aws-sdk: 2.1277.0 + bcryptjs: 2.4.3 + blurhash: 1.1.5 + bull: 4.10.2 + cacheable-lookup: 7.0.0 + calckey-js: 0.0.20 + cbor: 8.1.0 + chalk: 5.2.0 + chalk-template: 0.4.0 + chokidar: 3.5.3 + cli-highlight: 2.1.11 + color-convert: 2.0.1 + content-disposition: 0.5.4 + date-fns: 2.29.3 + deep-email-validator: 0.1.21 + escape-regexp: 0.0.1 + feed: 4.2.2 + file-type: 17.1.6 + fluent-ffmpeg: 2.1.2 + got: 12.5.3 + hpagent: 0.1.2 + ioredis: 5.2.4 + ip-cidr: 3.0.11 + is-svg: 4.3.2 + js-yaml: 4.1.0 + jsdom: 20.0.3 + json5: 2.2.3 + json5-loader: 4.0.1_webpack@5.75.0 + jsonld: 6.0.0 + jsrsasign: 10.6.1 + koa: 2.13.4 + koa-bodyparser: 4.3.0 + koa-favicon: 2.1.0 + koa-json-body: 5.3.0 + koa-logger: 3.2.1 + koa-mount: 4.0.0 + koa-send: 5.0.1 + koa-slow: 2.1.0 + koa-views: 7.0.2_6tybghmia4wsnt33xeid7y4rby + mfm-js: 0.23.2 + mime-types: 2.1.35 + mocha: 10.2.0 + multer: 1.4.4-lts.1 + nested-property: 4.0.0 + node-fetch: 3.3.0 + nodemailer: 6.8.0 + nsfwjs: 2.4.2_@tensorflow+tfjs@4.2.0 + oauth: 0.10.0 + os-utils: 0.0.14 + parse5: 7.1.2 + pg: 8.8.0 + private-ip: 2.3.4 + probe-image-size: 7.2.3 + promise-limit: 2.7.0 + pug: 3.0.2 + punycode: 2.1.1 + pureimage: 0.3.15 + qrcode: 1.5.1 + random-seed: 0.3.0 + ratelimiter: 3.4.1 + re2: 1.18.0 + redis-lock: 0.1.4 + reflect-metadata: 0.1.13 + rename: 1.0.4 + rndstr: 1.0.0 + rss-parser: 3.12.0 + s-age: 1.1.2 + sanitize-html: 2.8.1 + seedrandom: 3.0.5 + semver: 7.3.8 + sharp: 0.31.3 + speakeasy: 2.0.0 + strict-event-emitter-types: 2.0.0 + stringz: 2.1.0 + summaly: 2.7.0 + syslog-pro: 1.0.0 + systeminformation: 5.16.9 + tesseract.js: 3.0.3_eslint@8.31.0 + tinycolor2: 1.5.2 + tmp: 0.2.1 + ts-loader: 9.4.2_3fkjkrd3audxnith3e7fo4fnxi + ts-node: 10.9.1_fodzh64fuekdilycyvke2qmf2e + tsconfig-paths: 4.1.2 + twemoji-parser: 14.0.0 + typeorm: 0.3.11_zfbzyadn2rnu3hf3pysto5crhm + ulid: 2.3.0 + unzipper: 0.10.11 + uuid: 9.0.0 + web-push: 3.5.0 + websocket: 1.0.34 + ws: 8.11.0 + xev: 3.0.2 + optionalDependencies: + '@swc/core-android-arm64': 1.3.11 + '@tensorflow/tfjs-node': 3.21.1_seedrandom@3.0.5 + devDependencies: + '@types/bcryptjs': 2.4.2 + '@types/bull': 3.15.9 + '@types/cbor': 6.0.0 + '@types/escape-regexp': 0.0.1 + '@types/fluent-ffmpeg': 2.1.20 + '@types/js-yaml': 4.0.5 + '@types/jsdom': 20.0.1 + '@types/jsonld': 1.5.8 + '@types/jsrsasign': 10.5.4 + '@types/koa': 2.13.5 + '@types/koa-bodyparser': 4.3.10 + '@types/koa-cors': 0.0.2 + '@types/koa-favicon': 2.0.21 + '@types/koa-logger': 3.1.2 + '@types/koa-mount': 4.0.2 + '@types/koa-send': 4.1.3 + '@types/koa-views': 7.0.0_6tybghmia4wsnt33xeid7y4rby + '@types/koa__cors': 3.3.0 + '@types/koa__multer': 2.0.4 + '@types/koa__router': 8.0.11 + '@types/mocha': 9.1.1 + '@types/node': 18.11.18 + '@types/node-fetch': 3.0.3 + '@types/nodemailer': 6.4.7 + '@types/oauth': 0.9.1 + '@types/pug': 2.0.6 + '@types/punycode': 2.1.0 + '@types/qrcode': 1.5.0 + '@types/random-seed': 0.3.3 + '@types/ratelimiter': 3.4.4 + '@types/redis': 4.0.11 + '@types/rename': 1.0.4 + '@types/sanitize-html': 2.8.0 + '@types/semver': 7.3.13 + '@types/sharp': 0.31.1 + '@types/sinonjs__fake-timers': 8.1.2 + '@types/speakeasy': 2.0.7 + '@types/tinycolor2': 1.4.3 + '@types/tmp': 0.2.3 + '@types/uuid': 8.3.4 + '@types/web-push': 3.3.2 + '@types/websocket': 1.0.5 + '@types/ws': 8.5.3 + cross-env: 7.0.3 + eslint: 8.31.0 + execa: 6.1.0 + swc-loader: 0.2.3_v4imsvpumnwpgduroyqmpcfjiy + typescript: 4.9.4 + webpack: 5.75.0_@swc+core@1.3.26 + + packages/client: + specifiers: + '@discordapp/twemoji': 14.0.2 + '@rollup/plugin-alias': 3.1.9 + '@rollup/plugin-json': 4.1.0 + '@rollup/pluginutils': ^4.2.1 + '@syuilo/aiscript': 0.11.1 + '@types/escape-regexp': 0.0.1 + '@types/glob': 8.0.0 + '@types/gulp': 4.0.10 + '@types/gulp-rename': 2.0.1 + '@types/katex': 0.14.0 + '@types/matter-js': 0.18.2 + '@types/punycode': 2.1.0 + '@types/seedrandom': 3.0.4 + '@types/throttle-debounce': 5.0.0 + '@types/tinycolor2': 1.4.3 + '@types/uuid': 8.3.4 + '@vitejs/plugin-vue': 4.0.0 + '@vue/compiler-sfc': 3.2.45 + autobind-decorator: 2.4.0 + autosize: 5.0.2 + blurhash: 1.1.5 + broadcast-channel: 4.19.1 + browser-image-resizer: https://github.com/misskey-dev/browser-image-resizer.git + calckey-js: ^0.0.20 + chart.js: 4.1.1 + chartjs-adapter-date-fns: 2.0.1 + chartjs-plugin-gradient: 0.5.1 + chartjs-plugin-zoom: 1.2.1 + compare-versions: 5.0.3 + cropperjs: 2.0.0-beta.2 + cross-env: 7.0.3 + cypress: 10.11.0 + date-fns: 2.29.3 + escape-regexp: 0.0.1 + eventemitter3: 4.0.7 + idb-keyval: 6.2.0 + insert-text-at-cursor: 0.3.0 + json5: 2.2.3 + katex: 0.16.4 + matter-js: 0.18.0 + mfm-js: 0.23.2 + photoswipe: 5.3.4 + prismjs: 1.29.0 + punycode: 2.1.1 + querystring: 0.2.1 + rndstr: 1.0.0 + rollup: 3.9.1 + s-age: 1.1.2 + sass: 1.57.1 + seedrandom: 3.0.5 + start-server-and-test: 1.15.2 + strict-event-emitter-types: 2.0.0 + stringz: 2.1.0 + swiper: ^8.4.5 + syuilo-password-strength: 0.0.1 + textarea-caret: 3.1.0 + three: 0.146.0 + throttle-debounce: 5.0.0 + tinycolor2: 1.5.2 + tsc-alias: 1.8.2 + tsconfig-paths: 4.1.2 + twemoji-parser: 14.0.0 + typescript: 4.9.4 + uuid: 9.0.0 + vanilla-tilt: 1.8.0 + vite: ^4.1.0-beta.1 + vue: 3.2.45 + vue-isyourpasswordsafe: ^2.0.0 + vue-plyr: ^7.0.0 + vue-prism-editor: 2.0.0-alpha.2 + vuedraggable: 4.1.0 + dependencies: + '@discordapp/twemoji': 14.0.2 + '@rollup/plugin-alias': 3.1.9_rollup@3.9.1 + '@rollup/plugin-json': 4.1.0_rollup@3.9.1 + '@rollup/pluginutils': 4.2.1 + '@syuilo/aiscript': 0.11.1 + '@vitejs/plugin-vue': 4.0.0_f7f773kp2g3xbdt2psqzr7g57m + '@vue/compiler-sfc': 3.2.45 + autobind-decorator: 2.4.0 + autosize: 5.0.2 + blurhash: 1.1.5 + broadcast-channel: 4.19.1 + browser-image-resizer: github.com/misskey-dev/browser-image-resizer/0380d12c8e736788ea7f4e6e985175521ea7b23c + calckey-js: 0.0.20 + chart.js: 4.1.1 + chartjs-adapter-date-fns: 2.0.1_chart.js@4.1.1 + chartjs-plugin-gradient: 0.5.1_chart.js@4.1.1 + chartjs-plugin-zoom: 1.2.1_chart.js@4.1.1 + compare-versions: 5.0.3 + cropperjs: 2.0.0-beta.2 + date-fns: 2.29.3 + escape-regexp: 0.0.1 + eventemitter3: 4.0.7 + idb-keyval: 6.2.0 + insert-text-at-cursor: 0.3.0 + json5: 2.2.3 + katex: 0.16.4 + matter-js: 0.18.0 + mfm-js: 0.23.2 + photoswipe: 5.3.4 + prismjs: 1.29.0 + punycode: 2.1.1 + querystring: 0.2.1 + rndstr: 1.0.0 + s-age: 1.1.2 + sass: 1.57.1 + seedrandom: 3.0.5 + strict-event-emitter-types: 2.0.0 + stringz: 2.1.0 + swiper: 8.4.5 + syuilo-password-strength: 0.0.1 + textarea-caret: 3.1.0 + three: 0.146.0 + throttle-debounce: 5.0.0 + tinycolor2: 1.5.2 + tsc-alias: 1.8.2 + tsconfig-paths: 4.1.2 + twemoji-parser: 14.0.0 + typescript: 4.9.4 + uuid: 9.0.0 + vanilla-tilt: 1.8.0 + vite: 4.1.0-beta.2_sass@1.57.1 + vue: 3.2.45 + vue-isyourpasswordsafe: 2.0.0 + vue-plyr: 7.0.0 + vue-prism-editor: 2.0.0-alpha.2_vue@3.2.45 + vuedraggable: 4.1.0_vue@3.2.45 + devDependencies: + '@types/escape-regexp': 0.0.1 + '@types/glob': 8.0.0 + '@types/gulp': 4.0.10 + '@types/gulp-rename': 2.0.1 + '@types/katex': 0.14.0 + '@types/matter-js': 0.18.2 + '@types/punycode': 2.1.0 + '@types/seedrandom': 3.0.4 + '@types/throttle-debounce': 5.0.0 + '@types/tinycolor2': 1.4.3 + '@types/uuid': 8.3.4 + cross-env: 7.0.3 + cypress: 10.11.0 + rollup: 3.9.1 + start-server-and-test: 1.15.2 + + packages/sw: + specifiers: + '@swc/cli': ^0.1.59 + '@swc/core': ^1.3.26 + '@swc/core-android-arm64': 1.3.11 + calckey-js: ^0.0.20 + idb-keyval: ^6.2.0 + swc-loader: ^0.2.3 + webpack: ^5.75.0 + dependencies: + '@swc/cli': 0.1.59_@swc+core@1.3.26 + '@swc/core': 1.3.26 + calckey-js: 0.0.20 + idb-keyval: 6.2.0 + optionalDependencies: + '@swc/core-android-arm64': 1.3.11 + devDependencies: + swc-loader: 0.2.3_v4imsvpumnwpgduroyqmpcfjiy + webpack: 5.75.0_@swc+core@1.3.26 + +packages: + + /@babel/code-frame/7.18.6: + resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + dev: false + + /@babel/generator/7.20.7: + resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.20.7 + '@jridgewell/gen-mapping': 0.3.2 + jsesc: 2.5.2 + dev: false + + /@babel/helper-environment-visitor/7.18.9: + resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-function-name/7.19.0: + resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.20.7 + '@babel/types': 7.20.7 + dev: false + + /@babel/helper-hoist-variables/7.18.6: + resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.20.7 + dev: false + + /@babel/helper-split-export-declaration/7.18.6: + resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.20.7 + dev: false + + /@babel/helper-string-parser/7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier/7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + + /@babel/highlight/7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + + /@babel/parser/7.20.7: + resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.20.7 + + /@babel/runtime/7.20.7: + resolution: {integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + dev: false + + /@babel/template/7.20.7: + resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + dev: false + + /@babel/traverse/7.20.12: + resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.20.7 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/types/7.20.7: + resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + + /@bull-board/api/4.10.2: + resolution: {integrity: sha512-lRHo0A7hsz71aOx1ZN0SmLLWfSuvKdL6EZ4imlgo5SuXGozybvlRc5KPIJU2/E1w5meoUGi+nFezBwp1gT/SMw==} + dependencies: + redis-info: 3.1.0 + dev: false + + /@bull-board/koa/4.10.2_6tybghmia4wsnt33xeid7y4rby: + resolution: {integrity: sha512-gabPtsMOt2SQHkS5VcY1q/FCpbBRFiFrbWbcouZ7zWKg413J8nG+yErz3pc0rbmp23kbKX6wTG/diWKhE7EWbA==} + dependencies: + '@bull-board/api': 4.10.2 + '@bull-board/ui': 4.10.2 + ejs: 3.1.8 + koa: 2.13.4 + koa-mount: 4.0.0 + koa-router: 10.1.1 + koa-static: 5.0.0 + koa-views: 7.0.2_no5ijl6tnlxntgm3uzzxedo2fe + transitivePeerDependencies: + - '@types/koa' + - arc-templates + - atpl + - babel-core + - bracket-template + - coffee-script + - dot + - dust + - dustjs-helpers + - dustjs-linkedin + - eco + - ect + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jade + - jazz + - jqtpl + - just + - liquid-node + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - pug + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - slm + - squirrelly + - supports-color + - swig + - swig-templates + - teacup + - templayed + - then-jade + - then-pug + - tinyliquid + - toffee + - twig + - twing + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: false + + /@bull-board/ui/4.10.2: + resolution: {integrity: sha512-vaHGojG5D3xjnaed3nwOaLy4Y06RgDJdYRaFR5E06SjZ0vOvjVYGD6s4cykK512Aw/ElFhKDPwzhf8BvpwAtDQ==} + dependencies: + '@bull-board/api': 4.10.2 + dev: false + + /@colors/colors/1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@cropper/element-canvas/2.0.0-beta.2: + resolution: {integrity: sha512-LZcnMwv7M3ZxUKX9YrYGxqbf8YsYfeIUFREaB/IkKsm7E7ASaDrrjdc996QYMjdjUNcWdJjxhsoucPNEvl/DXA==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-crosshair/2.0.0-beta.2: + resolution: {integrity: sha512-kBxZ2zZ7uR7XlQcnUbudq7562XwtTOqbGNYg5VWem/ukcAAKwYmPlapNlv7n228DSUGEz5FxKW8GSwLucJlQ0Q==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-grid/2.0.0-beta.2: + resolution: {integrity: sha512-rWMOjlj+eq9L2oxAthNYdGxbV3sYyV+tra6VAuooZl+RbdQZ9XCnG0Pitb/RfgPZb860ia0q8biE5zEq4Uc8fA==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-handle/2.0.0-beta.2: + resolution: {integrity: sha512-IAFyqldnB57ZGzvf3VuE7Y9UAaq9IMmun15v17cAWX1q4ZCVqdFrugAWpRF+V5WgHBL2doxHUOQlfy7LznzRmg==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-image/2.0.0-beta.2: + resolution: {integrity: sha512-FgYb+GfcxdewH6VKgw6Ltws8fw3TSP8d0HMH/WZubBC2w/NNAvp92EonwgjDoTLEFFJKbj5P2aKTFY0aO70R0Q==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/element-canvas': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-selection/2.0.0-beta.2: + resolution: {integrity: sha512-O/fxpJe/WB5H+mELSVfp4tOAAa7yMVa+wn35DCRxaDPb/1Um55E7OT1G3puAL9Elm7NFA/CCMYuHohl9emE25A==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/element-canvas': 2.0.0-beta.2 + '@cropper/element-image': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-shade/2.0.0-beta.2: + resolution: {integrity: sha512-aY5RP2ygteq51ZDU3+rAj+f+0hSgEf+vRAdJ1YO2bJ1n25TpOaz2klO5COdHxn3unLVjYK97khIZGs7ClbV0rQ==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/element-canvas': 2.0.0-beta.2 + '@cropper/element-selection': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element-viewer/2.0.0-beta.2: + resolution: {integrity: sha512-/2BhLFr2Ti5LnRvcIlLlR3NDSF3x9w9BvYukFbnCxoTLIbGvwM02YQV2Qx+al8C0mBoW0ab6uF5ykl6W8i9WkQ==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/element-canvas': 2.0.0-beta.2 + '@cropper/element-image': 2.0.0-beta.2 + '@cropper/element-selection': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/element/2.0.0-beta.2: + resolution: {integrity: sha512-i3wfelk5d4MLNgAcQpRa/jOaxWAcDLRAUkiHmU6CMl7xvOAD/4TFQGB3qSpzgx3NK4hUDLn80/gp7gM2nvrBWg==} + dependencies: + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /@cropper/elements/2.0.0-beta.2: + resolution: {integrity: sha512-l08CmeOvLJ8XLJ95OQ+kSHSbf7+pHcsu3pvQYjustbrUj0H1vzBiWT8VygPjkCUMoVIfsBpYmBNpWVGJvjoy2Q==} + dependencies: + '@cropper/element': 2.0.0-beta.2 + '@cropper/element-canvas': 2.0.0-beta.2 + '@cropper/element-crosshair': 2.0.0-beta.2 + '@cropper/element-grid': 2.0.0-beta.2 + '@cropper/element-handle': 2.0.0-beta.2 + '@cropper/element-image': 2.0.0-beta.2 + '@cropper/element-selection': 2.0.0-beta.2 + '@cropper/element-shade': 2.0.0-beta.2 + '@cropper/element-viewer': 2.0.0-beta.2 + dev: false + + /@cropper/utils/2.0.0-beta.2: + resolution: {integrity: sha512-RJu5IWzH6vcygwLsx9KEqzwjnEqApPkSFViMzxCRbe0IuAXt2ZlSUmYKgLFZY+YJIdaZ+/P7PwiUcZ7GYH3Msw==} + dev: false + + /@cspotcode/source-map-support/0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: false + + /@cypress/request/2.88.11: + resolution: {integrity: sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==} + engines: {node: '>= 6'} + dependencies: + aws-sign2: 0.7.0 + aws4: 1.12.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.10.4 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + dev: true + + /@cypress/xvfb/1.2.4_supports-color@8.1.1: + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + dependencies: + debug: 3.2.7_supports-color@8.1.1 + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@digitalbazaar/http-client/3.2.0: + resolution: {integrity: sha512-NhYXcWE/JDE7AnJikNX7q0S6zNuUPA2NuIoRdUpmvHlarjmRqyr6hIO3Awu2FxlUzbdiI1uzuWrZyB9mD1tTvw==} + engines: {node: '>=14.0'} + dependencies: + ky: 0.30.0 + ky-universal: 0.10.1_ky@0.30.0 + undici: 5.15.0 + transitivePeerDependencies: + - web-streams-polyfill + dev: false + + /@discordapp/twemoji/14.0.2: + resolution: {integrity: sha512-eYJpFsjViDTYwq3f6v+tRu8iRc+yLAeGrlh6kmNRvvC6rroUE2bMlBfEQ/WNh+2Q1FtSEFXpxzuQPOHzRzbAyA==} + dependencies: + fs-extra: 8.1.0 + jsonfile: 5.0.0 + twemoji-parser: 14.0.0 + universalify: 0.1.2 + dev: false + + /@elastic/elasticsearch/7.17.0: + resolution: {integrity: sha512-5QLPCjd0uLmLj1lSuKSThjNpq39f6NmlTy9ROLFwG5gjyTgpwSqufDeYG/Fm43Xs05uF7WcscoO7eguI3HuuYA==} + engines: {node: '>=12'} + dependencies: + debug: 4.3.4 + hpagent: 0.1.2 + ms: 2.1.3 + secure-json-parse: 2.7.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@esbuild/android-arm/0.16.17: + resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm64/0.16.17: + resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-x64/0.16.17: + resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-arm64/0.16.17: + resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-x64/0.16.17: + resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-arm64/0.16.17: + resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-x64/0.16.17: + resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm/0.16.17: + resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm64/0.16.17: + resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ia32/0.16.17: + resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-loong64/0.16.17: + resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-mips64el/0.16.17: + resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ppc64/0.16.17: + resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-riscv64/0.16.17: + resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-s390x/0.16.17: + resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-x64/0.16.17: + resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-x64/0.16.17: + resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openbsd-x64/0.16.17: + resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/sunos-x64/0.16.17: + resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-arm64/0.16.17: + resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-ia32/0.16.17: + resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-x64/0.16.17: + resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.1 + globals: 13.19.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + /@gar/promisify/1.1.3: + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + dev: false + + /@hapi/hoek/9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: true + + /@hapi/topo/5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + + /@ioredis/commands/1.2.0: + resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + + /@jridgewell/gen-mapping/0.3.2: + resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping': 0.3.17 + + /@jridgewell/resolve-uri/3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + + /@jridgewell/set-array/1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + + /@jridgewell/source-map/0.3.2: + resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} + dependencies: + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.17 + + /@jridgewell/sourcemap-codec/1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + + /@jridgewell/trace-mapping/0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + + /@jridgewell/trace-mapping/0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: false + + /@koa/cors/3.4.3: + resolution: {integrity: sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==} + engines: {node: '>= 8.0.0'} + dependencies: + vary: 1.1.2 + dev: false + + /@koa/multer/3.0.0_multer@1.4.4-lts.1: + resolution: {integrity: sha512-y+OQBmex5D1jIl723gAEUYcAWPEicIXppaAKw/zCMfpllQ08ZNweDPwoCLxEoatqd5pCu2XG6V8dl67JRq3RJw==} + engines: {node: '>= 8'} + peerDependencies: + multer: '*' + dependencies: + multer: 1.4.4-lts.1 + dev: false + + /@koa/router/9.0.1: + resolution: {integrity: sha512-OI+OU49CJV4px0WkIMmayBeqVXB/JS1ZMq7UoGlTZt6Y7ijK7kdeQ18+SEHHJPytmtI1y6Hf8XLrpxva3mhv5Q==} + engines: {node: '>= 8.0.0'} + dependencies: + debug: 4.3.4 + http-errors: 1.8.1 + koa-compose: 4.1.0 + methods: 1.1.2 + path-to-regexp: 6.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@kurkle/color/0.3.2: + resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} + dev: false + + /@mapbox/node-pre-gyp/1.0.9: + resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==} + hasBin: true + dependencies: + detect-libc: 2.0.1 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.6.8 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.3.8 + tar: 6.1.13 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-darwin-arm64/2.2.0: + resolution: {integrity: sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-darwin-x64/2.2.0: + resolution: {integrity: sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm/2.2.0: + resolution: {integrity: sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm64/2.2.0: + resolution: {integrity: sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-x64/2.2.0: + resolution: {integrity: sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-win32-x64/2.2.0: + resolution: {integrity: sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + + /@npmcli/fs/2.1.2: + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.3.8 + dev: false + + /@npmcli/move-file/2.0.1: + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + dev: false + + /@nsfw-filter/gif-frames/1.0.2: + resolution: {integrity: sha512-XZrbJWEN8YfVla5i+PD4Wj51rRlJ8OgnXiPjjOt/OsrbsCR9GZRD4jr953oNWcwiRaoIcOCFWQNMQukO7Yb1dA==} + dependencies: + '@nsfw-filter/save-pixels': 2.3.4 + get-pixels-frame-info-update: 3.3.2 + multi-integer-range: 3.0.0 + dev: false + + /@nsfw-filter/save-pixels/2.3.4: + resolution: {integrity: sha512-dRZXwrXadMvxwJYKChrDBqC6GNvxVqlmdkyvZJO5DV65qyBsHZw8bPg9CnX7EgpxGl6+4ba/MAdHDLxs2XoD0Q==} + dependencies: + gif-encoder: 0.4.1 + ndarray: 1.0.18 + ndarray-ops: 1.2.2 + pngjs-nozlib: 1.0.0 + through: 2.3.4 + dev: false + + /@peertube/http-signature/1.7.0: + resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.17.0 + dev: false + + /@redis/bloom/1.1.0_@redis+client@1.4.2: + resolution: {integrity: sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==} + peerDependencies: + '@redis/client': ^1.0.0 + dependencies: + '@redis/client': 1.4.2 + dev: true + + /@redis/client/1.4.2: + resolution: {integrity: sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==} + engines: {node: '>=14'} + dependencies: + cluster-key-slot: 1.1.1 + generic-pool: 3.9.0 + yallist: 4.0.0 + dev: true + + /@redis/graph/1.1.0_@redis+client@1.4.2: + resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==} + peerDependencies: + '@redis/client': ^1.0.0 + dependencies: + '@redis/client': 1.4.2 + dev: true + + /@redis/json/1.0.4_@redis+client@1.4.2: + resolution: {integrity: sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==} + peerDependencies: + '@redis/client': ^1.0.0 + dependencies: + '@redis/client': 1.4.2 + dev: true + + /@redis/search/1.1.0_@redis+client@1.4.2: + resolution: {integrity: sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==} + peerDependencies: + '@redis/client': ^1.0.0 + dependencies: + '@redis/client': 1.4.2 + dev: true + + /@redis/time-series/1.0.4_@redis+client@1.4.2: + resolution: {integrity: sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==} + peerDependencies: + '@redis/client': ^1.0.0 + dependencies: + '@redis/client': 1.4.2 + dev: true + + /@redocly/ajv/8.11.0: + resolution: {integrity: sha512-9GWx27t7xWhDIR02PA18nzBdLcKQRgc46xNQvjFkrYk4UOmvKhJ/dawwiX0cCOeetN5LcaaiqQbVOWYK62SGHw==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + + /@redocly/openapi-core/1.0.0-beta.120: + resolution: {integrity: sha512-BvasunpVWm5O9F/mW6JmxUqat4XFU5zNnKJkMY6GJ9UYH2UxgKnGaMLWXKtbJEOBnMT12S/p9yeqrQHnk8rGhQ==} + engines: {node: '>=12.0.0'} + dependencies: + '@redocly/ajv': 8.11.0 + '@types/node': 14.18.36 + colorette: 1.4.0 + js-levenshtein: 1.1.6 + js-yaml: 4.1.0 + lodash.isequal: 4.5.0 + minimatch: 5.1.2 + node-fetch: 2.6.8 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - encoding + dev: false + + /@rollup/plugin-alias/3.1.9_rollup@3.9.1: + resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} + engines: {node: '>=8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + dependencies: + rollup: 3.9.1 + slash: 3.0.0 + dev: false + + /@rollup/plugin-json/4.1.0_rollup@3.9.1: + resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@3.9.1 + rollup: 3.9.1 + dev: false + + /@rollup/pluginutils/3.1.0_rollup@3.9.1: + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 3.9.1 + dev: false + + /@rollup/pluginutils/4.2.1: + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: false + + /@rometools/cli-darwin-arm64/11.0.0: + resolution: {integrity: sha512-F3vkdY+s3FLIEnAjSbyHTuIPB88cLpccimW4ecid5I7S6GzGG3iUJI4xT00JhH73K4P/qW20/9r+kH1T9Du8Xg==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rometools/cli-darwin-x64/11.0.0: + resolution: {integrity: sha512-X6jhtS6Iml4GOzgNtnLwIp/KXXhSdqeVyfv69m/AHnIzx3gQAjPZ7BPnJLvTCbhe4SKHL+uTZYFSCJpkUUKE6w==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rometools/cli-linux-arm64/11.0.0: + resolution: {integrity: sha512-dktTJJlTpmycBZ2TwhJBcAO8ztK8DdevdyZnFFxdYRvtmJgTjIsC2UFayf/SbKew8B8q1IhI0it+D6ihAeIpeg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rometools/cli-linux-x64/11.0.0: + resolution: {integrity: sha512-WVcnXPNdWGUWo0p4NU8YzuthjYR7q+b4vRcjdxtP1DlpphZmSsoC/RSE85nEqRAz8hChcKUansVzOPM8BSsuGA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rometools/cli-win32-arm64/11.0.0: + resolution: {integrity: sha512-tPj6RThQzS7Q45jqQll7NlTYvNcsg/BEP3LYiiazqSh9FAFnMkrV6ewUcMPKWyAfiyLs7jlz4rRvdNRUSygzfQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rometools/cli-win32-x64/11.0.0: + resolution: {integrity: sha512-bmBai8WHxYjsGk1+je7ZTfCUCWq30WJI3pQM8pzTA674lfGTZ9ymJoZwTaIMSO4rL5V9mlO6uLunsBKso9VqOg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@sideway/address/4.1.4: + resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@sideway/formula/3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + + /@sideway/pinpoint/2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: true + + /@sindresorhus/is/0.7.0: + resolution: {integrity: sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==} + engines: {node: '>=4'} + dev: false + + /@sindresorhus/is/4.6.0: + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + dev: false + + /@sindresorhus/is/5.3.0: + resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==} + engines: {node: '>=14.16'} + dev: false + + /@sinonjs/commons/1.8.6: + resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} + dependencies: + type-detect: 4.0.8 + dev: false + + /@sinonjs/fake-timers/9.1.2: + resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} + dependencies: + '@sinonjs/commons': 1.8.6 + dev: false + + /@sqltools/formatter/1.2.5: + resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} + dev: false + + /@swc/cli/0.1.59_@swc+core@1.3.26: + resolution: {integrity: sha512-BlX3wIxYTwdtR22dIqZ3FEIOJPqnlByAp4JY46OMZi2UXMB3ZbOzefawD2ZlLafRUWyy5NtiZZty5waKzaYRnA==} + engines: {node: '>= 12.13'} + hasBin: true + peerDependencies: + '@swc/core': ^1.2.66 + chokidar: ^3.5.1 + peerDependenciesMeta: + chokidar: + optional: true + dependencies: + '@swc/core': 1.3.26 + bin-wrapper: 4.1.0 + commander: 7.2.0 + fast-glob: 3.2.12 + semver: 7.3.8 + slash: 3.0.0 + source-map: 0.7.4 + dev: false + + /@swc/cli/0.1.59_cr4os3zuq4gmhe2qzzjtw2pxeu: + resolution: {integrity: sha512-BlX3wIxYTwdtR22dIqZ3FEIOJPqnlByAp4JY46OMZi2UXMB3ZbOzefawD2ZlLafRUWyy5NtiZZty5waKzaYRnA==} + engines: {node: '>= 12.13'} + hasBin: true + peerDependencies: + '@swc/core': ^1.2.66 + chokidar: ^3.5.1 + peerDependenciesMeta: + chokidar: + optional: true + dependencies: + '@swc/core': 1.3.26 + bin-wrapper: 4.1.0 + chokidar: 3.5.3 + commander: 7.2.0 + fast-glob: 3.2.12 + semver: 7.3.8 + slash: 3.0.0 + source-map: 0.7.4 + dev: false + + /@swc/core-android-arm64/1.3.11: + resolution: {integrity: sha512-M7FamR3kFpVTyTw73FzKcOZmS7/TWHX75eqtwBTaU9fW4shf0KTLr/h9DnMxNKAnwUMeub/lqlINUe5EKFIKwQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dependencies: + '@swc/wasm': 1.2.130 + dev: false + optional: true + + /@swc/core-darwin-arm64/1.3.26: + resolution: {integrity: sha512-FWWflBfKRYrUJtko2xiedC5XCa31O75IZZqnTWuLpe9g3C5tnUuF3M8LSXZS/dn6wprome1MhtG9GMPkSYkhkg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@swc/core-darwin-x64/1.3.26: + resolution: {integrity: sha512-0uQeebAtsewqJ2b35aPZstGrylwd6oJjUyAJOfVJNbremFSJ5JzytB3NoDCIw7CT5UQrSRpvD3mU95gfdQjDGA==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@swc/core-linux-arm-gnueabihf/1.3.26: + resolution: {integrity: sha512-06T+LbVFlyciQtwrUB5/a16A1ju1jFoYvd/hq9TWhf7GrtL43U7oJIgqMOPHx2j0+Ps2R3S6R/UUN5YXu618zA==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@swc/core-linux-arm64-gnu/1.3.26: + resolution: {integrity: sha512-2NT/0xALPfK+U01qIlHxjkGdIj6F0txhu1U2v6B0YP2+k0whL2gCgYeg9QUvkYEXSD5r1Yx+vcb2R/vaSCSClg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@swc/core-linux-arm64-musl/1.3.26: + resolution: {integrity: sha512-64KrTay9hC0mTvZ1AmEFmNEwV5QDjw9U7PJU5riotSc28I+Q/ZoM0qcSFW9JRRa6F2Tr+IfMtyv8+eB2//BQ5g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@swc/core-linux-x64-gnu/1.3.26: + resolution: {integrity: sha512-Te8G13l3dcRM1Mf3J4JzGUngzNXLKnMYlUmBOYN/ORsx7e+VNelR3zsTLHC0+0jGqELDgqvMyzDfk+dux/C/bQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@swc/core-linux-x64-musl/1.3.26: + resolution: {integrity: sha512-nqQWuSM6OTKepUiQ9+rXgERq/JiO72RBOpXKO2afYppsL96sngjIRewV74v5f6IAfyzw+k+AhC5pgRA4Xu/Jkg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@swc/core-win32-arm64-msvc/1.3.26: + resolution: {integrity: sha512-xx34mx+9IBV1sun7sxoNFiqNom9wiOuvsQFJUyQptCnZHgYwOr9OI204LBF95dCcBCZsTm2hT1wBnySJOeimYw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@swc/core-win32-ia32-msvc/1.3.26: + resolution: {integrity: sha512-48LZ/HKNuU9zl8c7qG6IQKb5rBCwmJgysGOmEGzTRBYxAf/x6Scmt0aqxCoV4J02HOs2WduCBDnhUKsSQ2kcXQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@swc/core-win32-x64-msvc/1.3.26: + resolution: {integrity: sha512-UPe7S+MezD/S6cKBIc50TduGzmw6PBz1Ms5p+5wDLOKYNS/LSEM4iRmLwvePzP5X8mOyesXrsbwxLy8KHP65Yw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /@swc/core/1.3.26: + resolution: {integrity: sha512-U7vEsaLn3IGg0XCRLJX/GTkK9WIfFHUX5USdrp1L2QD29sWPe25HqNndXmUR9KytzKmpDMNoUuHyiuhpVrnNeQ==} + engines: {node: '>=10'} + requiresBuild: true + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.26 + '@swc/core-darwin-x64': 1.3.26 + '@swc/core-linux-arm-gnueabihf': 1.3.26 + '@swc/core-linux-arm64-gnu': 1.3.26 + '@swc/core-linux-arm64-musl': 1.3.26 + '@swc/core-linux-x64-gnu': 1.3.26 + '@swc/core-linux-x64-musl': 1.3.26 + '@swc/core-win32-arm64-msvc': 1.3.26 + '@swc/core-win32-ia32-msvc': 1.3.26 + '@swc/core-win32-x64-msvc': 1.3.26 + + /@swc/wasm/1.2.130: + resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==} + requiresBuild: true + dev: false + optional: true + + /@syuilo/aiscript/0.11.1: + resolution: {integrity: sha512-chwOIA3yLUKvOB0G611hjLArKTeOWNmTm3lHERSaDW1d+dS6do56naX6Lkwy2UpnwWC0qzeNSgg35elk6t2gZg==} + dependencies: + autobind-decorator: 2.4.0 + chalk: 4.0.0 + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 7.0.3 + dev: false + + /@szmarczak/http-timer/4.0.6: + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + dependencies: + defer-to-connect: 2.0.1 + dev: false + + /@szmarczak/http-timer/5.0.1: + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + dependencies: + defer-to-connect: 2.0.1 + dev: false + + /@tensorflow/tfjs-backend-cpu/3.21.0_aipmo6igpprgzt4umpaa3m6sn4: + resolution: {integrity: sha512-88S21UAdzyK0CsLUrH17GPTD+26E85OP9CqmLZslaWjWUmBkeTQ5Zqyp6iK+gELnLxPx6q7JsNEeFuPv4254lQ==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + dependencies: + '@tensorflow/tfjs-core': 3.21.0 + '@types/seedrandom': 2.4.30 + seedrandom: 3.0.5 + dev: false + + /@tensorflow/tfjs-backend-cpu/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-8HWg9J69m0Ovc6w8TVhhixMOcwA3t/NPXLblOA/sgJ+/JD5gsbpLWJk4QISQyb1RnpSVzw6PX3BSMTJU7hWVOg==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.2.0 + dependencies: + '@tensorflow/tfjs-core': 4.2.0 + '@types/seedrandom': 2.4.30 + seedrandom: 3.0.5 + dev: false + + /@tensorflow/tfjs-backend-webgl/3.21.0_aipmo6igpprgzt4umpaa3m6sn4: + resolution: {integrity: sha512-N4zitIAT9IX8B8oe489qM3f3VcESxGZIZvHmVP8varOQakTvTX859aaPo1s8hK1qCy4BjSGbweooZe4U8D4kTQ==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + dependencies: + '@tensorflow/tfjs-backend-cpu': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 + '@tensorflow/tfjs-core': 3.21.0 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.30 + '@types/webgl-ext': 0.0.30 + '@types/webgl2': 0.0.6 + seedrandom: 3.0.5 + dev: false + + /@tensorflow/tfjs-backend-webgl/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-Qvf+hD5pSh+xi48kChSGzcDKJemkc4EKfoVVjuxl4k25ZUPwuEd7zZUAtinkLu1dzgHNyvePZY8k+9rVm59HJA==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.2.0 + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-core': 4.2.0 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.30 + '@types/webgl-ext': 0.0.30 + seedrandom: 3.0.5 + dev: false + + /@tensorflow/tfjs-converter/3.21.0_aipmo6igpprgzt4umpaa3m6sn4: + resolution: {integrity: sha512-12Y4zVDq3yW+wSjSDpSv4HnpL2sDZrNiGSg8XNiDE4HQBdjdA+a+Q3sZF/8NV9y2yoBhL5L7V4mMLDdbZBd9/Q==} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + dependencies: + '@tensorflow/tfjs-core': 3.21.0 + dev: false + + /@tensorflow/tfjs-converter/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-m+E2KJM6yGQdi8ElzWpChdD/JaqhWMCi9yK70v/ndkOaCL2q2UN48nYP2T5S15vkDvMIgzAQyZfh7hxQsMuvRQ==} + peerDependencies: + '@tensorflow/tfjs-core': 4.2.0 + dependencies: + '@tensorflow/tfjs-core': 4.2.0 + dev: false + + /@tensorflow/tfjs-core/3.21.0: + resolution: {integrity: sha512-YSfsswOqWfd+M4bXIhT3hwtAb+IV8+ODwIxwdFR/7jTAPZP1wMVnSlpKnXHAN64HFOiP+Tm3HmKusEZ0+09A0w==} + engines: {yarn: '>= 1.3.2'} + dependencies: + '@types/long': 4.0.2 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.30 + '@types/webgl-ext': 0.0.30 + '@webgpu/types': 0.1.16 + long: 4.0.0 + node-fetch: 2.6.8 + seedrandom: 3.0.5 + transitivePeerDependencies: + - encoding + dev: false + + /@tensorflow/tfjs-core/4.2.0: + resolution: {integrity: sha512-uuHkiWVC8b00ngFbHvAV7J7haRlN/9PEdeenCi0CzBjgKd7aN25wPWaoN0TSQcU+GT4FJ8mofMZ9VBYZ/s/WLg==} + engines: {yarn: '>= 1.3.2'} + dependencies: + '@types/long': 4.0.2 + '@types/offscreencanvas': 2019.7.0 + '@types/seedrandom': 2.4.30 + '@types/webgl-ext': 0.0.30 + '@webgpu/types': 0.1.21 + long: 4.0.0 + node-fetch: 2.6.8 + seedrandom: 3.0.5 + transitivePeerDependencies: + - encoding + dev: false + + /@tensorflow/tfjs-data/3.21.0_5g5qgh2bedza5bmf2zfn7wcrmu: + resolution: {integrity: sha512-eFLfw2wIcFNxnP2Iv/SnVlihehzKMumk1b5Prcx1ixk/SbkCo5u0Lt7OVOWaEOKVqvB2sT+dJcTjAh6lrCC/QA==} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + seedrandom: ^3.0.5 + dependencies: + '@tensorflow/tfjs-core': 3.21.0 + '@types/node-fetch': 2.6.2 + node-fetch: 2.6.8 + seedrandom: 3.0.5 + string_decoder: 1.3.0 + transitivePeerDependencies: + - encoding + dev: false + + /@tensorflow/tfjs-data/4.2.0_qsavyspjcgrxymzlcpasp6rzxe: + resolution: {integrity: sha512-11t7Q+ikseduJgkd9iSeRrtor1aA3o5PVCFhC5yYvR3JLO55ic1+4Ryo0EJfhRoismS6zBUJrpzX4K0zlLbIfw==} + peerDependencies: + '@tensorflow/tfjs-core': 4.2.0 + seedrandom: ^3.0.5 + dependencies: + '@tensorflow/tfjs-core': 4.2.0 + '@types/node-fetch': 2.6.2 + node-fetch: 2.6.8 + seedrandom: 3.0.5 + string_decoder: 1.3.0 + transitivePeerDependencies: + - encoding + dev: false + + /@tensorflow/tfjs-layers/3.21.0_aipmo6igpprgzt4umpaa3m6sn4: + resolution: {integrity: sha512-CMVXsraakXgnXEnqD9QbtResA7nvV7Jz20pGmjFIodcQkClgmFFhdCG5N+zlVRHEz7VKG2OyfhltZ0dBq/OAhA==} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + dependencies: + '@tensorflow/tfjs-core': 3.21.0 + dev: false + + /@tensorflow/tfjs-layers/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-SO0KTmCFOjrW+PlP9nKYXz07XGFq6uE7am9yH2bRaRPWpEeaKT/+k0C9vFMxI/GzRwY8AK4sLe4U+jE1mhYxGw==} + peerDependencies: + '@tensorflow/tfjs-core': 4.2.0 + dependencies: + '@tensorflow/tfjs-core': 4.2.0 + dev: false + + /@tensorflow/tfjs-node/3.21.1_seedrandom@3.0.5: + resolution: {integrity: sha512-WV77fiuux6E5RR7FRD8RL3yCruhoHjZMI9yybztGLItJwco2YVjHr6h4TOjaZcIMnxu9748iV118MN2ZeLXbdQ==} + engines: {node: '>=8.11.0'} + requiresBuild: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.9 + '@tensorflow/tfjs': 3.21.0_seedrandom@3.0.5 + adm-zip: 0.5.10 + google-protobuf: 3.21.2 + https-proxy-agent: 2.2.4 + progress: 2.0.3 + rimraf: 2.7.1 + tar: 4.4.19 + transitivePeerDependencies: + - encoding + - seedrandom + - supports-color + dev: false + optional: true + + /@tensorflow/tfjs/3.21.0_seedrandom@3.0.5: + resolution: {integrity: sha512-khcARd3/872llL/oF4ouR40qlT71mylU66PGT8kHP/GJ5YKj44sv8lDRjU7lOVlJK7jsJFWEsNVHI3eMc/GWNQ==} + hasBin: true + dependencies: + '@tensorflow/tfjs-backend-cpu': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 + '@tensorflow/tfjs-backend-webgl': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 + '@tensorflow/tfjs-converter': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 + '@tensorflow/tfjs-core': 3.21.0 + '@tensorflow/tfjs-data': 3.21.0_5g5qgh2bedza5bmf2zfn7wcrmu + '@tensorflow/tfjs-layers': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 + argparse: 1.0.10 + chalk: 4.1.2 + core-js: 3.27.1 + regenerator-runtime: 0.13.11 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - seedrandom + dev: false + + /@tensorflow/tfjs/4.2.0_seedrandom@3.0.5: + resolution: {integrity: sha512-iZmtyGC9IJkx+TpFnkgDol8BHv2BU3zJ01HyNcuvnm1w1EqoNe+1n8bwvLzI/sxHMcHTqzuu7VugMaphryxE+A==} + hasBin: true + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-backend-webgl': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-converter': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-core': 4.2.0 + '@tensorflow/tfjs-data': 4.2.0_qsavyspjcgrxymzlcpasp6rzxe + '@tensorflow/tfjs-layers': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + argparse: 1.0.10 + chalk: 4.1.2 + core-js: 3.27.1 + regenerator-runtime: 0.13.11 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - seedrandom + dev: false + + /@tokenizer/token/0.3.0: + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + dev: false + + /@tootallnate/once/2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: false + + /@tsconfig/node10/1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: false + + /@tsconfig/node12/1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: false + + /@tsconfig/node14/1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: false + + /@tsconfig/node16/1.0.3: + resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + dev: false + + /@types/accepts/1.3.5: + resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} + dependencies: + '@types/node': 18.11.18 + + /@types/bcryptjs/2.4.2: + resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} + dev: true + + /@types/body-parser/1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 18.11.18 + + /@types/bull/3.15.9: + resolution: {integrity: sha512-MPUcyPPQauAmynoO3ezHAmCOhbB0pWmYyijr/5ctaCqhbKWsjW0YCod38ZcLzUBprosfZ9dPqfYIcfdKjk7RNQ==} + dependencies: + '@types/ioredis': 5.0.0 + '@types/redis': 2.8.32 + transitivePeerDependencies: + - supports-color + dev: true + + /@types/cacheable-request/6.0.3: + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + dependencies: + '@types/http-cache-semantics': 4.0.1 + '@types/keyv': 3.1.4 + '@types/node': 18.11.18 + '@types/responselike': 1.0.0 + dev: false + + /@types/cbor/6.0.0: + resolution: {integrity: sha512-mGQ1lbYOwVti5Xlarn1bTeBZqgY0kstsdjnkoEovgohYKdBjGejHyNGXHdMBeqyQazIv32Jjp33+5pBEaSRy2w==} + deprecated: This is a stub types definition. cbor provides its own type definitions, so you do not need this installed. + dependencies: + cbor: 8.1.0 + dev: true + + /@types/connect/3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 18.11.18 + + /@types/content-disposition/0.5.5: + resolution: {integrity: sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA==} + + /@types/cookies/0.7.7: + resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==} + dependencies: + '@types/connect': 3.4.35 + '@types/express': 4.17.15 + '@types/keygrip': 1.0.2 + '@types/node': 18.11.18 + + /@types/disposable-email-domains/1.0.2: + resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==} + dev: false + + /@types/escape-regexp/0.0.1: + resolution: {integrity: sha512-ogj/ZTIdeFkiuxDwawYuZSIgC6suFGgBeZPr6Xs5lHEcvIXTjXGtH+/n8f1XhZhespaUwJ5LIGRICPji972FLw==} + dev: true + + /@types/eslint-scope/3.7.4: + resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} + dependencies: + '@types/eslint': 8.4.10 + '@types/estree': 0.0.51 + + /@types/eslint/8.4.10: + resolution: {integrity: sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==} + dependencies: + '@types/estree': 0.0.51 + '@types/json-schema': 7.0.11 + + /@types/estree/0.0.39: + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + dev: false + + /@types/estree/0.0.51: + resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} + + /@types/expect/1.20.4: + resolution: {integrity: sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==} + + /@types/express-serve-static-core/4.17.32: + resolution: {integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==} + dependencies: + '@types/node': 18.11.18 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + + /@types/express/4.17.15: + resolution: {integrity: sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.32 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.0 + + /@types/fluent-ffmpeg/2.1.20: + resolution: {integrity: sha512-B+OvhCdJ3LgEq2PhvWNOiB/EfwnXLElfMCgc4Z1K5zXgSfo9I6uGKwR/lqmNPFQuebNnes7re3gqkV77SyypLg==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/glob-stream/6.1.1: + resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} + dependencies: + '@types/glob': 8.0.0 + '@types/node': 18.11.18 + dev: true + + /@types/glob/8.0.0: + resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 18.11.18 + dev: true + + /@types/gulp-rename/2.0.1: + resolution: {integrity: sha512-9ZjeS2RHEnmBmTcyi2+oeye3BgCsWhvi4uv3qCnAg8i6plOuRdaeNxjOves0ELysEXYLBl7bCl5fbVs7AZtgTA==} + dependencies: + '@types/node': 18.11.18 + '@types/vinyl': 2.0.7 + dev: true + + /@types/gulp/4.0.10: + resolution: {integrity: sha512-spgZHJFqiEJGwqGlf7T/k4nkBpBcLgP7T0EfN6G2vvnhUfvd4uO1h8RwpXOE8x/54DVYUs1XCAtBHkX/R3axAQ==} + dependencies: + '@types/undertaker': 1.2.8 + '@types/vinyl-fs': 2.4.12 + chokidar: 3.5.3 + dev: true + + /@types/http-assert/1.5.3: + resolution: {integrity: sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==} + + /@types/http-cache-semantics/4.0.1: + resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} + dev: false + + /@types/http-errors/2.0.1: + resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==} + + /@types/ioredis/5.0.0: + resolution: {integrity: sha512-zJbJ3FVE17CNl5KXzdeSPtdltc4tMT3TzC6fxQS0sQngkbFZ6h+0uTafsRqu+eSLIugf6Yb0Ea0SUuRr42Nk9g==} + deprecated: This is a stub types definition. ioredis provides its own type definitions, so you do not need this installed. + dependencies: + ioredis: 5.2.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@types/js-yaml/4.0.5: + resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} + dev: true + + /@types/jsdom/20.0.1: + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + dependencies: + '@types/node': 18.11.18 + '@types/tough-cookie': 4.0.2 + parse5: 7.1.2 + dev: true + + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + + /@types/jsonld/1.5.8: + resolution: {integrity: sha512-4l5t/jDnJpqZ+i7CLTTgPcT5BYXnAnwJupb07aAokPufCV0SjDHcwctUkSTuhIuSU9yHok+WOOngIGCtpL96gw==} + dev: true + + /@types/jsrsasign/10.5.4: + resolution: {integrity: sha512-05S2f4lGaWgCwFHsa3OEirc4VJf/sJRfhofzxUbuFbmm6NbffPXZrnJqquQAtS3g4C8Z0L9NHgW0znmtDxNoTQ==} + dev: true + + /@types/katex/0.14.0: + resolution: {integrity: sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==} + dev: true + + /@types/keygrip/1.0.2: + resolution: {integrity: sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==} + + /@types/keyv/3.1.4: + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + dependencies: + '@types/node': 18.11.18 + dev: false + + /@types/koa-bodyparser/4.3.10: + resolution: {integrity: sha512-6ae05pjhmrmGhUR8GYD5qr5p9LTEMEGfGXCsK8VaSL+totwigm8+H/7MHW7K4854CMeuwRAubT8qcc/EagaeIA==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-compose/3.2.5: + resolution: {integrity: sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==} + dependencies: + '@types/koa': 2.13.5 + + /@types/koa-cors/0.0.2: + resolution: {integrity: sha512-uNaDY26HUVO+2C6arK8ZFODs9mBjYprD8mlvkVe2bYdX9wzEeKtycVXPafXpUkePhMh4sffIMkhRDyedokG/QA==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-favicon/2.0.21: + resolution: {integrity: sha512-paH1nheVhijx/VduoR/RCD/qTCiX+OI/6fHLi3mZae053Ts+gUBOrKtzl3pMTDbdEBqdLolfLje3PZbb6jW0jQ==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-logger/3.1.2: + resolution: {integrity: sha512-sioTA1xlKYiIgryANWPRHBkG3XGbWftw9slWADUPC+qvPIY/yRLSrhvX7zkJwMrntub5dPO0GuAoyGGf0yitfQ==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-mount/4.0.2: + resolution: {integrity: sha512-XnuGwV8bzw22nv2WqOs5a8wCHR2VgSnLLLuBQPzNTmhyiAvH0O6c+994rQVbMaBuwQJKefUInkvKoKuk+21uew==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-send/4.1.3: + resolution: {integrity: sha512-daaTqPZlgjIJycSTNjKpHYuKhXYP30atFc1pBcy6HHqB9+vcymDgYTguPdx9tO4HMOqNyz6bz/zqpxt5eLR+VA==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa-views/7.0.0_6tybghmia4wsnt33xeid7y4rby: + resolution: {integrity: sha512-AB/NB+oFHcLOZJYFv3bG5Af8YbwYCD9/zK0WcKALsbjI/FRKrcXTUTC64RebDrkyOkBm3bpCgpGndhAH/3YQ2Q==} + deprecated: This is a stub types definition. koa-views provides its own type definitions, so you do not need this installed. + dependencies: + koa-views: 7.0.2_6tybghmia4wsnt33xeid7y4rby + transitivePeerDependencies: + - '@types/koa' + - arc-templates + - atpl + - babel-core + - bracket-template + - coffee-script + - dot + - dust + - dustjs-helpers + - dustjs-linkedin + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jade + - jazz + - jqtpl + - just + - liquid-node + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - pug + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - slm + - squirrelly + - supports-color + - swig + - swig-templates + - teacup + - templayed + - then-jade + - then-pug + - tinyliquid + - toffee + - twig + - twing + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: true + + /@types/koa/2.13.5: + resolution: {integrity: sha512-HSUOdzKz3by4fnqagwthW/1w/yJspTgppyyalPVbgZf8jQWvdIXcVW5h2DGtw4zYntOaeRGx49r1hxoPWrD4aA==} + dependencies: + '@types/accepts': 1.3.5 + '@types/content-disposition': 0.5.5 + '@types/cookies': 0.7.7 + '@types/http-assert': 1.5.3 + '@types/http-errors': 2.0.1 + '@types/keygrip': 1.0.2 + '@types/koa-compose': 3.2.5 + '@types/node': 18.11.18 + + /@types/koa__cors/3.3.0: + resolution: {integrity: sha512-FUN8YxcBakIs+walVe3+HcNP+Bxd0SB8BJHBWkglZ5C1XQWljlKcEFDG/dPiCIqwVCUbc5X0nYDlH62uEhdHMA==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa__multer/2.0.4: + resolution: {integrity: sha512-WRkshXhE5rpYFUbbtAjyMhdOOSdbu1XX+2AQlRNM6AZtgxd0/WXMU4lrP7e9tk5HWVTWbx8DOOsVBmfHjSGJ4w==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/koa__router/8.0.11: + resolution: {integrity: sha512-WXgKWpBsbS14kzmzD9LeFapOIa678h7zvUHxDwXwSx4ETKXhXLVUAToX6jZ/U7EihM7qwyD9W/BZvB0MRu7MTQ==} + dependencies: + '@types/koa': 2.13.5 + dev: true + + /@types/long/4.0.2: + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + dev: false + + /@types/matter-js/0.18.2: + resolution: {integrity: sha512-W9UC9DOPNBRTUocqqPZmzX3cbHmlZBI9jLn6SuxZz0n5QrPk382Ig3hbBWHqYU8TRUmTCJJhuanXeyMTavF7Mg==} + dev: true + + /@types/mime/3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + + /@types/minimatch/5.1.2: + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + dev: true + + /@types/mocha/9.1.1: + resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} + dev: true + + /@types/node-fetch/2.6.2: + resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} + dependencies: + '@types/node': 18.11.18 + form-data: 3.0.1 + dev: false + + /@types/node-fetch/3.0.3: + resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==} + deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed. + dependencies: + node-fetch: 3.3.0 + dev: true + + /@types/node/14.18.36: + resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==} + + /@types/node/18.11.18: + resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} + + /@types/nodemailer/6.4.7: + resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/oauth/0.9.1: + resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/offscreencanvas/2019.3.0: + resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} + dev: false + + /@types/offscreencanvas/2019.7.0: + resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==} + dev: false + + /@types/pug/2.0.6: + resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} + dev: true + + /@types/punycode/2.1.0: + resolution: {integrity: sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g==} + dev: true + + /@types/qrcode/1.5.0: + resolution: {integrity: sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/qs/6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + + /@types/random-seed/0.3.3: + resolution: {integrity: sha512-kHsCbIRHNXJo6EN5W8EA5b4i1hdT6jaZke5crBPLUcLqaLdZ0QBq8QVMbafHzhjFF83Cl9qlee2dChD18d/kPg==} + dev: true + + /@types/range-parser/1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + + /@types/ratelimiter/3.4.4: + resolution: {integrity: sha512-GSMb93iSA8KKFDgVL2Wzs/kqrHMJcU8xhLdwI5omoACcj7K18SacklLtY1C4G02HC5drd6GygtsIaGbfxJSe0g==} + dev: true + + /@types/redis/2.8.32: + resolution: {integrity: sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/redis/4.0.11: + resolution: {integrity: sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==} + deprecated: This is a stub types definition. redis provides its own type definitions, so you do not need this installed. + dependencies: + redis: 4.5.1 + dev: true + + /@types/rename/1.0.4: + resolution: {integrity: sha512-eV81+6bVv2mdCBahkMefjEUwAjKDAP3AuyhqWCWRxcRaeVdUeHUBaoq2zSz+5HNHF2jzTajMcfLvJsy4K3cbwA==} + dev: true + + /@types/responselike/1.0.0: + resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} + dependencies: + '@types/node': 18.11.18 + dev: false + + /@types/sanitize-html/2.8.0: + resolution: {integrity: sha512-Uih6caOm3DsBYnVGOYn0A9NoTNe1c4aPStmHC/YA2JrpP9kx//jzaRcIklFvSpvVQEcpl/ZCr4DgISSf/YxTvg==} + dependencies: + htmlparser2: 8.0.1 + dev: true + + /@types/seedrandom/2.4.30: + resolution: {integrity: sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==} + dev: false + + /@types/seedrandom/3.0.4: + resolution: {integrity: sha512-/rWdxeiuZenlawrHU+XV6ZHMTKOqrC2hMfeDfLTIWJhDZP5aVqXRysduYHBbhD7CeJO6FJr/D2uBVXB7GT6v7w==} + dev: true + + /@types/semver/7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + dev: true + + /@types/serve-static/1.15.0: + resolution: {integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==} + dependencies: + '@types/mime': 3.0.1 + '@types/node': 18.11.18 + + /@types/sharp/0.31.1: + resolution: {integrity: sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/sinonjs__fake-timers/8.1.1: + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + dev: true + + /@types/sinonjs__fake-timers/8.1.2: + resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} + dev: true + + /@types/sizzle/2.3.3: + resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + dev: true + + /@types/speakeasy/2.0.7: + resolution: {integrity: sha512-JEcOhN2SQCoX86ZfiZEe8px84sVJtivBXMZfOVyARTYEj0hrwwbj1nF0FwEL3nJSoEV6uTbcdLllMKBgAYHWCQ==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/throttle-debounce/5.0.0: + resolution: {integrity: sha512-Pb7k35iCGFcGPECoNE4DYp3Oyf2xcTd3FbFQxXUI9hEYKUl6YX+KLf7HrBmgVcD05nl50LIH6i+80js4iYmWbw==} + dev: true + + /@types/tinycolor2/1.4.3: + resolution: {integrity: sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==} + dev: true + + /@types/tmp/0.2.3: + resolution: {integrity: sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==} + dev: true + + /@types/tough-cookie/4.0.2: + resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==} + dev: true + + /@types/undertaker-registry/1.0.1: + resolution: {integrity: sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==} + dev: true + + /@types/undertaker/1.2.8: + resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} + dependencies: + '@types/node': 18.11.18 + '@types/undertaker-registry': 1.0.1 + async-done: 1.3.2 + dev: true + + /@types/uuid/8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + + /@types/vinyl-fs/2.4.12: + resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} + dependencies: + '@types/glob-stream': 6.1.1 + '@types/node': 18.11.18 + '@types/vinyl': 2.0.7 + dev: true + + /@types/vinyl/2.0.7: + resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} + dependencies: + '@types/expect': 1.20.4 + '@types/node': 18.11.18 + + /@types/web-push/3.3.2: + resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/webgl-ext/0.0.30: + resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==} + dev: false + + /@types/webgl2/0.0.6: + resolution: {integrity: sha512-50GQhDVTq/herLMiqSQkdtRu+d5q/cWHn4VvKJtrj4DJAjo1MNkWYa2MA41BaBO1q1HgsUjuQvEOk0QHvlnAaQ==} + dev: false + + /@types/websocket/1.0.5: + resolution: {integrity: sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/ws/8.5.3: + resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} + dependencies: + '@types/node': 18.11.18 + dev: true + + /@types/yauzl/2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} + requiresBuild: true + dependencies: + '@types/node': 18.11.18 + dev: true + optional: true + + /@vitejs/plugin-vue/4.0.0_f7f773kp2g3xbdt2psqzr7g57m: + resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.1.0-beta.2_sass@1.57.1 + vue: 3.2.45 + dev: false + + /@vue/compiler-core/3.2.45: + resolution: {integrity: sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==} + dependencies: + '@babel/parser': 7.20.7 + '@vue/shared': 3.2.45 + estree-walker: 2.0.2 + source-map: 0.6.1 + dev: false + + /@vue/compiler-dom/3.2.45: + resolution: {integrity: sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==} + dependencies: + '@vue/compiler-core': 3.2.45 + '@vue/shared': 3.2.45 + dev: false + + /@vue/compiler-sfc/2.7.14: + resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==} + dependencies: + '@babel/parser': 7.20.7 + postcss: 8.4.21 + source-map: 0.6.1 + dev: false + + /@vue/compiler-sfc/3.2.45: + resolution: {integrity: sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==} + dependencies: + '@babel/parser': 7.20.7 + '@vue/compiler-core': 3.2.45 + '@vue/compiler-dom': 3.2.45 + '@vue/compiler-ssr': 3.2.45 + '@vue/reactivity-transform': 3.2.45 + '@vue/shared': 3.2.45 + estree-walker: 2.0.2 + magic-string: 0.25.9 + postcss: 8.4.21 + source-map: 0.6.1 + dev: false + + /@vue/compiler-ssr/3.2.45: + resolution: {integrity: sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==} + dependencies: + '@vue/compiler-dom': 3.2.45 + '@vue/shared': 3.2.45 + dev: false + + /@vue/reactivity-transform/3.2.45: + resolution: {integrity: sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==} + dependencies: + '@babel/parser': 7.20.7 + '@vue/compiler-core': 3.2.45 + '@vue/shared': 3.2.45 + estree-walker: 2.0.2 + magic-string: 0.25.9 + dev: false + + /@vue/reactivity/3.2.45: + resolution: {integrity: sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==} + dependencies: + '@vue/shared': 3.2.45 + dev: false + + /@vue/runtime-core/3.2.45: + resolution: {integrity: sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==} + dependencies: + '@vue/reactivity': 3.2.45 + '@vue/shared': 3.2.45 + dev: false + + /@vue/runtime-dom/3.2.45: + resolution: {integrity: sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==} + dependencies: + '@vue/runtime-core': 3.2.45 + '@vue/shared': 3.2.45 + csstype: 2.6.21 + dev: false + + /@vue/server-renderer/3.2.45_vue@3.2.45: + resolution: {integrity: sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==} + peerDependencies: + vue: 3.2.45 + dependencies: + '@vue/compiler-ssr': 3.2.45 + '@vue/shared': 3.2.45 + vue: 3.2.45 + dev: false + + /@vue/shared/3.2.45: + resolution: {integrity: sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==} + dev: false + + /@webassemblyjs/ast/1.11.1: + resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} + dependencies: + '@webassemblyjs/helper-numbers': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + + /@webassemblyjs/floating-point-hex-parser/1.11.1: + resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==} + + /@webassemblyjs/helper-api-error/1.11.1: + resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==} + + /@webassemblyjs/helper-buffer/1.11.1: + resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==} + + /@webassemblyjs/helper-numbers/1.11.1: + resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==} + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.1 + '@webassemblyjs/helper-api-error': 1.11.1 + '@xtuc/long': 4.2.2 + + /@webassemblyjs/helper-wasm-bytecode/1.11.1: + resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==} + + /@webassemblyjs/helper-wasm-section/1.11.1: + resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + + /@webassemblyjs/ieee754/1.11.1: + resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==} + dependencies: + '@xtuc/ieee754': 1.2.0 + + /@webassemblyjs/leb128/1.11.1: + resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==} + dependencies: + '@xtuc/long': 4.2.2 + + /@webassemblyjs/utf8/1.11.1: + resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==} + + /@webassemblyjs/wasm-edit/1.11.1: + resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/helper-wasm-section': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + '@webassemblyjs/wasm-opt': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + '@webassemblyjs/wast-printer': 1.11.1 + + /@webassemblyjs/wasm-gen/1.11.1: + resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/ieee754': 1.11.1 + '@webassemblyjs/leb128': 1.11.1 + '@webassemblyjs/utf8': 1.11.1 + + /@webassemblyjs/wasm-opt/1.11.1: + resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + + /@webassemblyjs/wasm-parser/1.11.1: + resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-api-error': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/ieee754': 1.11.1 + '@webassemblyjs/leb128': 1.11.1 + '@webassemblyjs/utf8': 1.11.1 + + /@webassemblyjs/wast-printer/1.11.1: + resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@xtuc/long': 4.2.2 + + /@webgpu/types/0.1.16: + resolution: {integrity: sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==} + dev: false + + /@webgpu/types/0.1.21: + resolution: {integrity: sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==} + dev: false + + /@xtuc/ieee754/1.2.0: + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + /@xtuc/long/4.2.2: + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + /abab/2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + dev: false + + /abbrev/1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + /abort-controller/3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + + /accepts/1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + + /acorn-globals/7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + dependencies: + acorn: 8.8.1 + acorn-walk: 8.2.0 + dev: false + + /acorn-import-assertions/1.8.0_acorn@8.8.1: + resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==} + peerDependencies: + acorn: ^8 + dependencies: + acorn: 8.8.1 + + /acorn-jsx/5.3.2_acorn@8.8.1: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.1 + + /acorn-walk/8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: false + + /acorn/7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + /acorn/8.8.1: + resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + engines: {node: '>=0.4.0'} + hasBin: true + + /adm-zip/0.5.10: + resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==} + engines: {node: '>=6.0'} + dev: false + optional: true + + /agent-base/4.3.0: + resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==} + engines: {node: '>= 4.0.0'} + dependencies: + es6-promisify: 5.0.0 + dev: false + optional: true + + /agent-base/6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /agentkeepalive/4.2.1: + resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==} + engines: {node: '>= 8.0.0'} + dependencies: + debug: 4.3.4 + depd: 1.1.2 + humanize-ms: 1.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /aggregate-error/3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + /ajv-keywords/3.5.2_ajv@6.12.6: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + dependencies: + ajv: 6.12.6 + + /ajv/6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + /ajv/8.11.2: + resolution: {integrity: sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + + /alphanum-sort/1.0.2: + resolution: {integrity: sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==} + dev: false + + /ansi-colors/1.1.0: + resolution: {integrity: sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-wrap: 0.1.0 + dev: false + + /ansi-colors/4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + dev: false + + /ansi-colors/4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes/4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-gray/0.1.1: + resolution: {integrity: sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-wrap: 0.1.0 + dev: false + + /ansi-regex/2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + dev: false + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-styles/2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + dev: false + + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-wrap/0.1.0: + resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==} + engines: {node: '>=0.10.0'} + dev: false + + /any-promise/1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + /anymatch/2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + dependencies: + micromatch: 3.1.10 + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /app-root-path/3.1.0: + resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} + engines: {node: '>= 6.0.0'} + dev: false + + /append-buffer/1.0.2: + resolution: {integrity: sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==} + engines: {node: '>=0.10.0'} + dependencies: + buffer-equal: 1.0.1 + dev: false + + /append-field/1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + dev: false + + /aproba/2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: false + + /arch/2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + + /archive-type/4.0.0: + resolution: {integrity: sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==} + engines: {node: '>=4'} + dependencies: + file-type: 4.4.0 + dev: false + + /archiver-utils/2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.10 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.7 + dev: false + + /archiver/5.3.1: + resolution: {integrity: sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.0 + readdir-glob: 1.1.2 + tar-stream: 2.2.0 + zip-stream: 4.1.0 + dev: false + + /archy/1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + + /are-we-there-yet/2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: false + optional: true + + /are-we-there-yet/3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: false + + /arg/4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: false + + /arg/5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse/1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: false + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + /arr-diff/4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + dev: false + + /arr-filter/1.1.2: + resolution: {integrity: sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==} + engines: {node: '>=0.10.0'} + dependencies: + make-iterator: 1.0.1 + dev: false + + /arr-flatten/1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + dev: false + + /arr-map/2.0.2: + resolution: {integrity: sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==} + engines: {node: '>=0.10.0'} + dependencies: + make-iterator: 1.0.1 + dev: false + + /arr-union/3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + dev: false + + /array-each/1.0.1: + resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==} + engines: {node: '>=0.10.0'} + dev: false + + /array-initial/1.1.0: + resolution: {integrity: sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==} + engines: {node: '>=0.10.0'} + dependencies: + array-slice: 1.1.0 + is-number: 4.0.0 + dev: false + + /array-last/1.3.0: + resolution: {integrity: sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 4.0.0 + dev: false + + /array-slice/1.1.0: + resolution: {integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==} + engines: {node: '>=0.10.0'} + dev: false + + /array-sort/1.0.0: + resolution: {integrity: sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==} + engines: {node: '>=0.10.0'} + dependencies: + default-compare: 1.0.0 + get-value: 2.0.6 + kind-of: 5.1.0 + dev: false + + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: false + + /array-unique/0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + dev: false + + /asap/2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + /asn1.js/5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: false + + /asn1/0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + + /assert-never/1.2.1: + resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==} + + /assert-plus/1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + /assign-symbols/1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + dev: false + + /astral-regex/2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /async-done/1.3.2: + resolution: {integrity: sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==} + engines: {node: '>= 0.10'} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + process-nextick-args: 2.0.1 + stream-exhaust: 1.0.2 + + /async-settle/1.0.0: + resolution: {integrity: sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==} + engines: {node: '>= 0.10'} + dependencies: + async-done: 1.3.2 + dev: false + + /async/3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + /at-least-node/1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /atob/2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + dev: false + + /autobind-decorator/2.4.0: + resolution: {integrity: sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==} + engines: {node: '>=8.10', npm: '>=6.4.1'} + dev: false + + /autoprefixer/6.7.7: + resolution: {integrity: sha512-WKExI/eSGgGAkWAO+wMVdFObZV7hQen54UpD1kCCTN3tvlL3W1jL4+lPP/M7MwoP7Q4RHzKtO3JQ4HxYEcd+xQ==} + dependencies: + browserslist: 1.7.7 + caniuse-db: 1.0.30001443 + normalize-range: 0.1.2 + num2fraction: 1.2.2 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /autosize/5.0.2: + resolution: {integrity: sha512-FPVt5ynkqUAA9gcMZnJHka1XfQgr1WNd/yRfIjmj5WGmjua+u5Hl9hn8M2nU5CNy2bEIcj1ZUwXq7IOHsfZG9w==} + dev: false + + /autwh/0.1.0: + resolution: {integrity: sha512-IkGZ4kjVlZMkEmDiVtZpGG3lDGHPqsMBIh4IpQKN7idYOJ5EGedqKPO+ychNqh8zrJEEqYsN0NcBkcmoE2uFAw==} + dependencies: + oauth: 0.9.15 + dev: false + + /available-typed-arrays/1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: false + + /aws-sdk/2.1277.0: + resolution: {integrity: sha512-cEZ0rg0j3STtLX6rba5tHMrV/KrhXKLtSleleF2IdTFzUjqRvxI54Pqc51w2D7tgAPUgEhMB4Q/ruKPqB8w+2Q==} + engines: {node: '>= 10.0.0'} + dependencies: + buffer: 4.9.2 + events: 1.1.1 + ieee754: 1.1.13 + jmespath: 0.16.0 + querystring: 0.2.0 + sax: 1.2.1 + url: 0.10.3 + util: 0.12.5 + uuid: 8.0.0 + xml2js: 0.4.19 + dev: false + + /aws-sign2/0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + /aws4/1.12.0: + resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} + + /axios/0.24.0: + resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} + dependencies: + follow-redirects: 1.15.2 + transitivePeerDependencies: + - debug + dev: false + + /axios/0.25.0_debug@4.3.4: + resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} + dependencies: + follow-redirects: 1.15.2 + transitivePeerDependencies: + - debug + dev: true + + /babel-eslint/10.1.0_eslint@8.31.0: + resolution: {integrity: sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==} + engines: {node: '>=6'} + deprecated: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates. + peerDependencies: + eslint: '>= 4.12.1' + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/parser': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 + eslint: 8.31.0 + eslint-visitor-keys: 1.3.0 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color + dev: false + + /babel-walk/3.0.0-canary-5: + resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} + engines: {node: '>= 10.0.0'} + dependencies: + '@babel/types': 7.20.7 + + /bach/1.2.0: + resolution: {integrity: sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==} + engines: {node: '>= 0.10'} + dependencies: + arr-filter: 1.1.2 + arr-flatten: 1.1.0 + arr-map: 2.0.2 + array-each: 1.0.1 + array-initial: 1.1.0 + array-last: 1.3.0 + async-done: 1.3.2 + async-settle: 1.0.0 + now-and-later: 2.0.1 + dev: false + + /balanced-match/0.4.2: + resolution: {integrity: sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==} + dev: false + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base/0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.0 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + dev: false + + /base32.js/0.0.1: + resolution: {integrity: sha512-EGHIRiegFa62/SsA1J+Xs2tIzludPdzM064N9wjbiEgHnGnJ1V0WEpA4pEwCYT5nDvZk3ubf0shqaCS7k6xeUQ==} + dev: false + + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /bcrypt-pbkdf/1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + dependencies: + tweetnacl: 0.14.5 + + /bcryptjs/2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + dev: false + + /big-integer/1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: false + + /big.js/5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + dev: false + + /bin-check/4.1.0: + resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==} + engines: {node: '>=4'} + dependencies: + execa: 0.7.0 + executable: 4.1.1 + dev: false + + /bin-version-check/4.0.0: + resolution: {integrity: sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==} + engines: {node: '>=6'} + dependencies: + bin-version: 3.1.0 + semver: 5.7.1 + semver-truncate: 1.1.2 + dev: false + + /bin-version/3.1.0: + resolution: {integrity: sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==} + engines: {node: '>=6'} + dependencies: + execa: 1.0.0 + find-versions: 3.2.0 + dev: false + + /bin-wrapper/4.1.0: + resolution: {integrity: sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==} + engines: {node: '>=6'} + dependencies: + bin-check: 4.1.0 + bin-version-check: 4.0.0 + download: 7.1.0 + import-lazy: 3.1.0 + os-filter-obj: 2.0.0 + pify: 4.0.1 + dev: false + + /binary-extensions/2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + /binary/0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + dev: false + + /binaryextensions/2.3.0: + resolution: {integrity: sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==} + engines: {node: '>=0.8'} + dev: false + + /bl/1.2.3: + resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} + dependencies: + readable-stream: 2.3.7 + safe-buffer: 5.2.1 + dev: false + + /bl/4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + + /blob-util/2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + dev: true + + /bluebird/3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + dev: false + + /bluebird/3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + /blurhash/1.1.5: + resolution: {integrity: sha512-a+LO3A2DfxTaTztsmkbLYmUzUeApi0LZuKalwbNmqAHR6HhJGMt1qSV/R3wc+w4DL28holjqO3Bg74aUGavGjg==} + dev: false + + /bmp-js/0.1.0: + resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} + dev: false + + /bn.js/4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /boolbase/1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion/2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces/2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /braces/3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /broadcast-channel/4.19.1: + resolution: {integrity: sha512-CroDV8L4QdMuCHtjs0AATaN2w1rA5e6ca9a3yZATmAs3lbFu3q3QkITkuMS4sQ/NjtZwkVANXLlhgyQfiukBuw==} + dependencies: + '@babel/runtime': 7.20.7 + oblivious-set: 1.1.1 + p-queue: 6.6.2 + rimraf: 3.0.2 + unload: 2.4.1 + dev: false + + /browser-stdout/1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + dev: false + + /browserslist/1.7.7: + resolution: {integrity: sha512-qHJblDE2bXVRYzuDetv/wAeHOJyO97+9wxC1cdCtyzgNuSozOyRCiiLaCR1f71AN66lQdVVBipWm63V+a7bPOw==} + deprecated: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools. + hasBin: true + dependencies: + caniuse-db: 1.0.30001443 + electron-to-chromium: 1.4.284 + dev: false + + /browserslist/4.21.4: + resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001443 + electron-to-chromium: 1.4.284 + node-releases: 2.0.8 + update-browserslist-db: 1.0.10_browserslist@4.21.4 + + /buffer-alloc-unsafe/1.1.0: + resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} + dev: false + + /buffer-alloc/1.2.0: + resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + dependencies: + buffer-alloc-unsafe: 1.1.0 + buffer-fill: 1.0.0 + dev: false + + /buffer-crc32/0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + /buffer-equal-constant-time/1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + dev: false + + /buffer-equal/1.0.1: + resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} + engines: {node: '>=0.4'} + dev: false + + /buffer-fill/1.0.0: + resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + dev: false + + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + /buffer-indexof-polyfill/1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + dev: false + + /buffer-writer/2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + dev: false + + /buffer/4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + dev: false + + /buffer/5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /buffer/6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /buffers/0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + dev: false + + /bufferutil/4.0.7: + resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.6.0 + dev: false + + /bull/4.10.2: + resolution: {integrity: sha512-xa65xtWjQsLqYU/eNaXxq9VRG8xd6qNsQEjR7yjYuae05xKrzbVMVj2QgrYsTMmSs/vsqJjHqHSRRiW1+IkGXQ==} + engines: {node: '>=12'} + dependencies: + cron-parser: 4.7.1 + debuglog: 1.0.1 + get-port: 5.1.1 + ioredis: 5.2.4 + lodash: 4.17.21 + msgpackr: 1.8.1 + p-timeout: 3.2.0 + semver: 7.3.8 + uuid: 8.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /busboy/1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + dev: false + + /bytes/3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: false + + /cacache/16.1.3: + resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.0.3 + infer-owner: 1.0.4 + lru-cache: 7.14.1 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.1.13 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + dev: false + + /cache-base/1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.0 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + dev: false + + /cache-content-type/1.0.1: + resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} + engines: {node: '>= 6.0.0'} + dependencies: + mime-types: 2.1.35 + ylru: 1.3.2 + dev: false + + /cacheable-lookup/5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + dev: false + + /cacheable-lookup/7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + dev: false + + /cacheable-request/10.2.5: + resolution: {integrity: sha512-5RwYYCfzjNPsyJxb/QpaM0bfzx+kw5/YpDhZPm9oMIDntHFQ9YXeyV47ZvzlTE0XrrrbyO2UITJH4GF9eRLdXQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.1 + get-stream: 6.0.1 + http-cache-semantics: 4.1.0 + keyv: 4.5.2 + mimic-response: 4.0.0 + normalize-url: 8.0.0 + responselike: 3.0.0 + dev: false + + /cacheable-request/2.1.4: + resolution: {integrity: sha512-vag0O2LKZ/najSoUwDbVlnlCFvhBE/7mGTY2B5FgCBDcRD+oVV1HYTOwM6JZfMg/hIcM6IwnTZ1uQQL5/X3xIQ==} + dependencies: + clone-response: 1.0.2 + get-stream: 3.0.0 + http-cache-semantics: 3.8.1 + keyv: 3.0.0 + lowercase-keys: 1.0.0 + normalize-url: 2.0.1 + responselike: 1.0.2 + dev: false + + /cacheable-request/7.0.2: + resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} + engines: {node: '>=8'} + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.1.0 + keyv: 4.5.2 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + dev: false + + /cachedir/2.3.0: + resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} + engines: {node: '>=6'} + dev: true + + /calckey-js/0.0.20: + resolution: {integrity: sha512-KqydxFuMKAEmi+NPOpNZfnq5Ik7w2eApY7hc2MxrqIkcuy/lgUv8io4rnNx512fHppEHtV7AVxovU2//buvgZA==} + dependencies: + autobind-decorator: 2.4.0 + eventemitter3: 4.0.7 + reconnecting-websocket: 4.4.0 + semver: 7.3.8 + dev: false + + /call-bind/1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.3 + + /callsites/3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /camelcase/3.0.0: + resolution: {integrity: sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==} + engines: {node: '>=0.10.0'} + dev: false + + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + + /camelcase/6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false + + /caniuse-api/1.6.1: + resolution: {integrity: sha512-SBTl70K0PkDUIebbkXrxWqZlHNs0wRgRD6QZ8guctShjbh63gEPfF+Wj0Yw+75f5Y8tSzqAI/NcisYv/cCah2Q==} + dependencies: + browserslist: 1.7.7 + caniuse-db: 1.0.30001443 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + dev: false + + /caniuse-db/1.0.30001443: + resolution: {integrity: sha512-4KKthVYyooNIOhO1w0OJ13EhEwOGECMrZdkeyDydhvYXaTDA3WdhR8amoJnAgpSgcCR26aOAWk6N9ANVYlv2oQ==} + dev: false + + /caniuse-lite/1.0.30001443: + resolution: {integrity: sha512-jUo8svymO8+Mkj3qbUbVjR8zv8LUGpGkUM/jKvc9SO2BvjCI980dp9fQbf/dyLs6RascPzgR4nhAKFA4OHeSaA==} + + /canonicalize/1.0.8: + resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==} + dev: false + + /caseless/0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + /caw/2.0.1: + resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} + engines: {node: '>=4'} + dependencies: + get-proxy: 2.1.0 + isurl: 1.0.0 + tunnel-agent: 0.6.0 + url-to-options: 1.0.1 + dev: false + + /cbor/8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + + /chainsaw/0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + dependencies: + traverse: 0.3.9 + dev: false + + /chalk-template/0.4.0: + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} + engines: {node: '>=12'} + dependencies: + chalk: 4.1.2 + dev: false + + /chalk/1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + dev: false + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + + /chalk/4.0.0: + resolution: {integrity: sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + /chalk/5.2.0: + resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + + /char-regex/1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: false + + /character-parser/2.2.0: + resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==} + dependencies: + is-regex: 1.1.4 + + /charenc/0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + dev: false + + /chart.js/4.1.1: + resolution: {integrity: sha512-P0pCosNXp+LR8zO/QTkZKT6Hb7p0DPFtypEeVOf+6x06hX13NIb75R0DXUA4Ksx/+48chDQKtCCmRCviQRTqsA==} + engines: {pnpm: ^7.0.0} + dependencies: + '@kurkle/color': 0.3.2 + dev: false + + /chartjs-adapter-date-fns/2.0.1_chart.js@4.1.1: + resolution: {integrity: sha512-v3WV9rdnQ05ce3A0ZCjzUekJCAbfm6+3HqSoeY2BIkdMYZoYr/4T+ril1tZyDl869lz6xdNVMXejUFT9YKpw4A==} + peerDependencies: + chart.js: '>=2.8.0' + dependencies: + chart.js: 4.1.1 + dev: false + + /chartjs-plugin-gradient/0.5.1_chart.js@4.1.1: + resolution: {integrity: sha512-vhwlYGZWan4MGZZ4Wj64Y4aIql1uCPCU1JcggLWn3cgYEv4G7pXp1YgM4XH5ugmyn6BVCgQqAhiJ2h6hppzHmQ==} + peerDependencies: + chart.js: '>=2.6.0' + dependencies: + chart.js: 4.1.1 + dev: false + + /chartjs-plugin-zoom/1.2.1_chart.js@4.1.1: + resolution: {integrity: sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==} + peerDependencies: + chart.js: ^3.2.0 + dependencies: + chart.js: 4.1.1 + hammerjs: 2.0.8 + dev: false + + /check-more-types/2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + dev: true + + /cheerio/0.22.0: + resolution: {integrity: sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==} + engines: {node: '>= 0.6'} + dependencies: + css-select: 1.2.0 + dom-serializer: 0.1.1 + entities: 1.1.2 + htmlparser2: 3.10.1 + lodash.assignin: 4.2.0 + lodash.bind: 4.2.1 + lodash.defaults: 4.2.0 + lodash.filter: 4.6.0 + lodash.flatten: 4.4.0 + lodash.foreach: 4.5.0 + lodash.map: 4.6.0 + lodash.merge: 4.6.2 + lodash.pick: 4.4.0 + lodash.reduce: 4.6.0 + lodash.reject: 4.6.0 + lodash.some: 4.6.0 + dev: false + + /chokidar/3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.2 + + /chownr/1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + + /chownr/2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: false + + /chrome-trace-event/1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + engines: {node: '>=6.0'} + + /ci-info/3.7.1: + resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==} + engines: {node: '>=8'} + dev: true + + /clap/1.2.3: + resolution: {integrity: sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==} + engines: {node: '>=0.10.0'} + dependencies: + chalk: 1.1.3 + dev: false + + /class-utils/0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + dev: false + + /clean-stack/2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + /cli-cursor/3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-highlight/2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + dev: false + + /cli-table3/0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + + /cli-truncate/2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + dev: true + + /cliui/3.2.0: + resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi: 2.1.0 + dev: false + + /cliui/6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /cliui/8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /clone-buffer/1.0.0: + resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==} + engines: {node: '>= 0.10'} + dev: false + + /clone-response/1.0.2: + resolution: {integrity: sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==} + dependencies: + mimic-response: 1.0.1 + dev: false + + /clone-response/1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + dependencies: + mimic-response: 1.0.1 + dev: false + + /clone-stats/1.0.0: + resolution: {integrity: sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==} + dev: false + + /clone/1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: false + + /clone/2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + dev: false + + /cloneable-readable/1.1.3: + resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==} + dependencies: + inherits: 2.0.4 + process-nextick-args: 2.0.1 + readable-stream: 2.3.7 + dev: false + + /cluster-key-slot/1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} + engines: {node: '>=0.10.0'} + dev: true + + /cluster-key-slot/1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + /co-body/5.2.0: + resolution: {integrity: sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==} + dependencies: + inflation: 2.0.0 + qs: 6.10.4 + raw-body: 2.5.1 + type-is: 1.6.18 + dev: false + + /co-body/6.1.0: + resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==} + dependencies: + inflation: 2.0.0 + qs: 6.10.4 + raw-body: 2.5.1 + type-is: 1.6.18 + dev: false + + /co/4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false + + /coa/1.0.4: + resolution: {integrity: sha512-KAGck/eNAmCL0dcT3BiuYwLbExK6lduR8DxM3C1TyDzaXhZHyZ8ooX5I5+na2e3dPFuibfxrGdorr0/Lr7RYCQ==} + engines: {node: '>= 0.8.0'} + dependencies: + q: 1.5.1 + dev: false + + /code-point-at/1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + dev: false + + /collection-map/1.0.0: + resolution: {integrity: sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-map: 2.0.2 + for-own: 1.0.0 + make-iterator: 1.0.1 + dev: false + + /collection-visit/1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + dev: false + + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name/1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-string/0.3.0: + resolution: {integrity: sha512-sz29j1bmSDfoAxKIEU6zwoIZXN6BrFbAMIhfYCNyiZXBDuU/aiHlN84lp/xDzL2ubyFhLDobHIlU1X70XRrMDA==} + dependencies: + color-name: 1.1.4 + dev: false + + /color-string/1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color-support/1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: false + + /color/0.11.4: + resolution: {integrity: sha512-Ajpjd8asqZ6EdxQeqGzU5WBhhTfJ/0cA4Wlbre7e5vXfmDSmda7Ov6jeKoru+b0vHcb1CqvuroTHp5zIWzhVMA==} + dependencies: + clone: 1.0.4 + color-convert: 1.9.3 + color-string: 0.3.0 + dev: false + + /color/4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + dev: false + + /colorette/1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + dev: false + + /colorette/2.0.19: + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + dev: true + + /colormin/1.1.2: + resolution: {integrity: sha512-XSEQUUQUR/lXqGyddiNH3XYFUPYlYr1vXy9rTFMsSOw+J7Q6EQkdlQIrTlYn4TccpsOaUE1PYQNjBn20gwCdgQ==} + dependencies: + color: 0.11.4 + css-color-names: 0.0.4 + has: 1.0.3 + dev: false + + /colors/1.1.2: + resolution: {integrity: sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==} + engines: {node: '>=0.1.90'} + dev: false + + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /commander/2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + /commander/5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + dev: true + + /commander/7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + + /commander/8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + dev: false + + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: false + + /common-tags/1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + + /compare-versions/5.0.3: + resolution: {integrity: sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==} + dev: false + + /component-emitter/1.3.0: + resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} + dev: false + + /compress-commons/4.1.1: + resolution: {integrity: sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==} + engines: {node: '>= 10'} + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.2 + normalize-path: 3.0.0 + readable-stream: 3.6.0 + dev: false + + /concat-map/0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /concat-stream/1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.7 + typedarray: 0.0.6 + dev: false + + /condense-newlines/0.2.1: + resolution: {integrity: sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-whitespace: 0.3.0 + kind-of: 3.2.2 + + /config-chain/1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + /console-control-strings/1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: false + + /consolidate/0.16.0_ejs@3.1.8+pug@3.0.2: + resolution: {integrity: sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==} + engines: {node: '>= 0.10.0'} + peerDependencies: + arc-templates: ^0.5.3 + atpl: '>=0.7.6' + babel-core: ^6.26.3 + bracket-template: ^1.1.5 + coffee-script: ^1.12.7 + dot: ^1.1.3 + dust: ^0.3.0 + dustjs-helpers: ^1.7.4 + dustjs-linkedin: ^2.7.5 + eco: ^1.1.0-rc-3 + ect: ^0.5.9 + ejs: ^3.1.5 + haml-coffee: ^1.14.1 + hamlet: ^0.3.3 + hamljs: ^0.6.2 + handlebars: ^4.7.6 + hogan.js: ^3.0.2 + htmling: ^0.0.8 + jade: ^1.11.0 + jazz: ^0.0.18 + jqtpl: ~1.1.0 + just: ^0.1.8 + liquid-node: ^3.0.1 + liquor: ^0.0.5 + lodash: ^4.17.20 + marko: ^3.14.4 + mote: ^0.2.0 + mustache: ^4.0.1 + nunjucks: ^3.2.2 + plates: ~0.4.11 + pug: ^3.0.0 + qejs: ^3.0.5 + ractive: ^1.3.12 + razor-tmpl: ^1.3.1 + react: ^16.13.1 + react-dom: ^16.13.1 + slm: ^2.0.0 + squirrelly: ^5.1.0 + swig: ^1.4.2 + swig-templates: ^2.0.3 + teacup: ^2.0.0 + templayed: '>=0.2.3' + then-jade: '*' + then-pug: '*' + tinyliquid: ^0.2.34 + toffee: ^0.3.6 + twig: ^1.15.2 + twing: ^5.0.2 + underscore: ^1.11.0 + vash: ^0.13.0 + velocityjs: ^2.0.1 + walrus: ^0.10.1 + whiskers: ^0.4.0 + peerDependenciesMeta: + arc-templates: + optional: true + atpl: + optional: true + babel-core: + optional: true + bracket-template: + optional: true + coffee-script: + optional: true + dot: + optional: true + dust: + optional: true + dustjs-helpers: + optional: true + dustjs-linkedin: + optional: true + eco: + optional: true + ect: + optional: true + ejs: + optional: true + haml-coffee: + optional: true + hamlet: + optional: true + hamljs: + optional: true + handlebars: + optional: true + hogan.js: + optional: true + htmling: + optional: true + jade: + optional: true + jazz: + optional: true + jqtpl: + optional: true + just: + optional: true + liquid-node: + optional: true + liquor: + optional: true + lodash: + optional: true + marko: + optional: true + mote: + optional: true + mustache: + optional: true + nunjucks: + optional: true + plates: + optional: true + pug: + optional: true + qejs: + optional: true + ractive: + optional: true + razor-tmpl: + optional: true + react: + optional: true + react-dom: + optional: true + slm: + optional: true + squirrelly: + optional: true + swig: + optional: true + swig-templates: + optional: true + teacup: + optional: true + templayed: + optional: true + then-jade: + optional: true + then-pug: + optional: true + tinyliquid: + optional: true + toffee: + optional: true + twig: + optional: true + twing: + optional: true + underscore: + optional: true + vash: + optional: true + velocityjs: + optional: true + walrus: + optional: true + whiskers: + optional: true + dependencies: + bluebird: 3.7.2 + ejs: 3.1.8 + pug: 3.0.2 + dev: false + + /consolidate/0.16.0_pug@3.0.2: + resolution: {integrity: sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==} + engines: {node: '>= 0.10.0'} + peerDependencies: + arc-templates: ^0.5.3 + atpl: '>=0.7.6' + babel-core: ^6.26.3 + bracket-template: ^1.1.5 + coffee-script: ^1.12.7 + dot: ^1.1.3 + dust: ^0.3.0 + dustjs-helpers: ^1.7.4 + dustjs-linkedin: ^2.7.5 + eco: ^1.1.0-rc-3 + ect: ^0.5.9 + ejs: ^3.1.5 + haml-coffee: ^1.14.1 + hamlet: ^0.3.3 + hamljs: ^0.6.2 + handlebars: ^4.7.6 + hogan.js: ^3.0.2 + htmling: ^0.0.8 + jade: ^1.11.0 + jazz: ^0.0.18 + jqtpl: ~1.1.0 + just: ^0.1.8 + liquid-node: ^3.0.1 + liquor: ^0.0.5 + lodash: ^4.17.20 + marko: ^3.14.4 + mote: ^0.2.0 + mustache: ^4.0.1 + nunjucks: ^3.2.2 + plates: ~0.4.11 + pug: ^3.0.0 + qejs: ^3.0.5 + ractive: ^1.3.12 + razor-tmpl: ^1.3.1 + react: ^16.13.1 + react-dom: ^16.13.1 + slm: ^2.0.0 + squirrelly: ^5.1.0 + swig: ^1.4.2 + swig-templates: ^2.0.3 + teacup: ^2.0.0 + templayed: '>=0.2.3' + then-jade: '*' + then-pug: '*' + tinyliquid: ^0.2.34 + toffee: ^0.3.6 + twig: ^1.15.2 + twing: ^5.0.2 + underscore: ^1.11.0 + vash: ^0.13.0 + velocityjs: ^2.0.1 + walrus: ^0.10.1 + whiskers: ^0.4.0 + peerDependenciesMeta: + arc-templates: + optional: true + atpl: + optional: true + babel-core: + optional: true + bracket-template: + optional: true + coffee-script: + optional: true + dot: + optional: true + dust: + optional: true + dustjs-helpers: + optional: true + dustjs-linkedin: + optional: true + eco: + optional: true + ect: + optional: true + ejs: + optional: true + haml-coffee: + optional: true + hamlet: + optional: true + hamljs: + optional: true + handlebars: + optional: true + hogan.js: + optional: true + htmling: + optional: true + jade: + optional: true + jazz: + optional: true + jqtpl: + optional: true + just: + optional: true + liquid-node: + optional: true + liquor: + optional: true + lodash: + optional: true + marko: + optional: true + mote: + optional: true + mustache: + optional: true + nunjucks: + optional: true + plates: + optional: true + pug: + optional: true + qejs: + optional: true + ractive: + optional: true + razor-tmpl: + optional: true + react: + optional: true + react-dom: + optional: true + slm: + optional: true + squirrelly: + optional: true + swig: + optional: true + swig-templates: + optional: true + teacup: + optional: true + templayed: + optional: true + then-jade: + optional: true + then-pug: + optional: true + tinyliquid: + optional: true + toffee: + optional: true + twig: + optional: true + twing: + optional: true + underscore: + optional: true + vash: + optional: true + velocityjs: + optional: true + walrus: + optional: true + whiskers: + optional: true + dependencies: + bluebird: 3.7.2 + pug: 3.0.2 + + /constantinople/4.0.1: + resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} + dependencies: + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + + /content-disposition/0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /content-type/1.0.4: + resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} + engines: {node: '>= 0.6'} + dev: false + + /convert-source-map/1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: false + + /cookies/0.8.0: + resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + keygrip: 1.1.0 + dev: false + + /copy-descriptor/0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + dev: false + + /copy-props/2.0.5: + resolution: {integrity: sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==} + dependencies: + each-props: 1.3.2 + is-plain-object: 5.0.0 + dev: false + + /copy-to/2.0.1: + resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==} + dev: false + + /core-js/3.27.1: + resolution: {integrity: sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==} + requiresBuild: true + dev: false + + /core-util-is/1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false + + /crc-32/1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: false + + /crc32-stream/4.0.2: + resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==} + engines: {node: '>= 10'} + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.0 + dev: false + + /create-require/1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: false + + /cron-parser/4.7.1: + resolution: {integrity: sha512-WguFaoQ0hQ61SgsCZLHUcNbAvlK0lypKXu62ARguefYmjzaOXIVRNrAmyXzabTwUn4sQvQLkk6bjH+ipGfw8bA==} + engines: {node: '>=12.0.0'} + dependencies: + luxon: 3.2.1 + dev: false + + /cropperjs/2.0.0-beta.2: + resolution: {integrity: sha512-jDRSODDGKmi9vp3p/+WXkxMqV/AE+GpSld1U3cHZDRdLy9UykRzurSe8k1dR0TExn45ygCMrv31qkg+K3EeXXw==} + dependencies: + '@cropper/elements': 2.0.0-beta.2 + '@cropper/utils': 2.0.0-beta.2 + dev: false + + /cross-env/7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + dependencies: + cross-spawn: 7.0.3 + dev: true + + /cross-spawn/5.1.0: + resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} + dependencies: + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + dev: false + + /cross-spawn/6.0.5: + resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + engines: {node: '>=4.8'} + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.1 + shebang-command: 1.2.0 + which: 1.3.1 + dev: false + + /cross-spawn/7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /crypt/0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + dev: false + + /css-color-names/0.0.4: + resolution: {integrity: sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==} + dev: false + + /css-select/1.2.0: + resolution: {integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==} + dependencies: + boolbase: 1.0.0 + css-what: 2.1.3 + domutils: 1.5.1 + nth-check: 1.0.2 + dev: false + + /css-what/2.1.3: + resolution: {integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==} + dev: false + + /cssnano/3.10.0: + resolution: {integrity: sha512-0o0IMQE0Ezo4b41Yrm8U6Rp9/Ag81vNXY1gZMnT1XhO4DpjEf2utKERqWJbOoz3g1Wdc1d3QSta/cIuJ1wSTEg==} + dependencies: + autoprefixer: 6.7.7 + decamelize: 1.2.0 + defined: 1.0.1 + has: 1.0.3 + object-assign: 4.1.1 + postcss: 5.2.18 + postcss-calc: 5.3.1 + postcss-colormin: 2.2.2 + postcss-convert-values: 2.6.1 + postcss-discard-comments: 2.0.4 + postcss-discard-duplicates: 2.1.0 + postcss-discard-empty: 2.1.0 + postcss-discard-overridden: 0.1.1 + postcss-discard-unused: 2.2.3 + postcss-filter-plugins: 2.0.3 + postcss-merge-idents: 2.1.7 + postcss-merge-longhand: 2.0.2 + postcss-merge-rules: 2.1.2 + postcss-minify-font-values: 1.0.5 + postcss-minify-gradients: 1.0.5 + postcss-minify-params: 1.2.2 + postcss-minify-selectors: 2.1.1 + postcss-normalize-charset: 1.1.1 + postcss-normalize-url: 3.0.8 + postcss-ordered-values: 2.2.3 + postcss-reduce-idents: 2.4.0 + postcss-reduce-initial: 1.0.1 + postcss-reduce-transforms: 1.0.4 + postcss-svgo: 2.1.6 + postcss-unique-selectors: 2.0.2 + postcss-value-parser: 3.3.1 + postcss-zindex: 2.2.0 + dev: false + + /csso/2.3.2: + resolution: {integrity: sha512-FmCI/hmqDeHHLaIQckMhMZneS84yzUZdrWDAvJVVxOwcKE1P1LF9FGmzr1ktIQSxOw6fl3PaQsmfg+GN+VvR3w==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + clap: 1.2.3 + source-map: 0.5.7 + dev: false + + /cssom/0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + dev: false + + /cssom/0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + dev: false + + /cssstyle/2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + dependencies: + cssom: 0.3.8 + dev: false + + /csstype/2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + dev: false + + /csstype/3.1.1: + resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} + dev: false + + /custom-event-polyfill/1.0.7: + resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==} + dev: false + + /cwise-compiler/1.1.3: + resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} + dependencies: + uniq: 1.0.1 + dev: false + + /cypress/10.11.0: + resolution: {integrity: sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==} + engines: {node: '>=12.0.0'} + hasBin: true + requiresBuild: true + dependencies: + '@cypress/request': 2.88.11 + '@cypress/xvfb': 1.2.4_supports-color@8.1.1 + '@types/node': 14.18.36 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.3 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.3.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.3 + commander: 5.1.0 + common-tags: 1.8.2 + dayjs: 1.11.7 + debug: 4.3.4_supports-color@8.1.1 + enquirer: 2.3.6 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1_supports-color@8.1.1 + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0_enquirer@2.3.6 + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.7 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.3.8 + supports-color: 8.1.1 + tmp: 0.2.1 + untildify: 4.0.0 + yauzl: 2.10.0 + dev: true + + /d/1.0.1: + resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + dependencies: + es5-ext: 0.10.62 + type: 1.2.0 + dev: false + + /dashdash/1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + + /data-uri-to-buffer/0.0.3: + resolution: {integrity: sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==} + dev: false + + /data-uri-to-buffer/4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + /data-urls/3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + dev: false + + /date-fns/2.29.3: + resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} + engines: {node: '>=0.11'} + dev: false + + /dayjs/1.11.7: + resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==} + dev: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + + /debug/3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + + /debug/3.2.7_supports-color@8.1.1: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + dev: true + + /debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /debug/4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /debug/4.3.4_supports-color@8.1.1: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /debuglog/1.0.1: + resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} + dev: false + + /decamelize/1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + + /decamelize/4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + dev: false + + /decimal.js/10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + dev: false + + /decode-uri-component/0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + dev: false + + /decompress-response/3.3.0: + resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} + engines: {node: '>=4'} + dependencies: + mimic-response: 1.0.1 + dev: false + + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + + /decompress-tar/4.1.1: + resolution: {integrity: sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==} + engines: {node: '>=4'} + dependencies: + file-type: 5.2.0 + is-stream: 1.1.0 + tar-stream: 1.6.2 + dev: false + + /decompress-tarbz2/4.1.1: + resolution: {integrity: sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==} + engines: {node: '>=4'} + dependencies: + decompress-tar: 4.1.1 + file-type: 6.2.0 + is-stream: 1.1.0 + seek-bzip: 1.0.6 + unbzip2-stream: 1.4.3 + dev: false + + /decompress-targz/4.1.1: + resolution: {integrity: sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==} + engines: {node: '>=4'} + dependencies: + decompress-tar: 4.1.1 + file-type: 5.2.0 + is-stream: 1.1.0 + dev: false + + /decompress-unzip/4.0.1: + resolution: {integrity: sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==} + engines: {node: '>=4'} + dependencies: + file-type: 3.9.0 + get-stream: 2.3.1 + pify: 2.3.0 + yauzl: 2.10.0 + dev: false + + /decompress/4.2.1: + resolution: {integrity: sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==} + engines: {node: '>=4'} + dependencies: + decompress-tar: 4.1.1 + decompress-tarbz2: 4.1.1 + decompress-targz: 4.1.1 + decompress-unzip: 4.0.1 + graceful-fs: 4.2.10 + make-dir: 1.3.0 + pify: 2.3.0 + strip-dirs: 2.1.0 + dev: false + + /deep-email-validator/0.1.21: + resolution: {integrity: sha512-DBAmMzbr+MAubXQ+TS9tZuPwLcdKscb8YzKZiwoLqF3NmaeEgXvSSHhZ0EXOFeKFE2FNWC4mNXCyiQ/JdFXUwg==} + dependencies: + '@types/disposable-email-domains': 1.0.2 + axios: 0.24.0 + disposable-email-domains: 1.0.62 + mailcheck: 1.1.1 + transitivePeerDependencies: + - debug + dev: false + + /deep-equal/1.0.1: + resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==} + dev: false + + /deep-extend/0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + + /deep-is/0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + /deepmerge/4.2.2: + resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} + engines: {node: '>=0.10.0'} + dev: false + + /default-compare/1.0.0: + resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 5.1.0 + dev: false + + /default-resolution/2.0.0: + resolution: {integrity: sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==} + engines: {node: '>= 0.10'} + dev: false + + /defer-to-connect/2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: false + + /define-properties/1.1.4: + resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: false + + /define-property/0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 0.1.6 + dev: false + + /define-property/1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.2 + dev: false + + /define-property/2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.2 + isobject: 3.0.1 + dev: false + + /defined/1.0.1: + resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + dev: false + + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + /delegates/1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: false + + /denque/2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + /depd/1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + + /depd/2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /destroy/1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + + /detect-file/1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + dev: false + + /detect-libc/2.0.1: + resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} + engines: {node: '>=8'} + dev: false + + /diff/4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: false + + /diff/5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + dev: false + + /dijkstrajs/1.0.2: + resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==} + dev: false + + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: false + + /disposable-email-domains/1.0.62: + resolution: {integrity: sha512-LBQvhRw7mznQTPoyZbsmYeNOZt1pN5aCsx4BAU/3siVFuiM9f2oyKzUaB8v1jbxFjE3aYqYiMo63kAL4pHgfWQ==} + dev: false + + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + + /doctypes/1.1.0: + resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} + + /dom-serializer/0.1.1: + resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==} + dependencies: + domelementtype: 1.3.1 + entities: 1.1.2 + dev: false + + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + + /dom7/4.0.4: + resolution: {integrity: sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw==} + dependencies: + ssr-window: 4.0.2 + dev: false + + /domelementtype/1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + dev: false + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + /domexception/4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + dependencies: + webidl-conversions: 7.0.0 + dev: false + + /domhandler/2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + dependencies: + domelementtype: 1.3.1 + dev: false + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + + /domutils/1.5.1: + resolution: {integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + + /domutils/1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + + /domutils/3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + /dotenv/16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + dev: false + + /download/7.1.0: + resolution: {integrity: sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==} + engines: {node: '>=6'} + dependencies: + archive-type: 4.0.0 + caw: 2.0.1 + content-disposition: 0.5.4 + decompress: 4.2.1 + ext-name: 5.0.0 + file-type: 8.1.0 + filenamify: 2.1.0 + get-stream: 3.0.0 + got: 8.3.2 + make-dir: 1.3.0 + p-event: 2.3.1 + pify: 3.0.0 + dev: false + + /duplexer/0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /duplexer2/0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + dependencies: + readable-stream: 2.3.7 + dev: false + + /duplexer3/0.1.5: + resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} + dev: false + + /duplexify/3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.7 + stream-shift: 1.0.1 + dev: false + + /each-props/1.3.2: + resolution: {integrity: sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==} + dependencies: + is-plain-object: 2.0.4 + object.defaults: 1.1.0 + dev: false + + /ecc-jsbn/0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + + /ecdsa-sig-formatter/1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /editorconfig/0.15.3: + resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} + hasBin: true + dependencies: + commander: 2.20.3 + lru-cache: 4.1.5 + semver: 5.7.1 + sigmund: 1.0.1 + + /ee-first/1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + + /ejs/3.1.8: + resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.8.5 + dev: false + + /electron-to-chromium/1.4.284: + resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + /emojis-list/3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + dev: false + + /encode-utf8/1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: false + + /encodeurl/1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + + /encoding/0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + requiresBuild: true + dependencies: + iconv-lite: 0.6.3 + dev: false + optional: true + + /end-of-stream/1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + + /enhanced-resolve/5.12.0: + resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.10 + tapable: 2.2.1 + + /enquirer/2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + dev: true + + /entities/1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + dev: false + + /entities/2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: false + + /entities/4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + + /env-paths/2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: false + + /err-code/2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + dev: false + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + + /es-module-lexer/0.9.3: + resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} + + /es5-ext/0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + engines: {node: '>=0.10'} + requiresBuild: true + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + next-tick: 1.1.0 + dev: false + + /es6-iterator/2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 + dev: false + + /es6-promise/4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + dev: false + optional: true + + /es6-promisify/5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 + dev: false + optional: true + + /es6-symbol/3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + dependencies: + d: 1.0.1 + ext: 1.7.0 + dev: false + + /es6-weak-map/2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + dev: false + + /esbuild/0.16.17: + resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.16.17 + '@esbuild/android-arm64': 0.16.17 + '@esbuild/android-x64': 0.16.17 + '@esbuild/darwin-arm64': 0.16.17 + '@esbuild/darwin-x64': 0.16.17 + '@esbuild/freebsd-arm64': 0.16.17 + '@esbuild/freebsd-x64': 0.16.17 + '@esbuild/linux-arm': 0.16.17 + '@esbuild/linux-arm64': 0.16.17 + '@esbuild/linux-ia32': 0.16.17 + '@esbuild/linux-loong64': 0.16.17 + '@esbuild/linux-mips64el': 0.16.17 + '@esbuild/linux-ppc64': 0.16.17 + '@esbuild/linux-riscv64': 0.16.17 + '@esbuild/linux-s390x': 0.16.17 + '@esbuild/linux-x64': 0.16.17 + '@esbuild/netbsd-x64': 0.16.17 + '@esbuild/openbsd-x64': 0.16.17 + '@esbuild/sunos-x64': 0.16.17 + '@esbuild/win32-arm64': 0.16.17 + '@esbuild/win32-ia32': 0.16.17 + '@esbuild/win32-x64': 0.16.17 + dev: false + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + /escape-html/1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false + + /escape-regexp/0.0.1: + resolution: {integrity: sha512-jVgdsYRa7RKxTT6MKNC3gdT+BF0Gfhpel19+HMRZJC2L0PufB0XOBuXBoXj29NKHwuktnAXd1Z1lyiH/8vOTpw==} + dev: false + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + /escodegen/2.0.0: + resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + dev: false + + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + /eslint-utils/3.0.0_eslint@8.31.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.31.0 + eslint-visitor-keys: 2.1.0 + + /eslint-visitor-keys/1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + dev: false + + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /eslint/8.31.0: + resolution: {integrity: sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.31.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.19.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.2.0 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.1 + acorn-jsx: 5.3.2_acorn@8.8.1 + eslint-visitor-keys: 3.3.0 + + /esprima/2.7.3: + resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} + engines: {node: '>=0.10.0'} + hasBin: true + dev: false + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /esquery/1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + + /esrecurse/4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + + /estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + /estree-walker/1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + dev: false + + /estree-walker/2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: false + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + /event-stream/3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /event-target-shim/5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + + /eventemitter2/6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + dev: true + + /eventemitter3/4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + + /events/1.1.1: + resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} + engines: {node: '>=0.4.x'} + dev: false + + /events/3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + /execa/0.7.0: + resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==} + engines: {node: '>=4'} + dependencies: + cross-spawn: 5.1.0 + get-stream: 3.0.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + dev: false + + /execa/1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + dependencies: + cross-spawn: 6.0.5 + get-stream: 4.1.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + dev: false + + /execa/4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa/5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + /execa/6.1.0: + resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 3.0.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + + /executable/4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + dependencies: + pify: 2.3.0 + + /executioner/2.0.1: + resolution: {integrity: sha512-idZAlKsxEZASjaIqP4PQ1txyS1bOcDwWCHy/8p5oMmLGV0XNCQPD6WWAOwJCUVsWItWzAN2BEash5N78PliaIw==} + dependencies: + mixly: 1.0.0 + dev: true + + /expand-brackets/2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /expand-template/2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + + /expand-tilde/2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + dependencies: + homedir-polyfill: 1.0.3 + dev: false + + /ext-list/2.2.2: + resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} + engines: {node: '>=0.10.0'} + dependencies: + mime-db: 1.52.0 + dev: false + + /ext-name/5.0.0: + resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==} + engines: {node: '>=4'} + dependencies: + ext-list: 2.2.2 + sort-keys-length: 1.0.1 + dev: false + + /ext/1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + dependencies: + type: 2.7.2 + dev: false + + /extend-shallow/2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + + /extend-shallow/3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + dev: false + + /extend/3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + /extglob/2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /extract-zip/2.0.1_supports-color@8.1.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4_supports-color@8.1.1 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.0 + transitivePeerDependencies: + - supports-color + dev: true + + /extsprintf/1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + /fancy-log/1.3.3: + resolution: {integrity: sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==} + engines: {node: '>= 0.10'} + dependencies: + ansi-gray: 0.1.1 + color-support: 1.1.3 + parse-node-version: 1.0.1 + time-stamp: 1.1.0 + dev: false + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + /fast-glob/3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: false + + /fast-json-stable-stringify/2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + /fast-levenshtein/1.1.4: + resolution: {integrity: sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==} + dev: false + + /fast-levenshtein/2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + /fast-xml-parser/3.21.1: + resolution: {integrity: sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + + /fastq/1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + + /fd-slicer/1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + + /feed/4.2.2: + resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} + engines: {node: '>=0.4.0'} + dependencies: + xml-js: 1.6.11 + dev: false + + /fetch-blob/3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.2.1 + + /figures/3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + + /file-type/12.4.2: + resolution: {integrity: sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==} + engines: {node: '>=8'} + dev: false + + /file-type/17.1.6: + resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + readable-web-to-node-stream: 3.0.2 + strtok3: 7.0.0 + token-types: 5.0.1 + dev: false + + /file-type/3.9.0: + resolution: {integrity: sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==} + engines: {node: '>=0.10.0'} + dev: false + + /file-type/4.4.0: + resolution: {integrity: sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==} + engines: {node: '>=4'} + dev: false + + /file-type/5.2.0: + resolution: {integrity: sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==} + engines: {node: '>=4'} + dev: false + + /file-type/6.2.0: + resolution: {integrity: sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==} + engines: {node: '>=4'} + dev: false + + /file-type/8.1.0: + resolution: {integrity: sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==} + engines: {node: '>=6'} + dev: false + + /filelist/1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.1.2 + dev: false + + /filename-reserved-regex/2.0.0: + resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} + engines: {node: '>=4'} + dev: false + + /filenamify/2.1.0: + resolution: {integrity: sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==} + engines: {node: '>=4'} + dependencies: + filename-reserved-regex: 2.0.0 + strip-outer: 1.0.1 + trim-repeated: 1.0.0 + dev: false + + /fill-range/4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + dev: false + + /fill-range/7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /find-up/1.1.2: + resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} + engines: {node: '>=0.10.0'} + dependencies: + path-exists: 2.1.0 + pinkie-promise: 2.0.1 + dev: false + + /find-up/4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: false + + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + /find-versions/3.2.0: + resolution: {integrity: sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==} + engines: {node: '>=6'} + dependencies: + semver-regex: 2.0.0 + dev: false + + /findup-sync/2.0.0: + resolution: {integrity: sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==} + engines: {node: '>= 0.10'} + dependencies: + detect-file: 1.0.0 + is-glob: 3.1.0 + micromatch: 3.1.10 + resolve-dir: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /findup-sync/3.0.0: + resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==} + engines: {node: '>= 0.10'} + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 3.1.10 + resolve-dir: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /fined/1.2.0: + resolution: {integrity: sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==} + engines: {node: '>= 0.10'} + dependencies: + expand-tilde: 2.0.2 + is-plain-object: 2.0.4 + object.defaults: 1.1.0 + object.pick: 1.3.0 + parse-filepath: 1.0.2 + dev: false + + /flagged-respawn/1.0.1: + resolution: {integrity: sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==} + engines: {node: '>= 0.10'} + dev: false + + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + + /flat/5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: false + + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + + /flatten/1.0.3: + resolution: {integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==} + deprecated: flatten is deprecated in favor of utility frameworks such as lodash. + dev: false + + /fluent-ffmpeg/2.1.2: + resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==} + engines: {node: '>=0.8.0'} + dependencies: + async: 3.2.4 + which: 1.3.1 + dev: false + + /flush-write-stream/1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.7 + dev: false + + /follow-redirects/1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + /for-each/0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: false + + /for-in/1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + dev: false + + /for-own/1.0.0: + resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 1.0.2 + dev: false + + /forever-agent/0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + /form-data-encoder/2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + dev: false + + /form-data/2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + /form-data/3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /formdata-polyfill/4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + dependencies: + fetch-blob: 3.2.0 + + /fragment-cache/0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + dependencies: + map-cache: 0.2.2 + dev: false + + /fresh/0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + + /from/0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /from2/2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.7 + dev: false + + /fs-constants/1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-extra/9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs-minipass/1.2.7: + resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} + dependencies: + minipass: 2.9.0 + dev: false + optional: true + + /fs-minipass/2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: false + + /fs-mkdirp-stream/1.0.0: + resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==} + engines: {node: '>= 0.10'} + dependencies: + graceful-fs: 4.2.10 + through2: 2.0.5 + dev: false + + /fs.realpath/1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + /fstream/1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + dependencies: + graceful-fs: 4.2.10 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.7.1 + dev: false + + /fulcon/1.0.2: + resolution: {integrity: sha512-vYwUBqbdo9XK0NmN7cFmURmy2T1YHpEsTCbxGO3aErxx6a0Z/HkWXcqcPkk7yOuJ74mSAHGWGBSBBd6v3GKebA==} + engines: {node: '>= 0.10'} + dev: true + + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + /gauge/3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + optional: true + + /gauge/4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + + /generic-pool/3.9.0: + resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} + engines: {node: '>= 4'} + dev: true + + /get-caller-file/1.0.3: + resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} + dev: false + + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + + /get-intrinsic/1.1.3: + resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + + /get-paths/0.0.7: + resolution: {integrity: sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==} + engines: {node: '>=6.4'} + dependencies: + pify: 4.0.1 + + /get-pixels-frame-info-update/3.3.2: + resolution: {integrity: sha512-LzVij57X/gK4Y6LpcDdqj+R9WCpD6Sv3ZH85GMA+S3xgPGCz81mHql4GiSnF4GijRjk7TE0ja2sDr8FFYKLe2g==} + dependencies: + data-uri-to-buffer: 0.0.3 + jpeg-js: 0.3.7 + mime-types: 2.1.35 + ndarray: 1.0.19 + ndarray-pack: 1.2.1 + node-bitmap: 0.0.1 + omggif: 1.0.10 + parse-data-uri: 0.2.0 + pngjs: 3.4.0 + request: 2.88.2 + through: 2.3.8 + dev: false + + /get-port/5.1.1: + resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} + engines: {node: '>=8'} + dev: false + + /get-proxy/2.1.0: + resolution: {integrity: sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==} + engines: {node: '>=4'} + dependencies: + npm-conf: 1.1.3 + dev: false + + /get-stream/2.3.1: + resolution: {integrity: sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==} + engines: {node: '>=0.10.0'} + dependencies: + object-assign: 4.1.1 + pinkie-promise: 2.0.1 + dev: false + + /get-stream/3.0.0: + resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} + engines: {node: '>=4'} + dev: false + + /get-stream/4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + dependencies: + pump: 3.0.0 + dev: false + + /get-stream/5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + + /get-stream/6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + /get-value/2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + dev: false + + /getos/3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + dependencies: + async: 3.2.4 + dev: true + + /getpass/0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + dependencies: + assert-plus: 1.0.0 + + /gif-encoder/0.4.1: + resolution: {integrity: sha512-++rNGpDBgWQ9eXj9JfTBLHMUEd7lDOdzIvFyHQM9yL8ffxkcg4G6jWmsgu/r59Uq6nHc3wcVwtgy3geLnIWunQ==} + engines: {node: '>= 0.8.0'} + dependencies: + readable-stream: 1.1.14 + dev: false + + /github-from-package/0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + + /glob-parent/3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + dev: false + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob-stream/6.1.0: + resolution: {integrity: sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==} + engines: {node: '>= 0.10'} + dependencies: + extend: 3.0.2 + glob: 7.2.3 + glob-parent: 3.1.0 + is-negated-glob: 1.0.0 + ordered-read-streams: 1.0.1 + pumpify: 1.5.1 + readable-stream: 2.3.7 + remove-trailing-separator: 1.1.0 + to-absolute-glob: 2.0.2 + unique-stream: 2.3.1 + dev: false + + /glob-to-regexp/0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + /glob-watcher/5.0.5: + resolution: {integrity: sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==} + engines: {node: '>= 0.10'} + dependencies: + anymatch: 2.0.0 + async-done: 1.3.2 + chokidar: 3.5.3 + is-negated-glob: 1.0.0 + just-debounce: 1.1.0 + normalize-path: 3.0.0 + object.defaults: 1.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /glob/7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /glob/7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + /glob/8.0.3: + resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.2 + once: 1.4.0 + + /global-dirs/3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /global-modules/1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + dev: false + + /global-prefix/1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + dev: false + + /globals/11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: false + + /globals/13.19.0: + resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + + /globby/11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: false + + /glogg/1.0.2: + resolution: {integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==} + engines: {node: '>= 0.10'} + dependencies: + sparkles: 1.0.1 + dev: false + + /google-protobuf/3.21.2: + resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==} + dev: false + optional: true + + /gopd/1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.1.3 + dev: false + + /got/11.8.5: + resolution: {integrity: sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==} + engines: {node: '>=10.19.0'} + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.0 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.2 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + dev: false + + /got/12.5.3: + resolution: {integrity: sha512-8wKnb9MGU8IPGRIo+/ukTy9XLJBwDiCpIf5TVzQ9Cpol50eMTpBq2GAuDsuDIz7hTYmZgMgC1e9ydr6kSDWs3w==} + engines: {node: '>=14.16'} + dependencies: + '@sindresorhus/is': 5.3.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.5 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.0 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: false + + /got/8.3.2: + resolution: {integrity: sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==} + engines: {node: '>=4'} + dependencies: + '@sindresorhus/is': 0.7.0 + '@types/keyv': 3.1.4 + '@types/responselike': 1.0.0 + cacheable-request: 2.1.4 + decompress-response: 3.3.0 + duplexer3: 0.1.5 + get-stream: 3.0.0 + into-stream: 3.1.0 + is-retry-allowed: 1.2.0 + isurl: 1.0.0 + lowercase-keys: 1.0.1 + mimic-response: 1.0.1 + p-cancelable: 0.4.1 + p-timeout: 2.0.1 + pify: 3.0.0 + safe-buffer: 5.2.1 + timed-out: 4.0.1 + url-parse-lax: 3.0.0 + url-to-options: 1.0.1 + dev: false + + /graceful-fs/4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + /grapheme-splitter/1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + /gulp-cli/2.3.0: + resolution: {integrity: sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + ansi-colors: 1.1.0 + archy: 1.0.0 + array-sort: 1.0.0 + color-support: 1.1.3 + concat-stream: 1.6.2 + copy-props: 2.0.5 + fancy-log: 1.3.3 + gulplog: 1.0.0 + interpret: 1.4.0 + isobject: 3.0.1 + liftoff: 3.1.0 + matchdep: 2.0.0 + mute-stdout: 1.0.1 + pretty-hrtime: 1.0.3 + replace-homedir: 1.0.0 + semver-greatest-satisfied-range: 1.1.0 + v8flags: 3.2.0 + yargs: 7.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /gulp-cssnano/2.1.3: + resolution: {integrity: sha512-r8qdX5pTXsBb/IRm9loE8Ijz8UiPW/URMC/bKJe4FPNHRaz4aEx8Bev03L0FYHd/7BSGu/ebmfumAkpGuTdenA==} + dependencies: + buffer-from: 1.1.2 + cssnano: 3.10.0 + object-assign: 4.1.1 + plugin-error: 1.0.1 + vinyl-sourcemaps-apply: 0.2.1 + dev: false + + /gulp-rename/2.0.0: + resolution: {integrity: sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==} + engines: {node: '>=4'} + dev: false + + /gulp-replace/1.1.4: + resolution: {integrity: sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==} + engines: {node: '>=10'} + dependencies: + '@types/node': 18.11.18 + '@types/vinyl': 2.0.7 + istextorbinary: 3.3.0 + replacestream: 4.0.3 + yargs-parser: 21.1.1 + dev: false + + /gulp-terser/2.1.0: + resolution: {integrity: sha512-lQ3+JUdHDVISAlUIUSZ/G9Dz/rBQHxOiYDQ70IVWFQeh4b33TC1MCIU+K18w07PS3rq/CVc34aQO4SUbdaNMPQ==} + engines: {node: '>=10'} + dependencies: + plugin-error: 1.0.1 + terser: 5.16.1 + through2: 4.0.2 + vinyl-sourcemaps-apply: 0.2.1 + dev: false + + /gulp/4.0.2: + resolution: {integrity: sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + glob-watcher: 5.0.5 + gulp-cli: 2.3.0 + undertaker: 1.3.0 + vinyl-fs: 3.0.3 + transitivePeerDependencies: + - supports-color + dev: false + + /gulplog/1.0.0: + resolution: {integrity: sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==} + engines: {node: '>= 0.10'} + dependencies: + glogg: 1.0.2 + dev: false + + /hammerjs/2.0.8: + resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} + engines: {node: '>=0.8.0'} + dev: false + + /har-schema/2.0.0: + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} + dev: false + + /har-validator/5.1.5: + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} + deprecated: this library is no longer supported + dependencies: + ajv: 6.12.6 + har-schema: 2.0.0 + dev: false + + /has-ansi/2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: false + + /has-flag/1.0.0: + resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} + engines: {node: '>=0.10.0'} + dev: false + + /has-flag/3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors/1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.1.3 + dev: false + + /has-symbol-support-x/1.4.2: + resolution: {integrity: sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==} + dev: false + + /has-symbols/1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + /has-to-string-tag-x/1.4.1: + resolution: {integrity: sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==} + dependencies: + has-symbol-support-x: 1.4.2 + dev: false + + /has-tostringtag/1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + + /has-unicode/2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: false + + /has-value/0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + dev: false + + /has-value/1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + dev: false + + /has-values/0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + dev: false + + /has-values/1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + dev: false + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + + /he/1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: false + + /highlight.js/10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + dev: false + + /homedir-polyfill/1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + dependencies: + parse-passwd: 1.0.0 + dev: false + + /hosted-git-info/2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: false + + /hpagent/0.1.2: + resolution: {integrity: sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==} + dev: false + + /html-comment-regex/1.1.2: + resolution: {integrity: sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==} + dev: false + + /html-encoding-sniffer/3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + dependencies: + whatwg-encoding: 2.0.0 + dev: false + + /html-entities/2.3.2: + resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==} + dev: false + + /htmlparser2/3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + + /htmlparser2/8.0.1: + resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + entities: 4.4.0 + + /http-assert/1.5.0: + resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==} + engines: {node: '>= 0.8'} + dependencies: + deep-equal: 1.0.1 + http-errors: 1.8.1 + dev: false + + /http-cache-semantics/3.8.1: + resolution: {integrity: sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==} + dev: false + + /http-cache-semantics/4.1.0: + resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==} + dev: false + + /http-errors/1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + + /http-errors/1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + + /http-errors/2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + + /http-proxy-agent/5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /http-signature/1.2.0: + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.17.0 + dev: false + + /http-signature/1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.17.0 + dev: true + + /http2-wrapper/1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: false + + /http2-wrapper/2.2.0: + resolution: {integrity: sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: false + + /http_ece/1.1.0: + resolution: {integrity: sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA==} + engines: {node: '>=4'} + dependencies: + urlsafe-base64: 1.0.0 + dev: false + + /https-proxy-agent/2.2.4: + resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==} + engines: {node: '>= 4.5.0'} + dependencies: + agent-base: 4.3.0 + debug: 3.2.7 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /https-proxy-agent/5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /human-signals/1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + dev: true + + /human-signals/2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + /human-signals/3.0.1: + resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} + engines: {node: '>=12.20.0'} + dev: true + + /humanize-ms/1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + dev: false + + /humanize-number/0.0.2: + resolution: {integrity: sha512-un3ZAcNQGI7RzaWGZzQDH47HETM4Wrj6z6E4TId8Yeq9w5ZKUVB1nrT2jwFheTUjEmqcgTjXDc959jum+ai1kQ==} + dev: false + + /iconv-lite/0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /iconv-lite/0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /idb-keyval/3.2.0: + resolution: {integrity: sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ==} + dev: false + + /idb-keyval/6.2.0: + resolution: {integrity: sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng==} + dependencies: + safari-14-idb-fix: 3.0.0 + dev: false + + /ieee754/1.1.13: + resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} + dev: false + + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /ignore/5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + /immutable/4.2.2: + resolution: {integrity: sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==} + dev: false + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /import-lazy/3.1.0: + resolution: {integrity: sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==} + engines: {node: '>=6'} + dev: false + + /imurmurhash/0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + /indexes-of/1.0.1: + resolution: {integrity: sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==} + dev: false + + /infer-owner/1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + dev: false + + /inflation/2.0.0: + resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==} + engines: {node: '>= 0.8.0'} + dev: false + + /inflight/1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits/2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + /ini/2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /insert-text-at-cursor/0.3.0: + resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==} + dev: false + + /install-artifact-from-github/1.3.2: + resolution: {integrity: sha512-yCFcLvqk0yQdxx0uJz4t9Z3adDMLAYrcGYv546uRXCSvxE+GqNYhhz/KmrGcUKGI/gVLR9n/e/zM9jX/+ASMJQ==} + hasBin: true + dev: false + + /install-peers/1.0.4: + resolution: {integrity: sha512-0POFG2zRn/rt0uO1tUekCDhq6t6l3HDjxR42+Hcbjmj75Gv4yuqEfMe63HC76piO1lsctAp/cQW+Ny+i/SxTlg==} + requiresBuild: true + dependencies: + executioner: 2.0.1 + dev: true + + /interpret/1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: false + + /into-stream/3.1.0: + resolution: {integrity: sha512-TcdjPibTksa1NQximqep2r17ISRiNE9fwlfbg3F8ANdvP5/yrFTew86VcO//jk4QTaMlbjypPBq76HN2zaKfZQ==} + engines: {node: '>=4'} + dependencies: + from2: 2.3.0 + p-is-promise: 1.1.0 + dev: false + + /invert-kv/1.0.0: + resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} + engines: {node: '>=0.10.0'} + dev: false + + /ioredis/5.2.4: + resolution: {integrity: sha512-qIpuAEt32lZJQ0XyrloCRdlEdUUNGG9i0UOk6zgzK6igyudNWqEBxfH6OlbnOOoBBvr1WB02mm8fR55CnikRng==} + engines: {node: '>=12.22.0'} + dependencies: + '@ioredis/commands': 1.2.0 + cluster-key-slot: 1.1.2 + debug: 4.3.4 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + /iota-array/1.0.0: + resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} + dev: false + + /ip-address/7.1.0: + resolution: {integrity: sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==} + engines: {node: '>= 10'} + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.2 + dev: false + + /ip-cidr/3.0.11: + resolution: {integrity: sha512-6pf3APV0cRWy7vk0ealQt7UeWPqpT4RQM0bR0miVY/XRiBV8hIkPSkEHctv1+GAUPIwT9qpUL57deYlYca9UEA==} + engines: {node: '>=10.0.0'} + dependencies: + ip-address: 7.1.0 + jsbn: 1.1.0 + dev: false + + /ip-regex/4.3.0: + resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} + engines: {node: '>=8'} + dev: false + + /ip/2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: false + + /ipaddr.js/2.0.1: + resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==} + engines: {node: '>= 10'} + dev: false + + /is-absolute-url/2.1.0: + resolution: {integrity: sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==} + engines: {node: '>=0.10.0'} + dev: false + + /is-absolute/1.0.0: + resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} + engines: {node: '>=0.10.0'} + dependencies: + is-relative: 1.0.0 + is-windows: 1.0.2 + dev: false + + /is-accessor-descriptor/0.1.6: + resolution: {integrity: sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /is-accessor-descriptor/1.0.0: + resolution: {integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 6.0.3 + dev: false + + /is-arguments/1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: false + + /is-arrayish/0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + + /is-arrayish/0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + + /is-binary-path/2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + + /is-buffer/1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + /is-callable/1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: false + + /is-ci/3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.7.1 + dev: true + + /is-core-module/2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + dependencies: + has: 1.0.3 + + /is-data-descriptor/0.1.4: + resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /is-data-descriptor/1.0.0: + resolution: {integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 6.0.3 + dev: false + + /is-descriptor/0.1.6: + resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==} + engines: {node: '>=0.10.0'} + dependencies: + is-accessor-descriptor: 0.1.6 + is-data-descriptor: 0.1.4 + kind-of: 5.1.0 + dev: false + + /is-descriptor/1.0.2: + resolution: {integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==} + engines: {node: '>=0.10.0'} + dependencies: + is-accessor-descriptor: 1.0.0 + is-data-descriptor: 1.0.0 + kind-of: 6.0.3 + dev: false + + /is-electron/2.2.1: + resolution: {integrity: sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==} + dev: false + + /is-expression/4.0.0: + resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==} + dependencies: + acorn: 7.4.1 + object-assign: 4.1.1 + + /is-extendable/0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + /is-extendable/1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + dependencies: + is-plain-object: 2.0.4 + dev: false + + /is-extglob/2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point/1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + dependencies: + number-is-nan: 1.0.1 + dev: false + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + /is-generator-function/1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: false + + /is-glob/3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: false + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-installed-globally/0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-ip/3.1.0: + resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==} + engines: {node: '>=8'} + dependencies: + ip-regex: 4.3.0 + dev: false + + /is-lambda/1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + dev: false + + /is-natural-number/4.0.1: + resolution: {integrity: sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==} + dev: false + + /is-negated-glob/1.0.0: + resolution: {integrity: sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==} + engines: {node: '>=0.10.0'} + dev: false + + /is-number/3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /is-number/4.0.0: + resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==} + engines: {node: '>=0.10.0'} + dev: false + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-object/1.0.2: + resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==} + dev: false + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + /is-plain-obj/1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: false + + /is-plain-obj/2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + dev: false + + /is-plain-object/2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: false + + /is-plain-object/5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: false + + /is-potential-custom-element-name/1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: false + + /is-promise/2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + + /is-regex/1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + + /is-relative/1.0.0: + resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} + engines: {node: '>=0.10.0'} + dependencies: + is-unc-path: 1.0.0 + dev: false + + /is-retry-allowed/1.2.0: + resolution: {integrity: sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==} + engines: {node: '>=0.10.0'} + dev: false + + /is-stream/1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + dev: false + + /is-stream/2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + /is-stream/3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-svg/2.1.0: + resolution: {integrity: sha512-Ya1giYJUkcL/94quj0+XGcmts6cETPBW1MiFz1ReJrnDJ680F52qpAEGAEGU0nq96FRGIGPx6Yo1CyPXcOoyGw==} + engines: {node: '>=0.10.0'} + dependencies: + html-comment-regex: 1.1.2 + dev: false + + /is-svg/4.3.2: + resolution: {integrity: sha512-mM90duy00JGMyjqIVHu9gNTjywdZV+8qNasX8cm/EEYZ53PHDgajvbBwNVvty5dwSAxLUD3p3bdo+7sR/UMrpw==} + engines: {node: '>=6'} + dependencies: + fast-xml-parser: 3.21.1 + dev: false + + /is-typed-array/1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: false + + /is-typedarray/1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + /is-unc-path/1.0.0: + resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} + engines: {node: '>=0.10.0'} + dependencies: + unc-path-regex: 0.1.2 + dev: false + + /is-unicode-supported/0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + /is-url/1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + dev: false + + /is-utf8/0.2.1: + resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} + dev: false + + /is-valid-glob/1.0.0: + resolution: {integrity: sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==} + engines: {node: '>=0.10.0'} + dev: false + + /is-whitespace/0.3.0: + resolution: {integrity: sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==} + engines: {node: '>=0.10.0'} + + /is-windows/1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: false + + /isarray/0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + dev: false + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /isobject/2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + dependencies: + isarray: 1.0.0 + dev: false + + /isobject/3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + dev: false + + /isstream/0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + + /istextorbinary/3.3.0: + resolution: {integrity: sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==} + engines: {node: '>=8'} + dependencies: + binaryextensions: 2.3.0 + textextensions: 3.3.0 + dev: false + + /isurl/1.0.0: + resolution: {integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==} + engines: {node: '>= 4'} + dependencies: + has-to-string-tag-x: 1.4.1 + is-object: 1.0.2 + dev: false + + /jake/10.8.5: + resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.4 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: false + + /jest-worker/27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 18.11.18 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + /jmespath/0.16.0: + resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} + engines: {node: '>= 0.6.0'} + dev: false + + /joi/17.7.0: + resolution: {integrity: sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + + /jpeg-js/0.3.7: + resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==} + dev: false + + /jpeg-js/0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + dev: false + + /js-base64/2.6.4: + resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} + dev: false + + /js-beautify/1.14.7: + resolution: {integrity: sha512-5SOX1KXPFKx+5f6ZrPsIPEY7NwKeQz47n3jm2i+XeHx9MoRsfQenlOP13FQhWvg8JRS0+XLO6XYUQ2GX+q+T9A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + config-chain: 1.1.13 + editorconfig: 0.15.3 + glob: 8.0.3 + nopt: 6.0.0 + + /js-levenshtein/1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + dev: false + + /js-sdsl/4.2.0: + resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} + + /js-stringify/1.0.2: + resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + + /js-yaml/3.7.0: + resolution: {integrity: sha512-eIlkGty7HGmntbV6P/ZlAsoncFLGsNoM27lkTzS+oneY/EiNhj+geqD9ezg/ip+SW6Var0BJU2JtV0vEUZpWVQ==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 2.7.3 + dev: false + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + + /jsbn/0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + /jsbn/1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + dev: false + + /jschardet/3.0.0: + resolution: {integrity: sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==} + engines: {node: '>=0.1.90'} + dev: false + + /jsdom/20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.8.1 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.0.0 + form-data: 4.0.0 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.2 + parse5: 7.1.2 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.2 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.11.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /jsesc/2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /json-buffer/3.0.0: + resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} + dev: false + + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: false + + /json-parse-even-better-errors/2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + /json-schema-traverse/0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + /json-schema-traverse/1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: false + + /json-schema/0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + /json-stringify-safe/5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + /json5-loader/4.0.1_webpack@5.75.0: + resolution: {integrity: sha512-c9viNZlZTz0MTIcf/4qvek5Dz1/PU3DNCB4PwUhlEZIV3qb1bSD6vQQymlV17/Wm6ncra1aCvmIPsuRj+KfEEg==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + dependencies: + json5: 2.2.3 + loader-utils: 2.0.4 + schema-utils: 3.1.1 + webpack: 5.75.0_@swc+core@1.3.26 + dev: false + + /json5/2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: false + + /jsonfile/4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.10 + dev: false + + /jsonfile/5.0.0: + resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==} + dependencies: + universalify: 0.1.2 + optionalDependencies: + graceful-fs: 4.2.10 + dev: false + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.10 + dev: true + + /jsonld/6.0.0: + resolution: {integrity: sha512-1SkN2RXhMCTCSkX+bzHvr9ycM2HTmjWyV41hn2xG7k6BqlCgRjw0zHmuqfphjBRPqi1gKMIqgBCe/0RZMcWrAA==} + engines: {node: '>=14'} + dependencies: + '@digitalbazaar/http-client': 3.2.0 + canonicalize: 1.0.8 + lru-cache: 6.0.0 + rdf-canonize: 3.3.0 + transitivePeerDependencies: + - web-streams-polyfill + dev: false + + /jsprim/1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: false + + /jsprim/2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: true + + /jsrsasign/10.6.1: + resolution: {integrity: sha512-emiQ05haY9CRj1Ho/LiuCqr/+8RgJuWdiHYNglIg2Qjfz0n+pnUq9I2QHplXuOMO2EnAW1oCGC1++aU5VoWSlw==} + dev: false + + /jstransformer/1.0.0: + resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==} + dependencies: + is-promise: 2.2.2 + promise: 7.3.1 + + /just-debounce/1.1.0: + resolution: {integrity: sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==} + dev: false + + /jwa/2.0.0: + resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + + /jws/4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + dependencies: + jwa: 2.0.0 + safe-buffer: 5.2.1 + dev: false + + /katex/0.16.4: + resolution: {integrity: sha512-WudRKUj8yyBeVDI4aYMNxhx5Vhh2PjpzQw1GRu/LVGqL4m1AxwD1GcUp0IMbdJaf5zsjtj8ghP0DOQRYhroNkw==} + hasBin: true + dependencies: + commander: 8.3.0 + dev: false + + /keygrip/1.1.0: + resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} + engines: {node: '>= 0.6'} + dependencies: + tsscmp: 1.0.6 + dev: false + + /keyv/3.0.0: + resolution: {integrity: sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==} + dependencies: + json-buffer: 3.0.0 + dev: false + + /keyv/4.5.2: + resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==} + dependencies: + json-buffer: 3.0.1 + dev: false + + /kind-of/3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + + /kind-of/4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + dev: false + + /kind-of/5.1.0: + resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} + engines: {node: '>=0.10.0'} + dev: false + + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: false + + /koa-bodyparser/4.3.0: + resolution: {integrity: sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw==} + engines: {node: '>=8.0.0'} + dependencies: + co-body: 6.1.0 + copy-to: 2.0.1 + dev: false + + /koa-compose/4.1.0: + resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} + dev: false + + /koa-convert/2.0.0: + resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==} + engines: {node: '>= 10'} + dependencies: + co: 4.6.0 + koa-compose: 4.1.0 + dev: false + + /koa-favicon/2.1.0: + resolution: {integrity: sha512-LvukcooYjxKtnZq0RXdBup+JDhaHwLgnLlDHB/xvjwQEjbc4rbp/0WkmOzpOvaHujc+fIwPear0dpKX1V+dHVg==} + dependencies: + mz: 2.7.0 + dev: false + + /koa-json-body/5.3.0: + resolution: {integrity: sha512-M2P3zLOs2XiYCpJLGSTXOKij4u5vJ8pbAMXXarXQnwsx4DwDav9qn081tYI2RdZ79B159Pdk4bRfvwl/sazL8A==} + engines: {node: '>= 4.0.0'} + dependencies: + co-body: 5.2.0 + dev: false + + /koa-logger/3.2.1: + resolution: {integrity: sha512-MjlznhLLKy9+kG8nAXKJLM0/ClsQp/Or2vI3a5rbSQmgl8IJBQO0KI5FA70BvW+hqjtxjp49SpH2E7okS6NmHg==} + engines: {node: '>= 7.6.0'} + dependencies: + bytes: 3.1.2 + chalk: 2.4.2 + humanize-number: 0.0.2 + passthrough-counter: 1.0.0 + dev: false + + /koa-mount/4.0.0: + resolution: {integrity: sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==} + engines: {node: '>= 7.6.0'} + dependencies: + debug: 4.3.4 + koa-compose: 4.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /koa-router/10.1.1: + resolution: {integrity: sha512-z/OzxVjf5NyuNO3t9nJpx7e1oR3FSBAauiwXtMQu4ppcnuNZzTaQ4p21P8A6r2Es8uJJM339oc4oVW+qX7SqnQ==} + engines: {node: '>= 8.0.0'} + dependencies: + debug: 4.3.4 + http-errors: 1.8.1 + koa-compose: 4.1.0 + methods: 1.1.2 + path-to-regexp: 6.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /koa-send/5.0.1: + resolution: {integrity: sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==} + engines: {node: '>= 8'} + dependencies: + debug: 4.3.4 + http-errors: 1.8.1 + resolve-path: 1.4.0 + transitivePeerDependencies: + - supports-color + + /koa-slow/2.1.0: + resolution: {integrity: sha512-ii6s1zuZ51p+SY7WIrwjRi1tmPrNpeHEaw5UYi4h1QzAPmIcNk16e9zwKd9+eNNzI9n+Q2LXHAvt1MCfs7j/8w==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dependencies: + lodash.isregexp: 3.0.5 + q: 1.4.1 + dev: false + + /koa-static/5.0.0: + resolution: {integrity: sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==} + engines: {node: '>= 7.6.0'} + dependencies: + debug: 3.2.7 + koa-send: 5.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /koa-views/7.0.2_6tybghmia4wsnt33xeid7y4rby: + resolution: {integrity: sha512-dvx3mdVeSVuIPEaKAoGbxLcenudvhl821xxyuRbcoA+bOJ2dvN8wlGjkLu0ZFMlkCscXZV6lzxy28rafeazI/w==} + peerDependencies: + '@types/koa': ^2.13.1 + peerDependenciesMeta: + '@types/koa': + optional: true + dependencies: + '@types/koa': 2.13.5 + consolidate: 0.16.0_pug@3.0.2 + debug: 4.3.4 + get-paths: 0.0.7 + koa-send: 5.0.1 + mz: 2.7.0 + pretty: 2.0.0 + resolve-path: 1.4.0 + transitivePeerDependencies: + - arc-templates + - atpl + - babel-core + - bracket-template + - coffee-script + - dot + - dust + - dustjs-helpers + - dustjs-linkedin + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jade + - jazz + - jqtpl + - just + - liquid-node + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - pug + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - slm + - squirrelly + - supports-color + - swig + - swig-templates + - teacup + - templayed + - then-jade + - then-pug + - tinyliquid + - toffee + - twig + - twing + - underscore + - vash + - velocityjs + - walrus + - whiskers + + /koa-views/7.0.2_no5ijl6tnlxntgm3uzzxedo2fe: + resolution: {integrity: sha512-dvx3mdVeSVuIPEaKAoGbxLcenudvhl821xxyuRbcoA+bOJ2dvN8wlGjkLu0ZFMlkCscXZV6lzxy28rafeazI/w==} + peerDependencies: + '@types/koa': ^2.13.1 + peerDependenciesMeta: + '@types/koa': + optional: true + dependencies: + '@types/koa': 2.13.5 + consolidate: 0.16.0_ejs@3.1.8+pug@3.0.2 + debug: 4.3.4 + get-paths: 0.0.7 + koa-send: 5.0.1 + mz: 2.7.0 + pretty: 2.0.0 + resolve-path: 1.4.0 + transitivePeerDependencies: + - arc-templates + - atpl + - babel-core + - bracket-template + - coffee-script + - dot + - dust + - dustjs-helpers + - dustjs-linkedin + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jade + - jazz + - jqtpl + - just + - liquid-node + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - pug + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - slm + - squirrelly + - supports-color + - swig + - swig-templates + - teacup + - templayed + - then-jade + - then-pug + - tinyliquid + - toffee + - twig + - twing + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: false + + /koa/2.13.4: + resolution: {integrity: sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==} + engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} + dependencies: + accepts: 1.3.8 + cache-content-type: 1.0.1 + content-disposition: 0.5.4 + content-type: 1.0.4 + cookies: 0.8.0 + debug: 4.3.4 + delegates: 1.0.0 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + fresh: 0.5.2 + http-assert: 1.5.0 + http-errors: 1.8.1 + is-generator-function: 1.0.10 + koa-compose: 4.1.0 + koa-convert: 2.0.0 + on-finished: 2.4.1 + only: 0.0.2 + parseurl: 1.3.3 + statuses: 1.5.0 + type-is: 1.6.18 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /ky-universal/0.10.1_ky@0.30.0: + resolution: {integrity: sha512-r8909k+ELKZAxhVA5c440x22hqw5XcMRwLRbgpPQk4JHy3/ddJnvzcnSo5Ww3HdKdNeS3Y8dBgcIYyVahMa46g==} + engines: {node: '>=14'} + peerDependencies: + ky: '>=0.26.0' + web-streams-polyfill: '>=3.0.1' + peerDependenciesMeta: + web-streams-polyfill: + optional: true + dependencies: + abort-controller: 3.0.0 + ky: 0.30.0 + node-fetch: 3.3.0 + dev: false + + /ky/0.30.0: + resolution: {integrity: sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==} + engines: {node: '>=12'} + dev: false + + /last-run/1.1.1: + resolution: {integrity: sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==} + engines: {node: '>= 0.10'} + dependencies: + default-resolution: 2.0.0 + es6-weak-map: 2.0.3 + dev: false + + /lazy-ass/1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + dev: true + + /lazystream/1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.7 + dev: false + + /lcid/1.0.0: + resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} + engines: {node: '>=0.10.0'} + dependencies: + invert-kv: 1.0.0 + dev: false + + /lead/1.0.0: + resolution: {integrity: sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==} + engines: {node: '>= 0.10'} + dependencies: + flush-write-stream: 1.1.1 + dev: false + + /levn/0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: false + + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + /liftoff/3.1.0: + resolution: {integrity: sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==} + engines: {node: '>= 0.8'} + dependencies: + extend: 3.0.2 + findup-sync: 3.0.0 + fined: 1.2.0 + flagged-respawn: 1.0.1 + is-plain-object: 2.0.4 + object.map: 1.0.1 + rechoir: 0.6.2 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color + dev: false + + /listenercount/1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + dev: false + + /listr2/3.14.0_enquirer@2.3.6: + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.19 + enquirer: 2.3.6 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.3.0 + rxjs: 7.8.0 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + + /load-json-file/1.1.0: + resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} + engines: {node: '>=0.10.0'} + dependencies: + graceful-fs: 4.2.10 + parse-json: 2.2.0 + pify: 2.3.0 + pinkie-promise: 2.0.1 + strip-bom: 2.0.0 + dev: false + + /loader-runner/4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + /loader-utils/2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 2.2.3 + dev: false + + /loadjs/4.2.0: + resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==} + dev: false + + /locate-path/5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: false + + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + + /lodash.assignin/4.2.0: + resolution: {integrity: sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==} + dev: false + + /lodash.bind/4.2.1: + resolution: {integrity: sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==} + dev: false + + /lodash.defaults/4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + /lodash.difference/4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + dev: false + + /lodash.filter/4.6.0: + resolution: {integrity: sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==} + dev: false + + /lodash.flatten/4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: false + + /lodash.foreach/4.5.0: + resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==} + dev: false + + /lodash.isarguments/3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + /lodash.isequal/4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: false + + /lodash.isplainobject/4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false + + /lodash.isregexp/3.0.5: + resolution: {integrity: sha512-VlV0abdYZs5asSYW1JW5W1f6gxf2SGQt90rzQp7UNTQ8KwcB3CprZe5crN1LIlCA/fB5R9xecrZijGSELJL8Yg==} + dev: false + + /lodash.map/4.6.0: + resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==} + dev: false + + /lodash.memoize/4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false + + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + /lodash.once/4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: true + + /lodash.pick/4.4.0: + resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} + dev: false + + /lodash.reduce/4.6.0: + resolution: {integrity: sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==} + dev: false + + /lodash.reject/4.6.0: + resolution: {integrity: sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==} + dev: false + + /lodash.some/4.6.0: + resolution: {integrity: sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==} + dev: false + + /lodash.union/4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + dev: false + + /lodash.uniq/4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: false + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + /log-symbols/4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + /log-update/4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + dev: true + + /long/4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + dev: false + + /long/5.2.1: + resolution: {integrity: sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==} + dev: false + + /lowercase-keys/1.0.0: + resolution: {integrity: sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A==} + engines: {node: '>=0.10.0'} + dev: false + + /lowercase-keys/1.0.1: + resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} + engines: {node: '>=0.10.0'} + dev: false + + /lowercase-keys/2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + dev: false + + /lowercase-keys/3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /lru-cache/4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + + /lru-cache/7.14.1: + resolution: {integrity: sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==} + engines: {node: '>=12'} + dev: false + + /luxon/3.2.1: + resolution: {integrity: sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==} + engines: {node: '>=12'} + dev: false + + /magic-string/0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + dependencies: + sourcemap-codec: 1.4.8 + dev: false + + /mailcheck/1.1.1: + resolution: {integrity: sha512-3WjL8+ZDouZwKlyJBMp/4LeziLFXgleOdsYu87piGcMLqhBzCsy2QFdbtAwv757TFC/rtqd738fgJw1tFQCSgA==} + dev: false + + /make-dir/1.3.0: + resolution: {integrity: sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==} + engines: {node: '>=4'} + dependencies: + pify: 3.0.0 + dev: false + + /make-dir/3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: false + optional: true + + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: false + + /make-fetch-happen/10.2.1: + resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + agentkeepalive: 4.2.1 + cacache: 16.1.3 + http-cache-semantics: 4.1.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.14.1 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + + /make-iterator/1.0.1: + resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 6.0.3 + dev: false + + /map-cache/0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + dev: false + + /map-stream/0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /map-visit/1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + dependencies: + object-visit: 1.0.1 + dev: false + + /matchdep/2.0.0: + resolution: {integrity: sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==} + engines: {node: '>= 0.10.0'} + dependencies: + findup-sync: 2.0.0 + micromatch: 3.1.10 + resolve: 1.22.1 + stack-trace: 0.0.10 + transitivePeerDependencies: + - supports-color + dev: false + + /math-expression-evaluator/1.4.0: + resolution: {integrity: sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==} + dev: false + + /matter-js/0.18.0: + resolution: {integrity: sha512-/ZVem4WygUnbmo/iE4oHZpZS97btfBtYy5Iwn1396vUZU7YhgVEN8J4UWwfZwY1ZqoTYlPgjvSw9WXauuXL0mg==} + dev: false + + /media-typer/0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + + /merge-stream/2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: false + + /methods/1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: false + + /mfm-js/0.23.2: + resolution: {integrity: sha512-lfYvsMr6FIYbt0ZDL+nY+GWWqmcXpe9jrYLBLy5vvQHwGfPALpx43uNHj8hZsakgM82hPMo/zdx0e9tj+4Z4IA==} + dependencies: + twemoji-parser: 14.0.0 + dev: false + + /micromatch/3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /micromatch/4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: false + + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /mimic-fn/2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + /mimic-fn/4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /mimic-response/1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + dev: false + + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + + /mimic-response/4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /minimalistic-assert/1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch/5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimatch/5.1.2: + resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + + /minimist/1.2.7: + resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} + + /minipass-collect/1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: false + + /minipass-fetch/2.1.2: + resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: false + + /minipass-flush/1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: false + + /minipass-pipeline/1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: false + + /minipass-sized/1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: false + + /minipass/2.9.0: + resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} + dependencies: + safe-buffer: 5.2.1 + yallist: 3.1.1 + dev: false + optional: true + + /minipass/3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: false + + /minipass/4.0.0: + resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: false + + /minizlib/1.3.3: + resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} + dependencies: + minipass: 2.9.0 + dev: false + optional: true + + /minizlib/2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: false + + /mixin-deep/1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + dev: false + + /mixly/1.0.0: + resolution: {integrity: sha512-ks+xIMVeIDwuYK4LnOMXTfmiEI8oo3tFNFirpHd60C4r2H0wMwKN5/qHCrFBKFK+BYx2Gp7qs+evUJw7QO9D2w==} + engines: {node: '>= 0.10'} + dependencies: + fulcon: 1.0.2 + dev: true + + /mkdirp-classic/0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + + /mkdirp/0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + dependencies: + minimist: 1.2.7 + dev: false + + /mkdirp/1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: false + + /mocha/10.2.0: + resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} + engines: {node: '>= 14.0.0'} + hasBin: true + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4_supports-color@8.1.1 + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + nanoid: 3.3.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: false + + /moment/2.29.4: + resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + dev: false + + /ms/2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + /msgpackr-extract/2.2.0: + resolution: {integrity: sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==} + hasBin: true + requiresBuild: true + dependencies: + node-gyp-build-optional-packages: 5.0.3 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 2.2.0 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 2.2.0 + '@msgpackr-extract/msgpackr-extract-linux-arm': 2.2.0 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 2.2.0 + '@msgpackr-extract/msgpackr-extract-linux-x64': 2.2.0 + '@msgpackr-extract/msgpackr-extract-win32-x64': 2.2.0 + dev: false + optional: true + + /msgpackr/1.8.1: + resolution: {integrity: sha512-05fT4J8ZqjYlR4QcRDIhLCYKUOHXk7C/xa62GzMKj74l3up9k2QZ3LgFc6qWdsPHl91QA2WLWqWc8b8t7GLNNw==} + optionalDependencies: + msgpackr-extract: 2.2.0 + dev: false + + /multer/1.4.4-lts.1: + resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==} + engines: {node: '>= 6.0.0'} + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + dev: false + + /multi-integer-range/3.0.0: + resolution: {integrity: sha512-uQzynjVJ8F7x5wjaK0g4Ybhy2TvO/pk96+YHyS5g1W4GuUEV6HMebZ8HcRwWgKIRCUT2MLbM5uCKwYcAqkS+8Q==} + dev: false + + /mute-stdout/1.0.1: + resolution: {integrity: sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==} + engines: {node: '>= 0.10'} + dev: false + + /mylas/2.1.13: + resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==} + engines: {node: '>=12.0.0'} + dev: false + + /mz/2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + /nan/2.17.0: + resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} + dev: false + + /nanoid/3.3.3: + resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false + + /nanoid/3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false + + /nanomatch/1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /napi-build-utils/1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + + /natural-compare/1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + /ndarray-ops/1.2.2: + resolution: {integrity: sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==} + dependencies: + cwise-compiler: 1.1.3 + dev: false + + /ndarray-pack/1.2.1: + resolution: {integrity: sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==} + dependencies: + cwise-compiler: 1.1.3 + ndarray: 1.0.19 + dev: false + + /ndarray/1.0.18: + resolution: {integrity: sha512-jUz6G+CIsEsqs2VlB1EvaQSAA0Jkf8YKm7eFBleKyhiQjYWzTxXqHzWEOm3jFoGCpxGh4DnPUYHB4ECWE+n9SQ==} + dependencies: + iota-array: 1.0.0 + is-buffer: 1.1.6 + dev: false + + /ndarray/1.0.19: + resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==} + dependencies: + iota-array: 1.0.0 + is-buffer: 1.1.6 + dev: false + + /needle/2.9.1: + resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + dev: false + + /negotiator/0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: false + + /neo-async/2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + /nested-property/4.0.0: + resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==} + dev: false + + /netmask/2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + dev: false + + /next-tick/1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + dev: false + + /nice-try/1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + dev: false + + /node-abi/3.31.0: + resolution: {integrity: sha512-eSKV6s+APenqVh8ubJyiu/YhZgxQpGP66ntzUb3lY1xB9ukSRaGnx0AIxI+IM+1+IVYC1oWobgG5L3Lt9ARykQ==} + engines: {node: '>=10'} + dependencies: + semver: 7.3.8 + dev: false + + /node-addon-api/5.0.0: + resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==} + dev: false + + /node-bitmap/0.0.1: + resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==} + engines: {node: '>=v0.6.5'} + dev: false + + /node-domexception/1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + /node-fetch/2.6.8: + resolution: {integrity: sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /node-fetch/3.3.0: + resolution: {integrity: sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + /node-gyp-build-optional-packages/5.0.3: + resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + hasBin: true + dev: false + optional: true + + /node-gyp-build/4.6.0: + resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} + hasBin: true + dev: false + + /node-gyp/9.3.1: + resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} + engines: {node: ^12.13 || ^14.13 || >=16} + hasBin: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.10 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.3.8 + tar: 6.1.13 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + + /node-releases/2.0.8: + resolution: {integrity: sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==} + + /nodemailer/6.8.0: + resolution: {integrity: sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==} + engines: {node: '>=6.0.0'} + dev: false + + /nofilter/3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + + /nopt/5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false + optional: true + + /nopt/6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + dependencies: + abbrev: 1.1.1 + + /normalize-package-data/2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.1 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: false + + /normalize-path/2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + dependencies: + remove-trailing-separator: 1.1.0 + dev: false + + /normalize-path/3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /normalize-range/0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: false + + /normalize-url/1.9.1: + resolution: {integrity: sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==} + engines: {node: '>=4'} + dependencies: + object-assign: 4.1.1 + prepend-http: 1.0.4 + query-string: 4.3.4 + sort-keys: 1.1.2 + dev: false + + /normalize-url/2.0.1: + resolution: {integrity: sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==} + engines: {node: '>=4'} + dependencies: + prepend-http: 2.0.0 + query-string: 5.1.1 + sort-keys: 2.0.0 + dev: false + + /normalize-url/6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + dev: false + + /normalize-url/8.0.0: + resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} + engines: {node: '>=14.16'} + dev: false + + /now-and-later/2.0.1: + resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==} + engines: {node: '>= 0.10'} + dependencies: + once: 1.4.0 + dev: false + + /npm-conf/1.1.3: + resolution: {integrity: sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==} + engines: {node: '>=4'} + dependencies: + config-chain: 1.1.13 + pify: 3.0.0 + dev: false + + /npm-run-path/2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + dependencies: + path-key: 2.0.1 + dev: false + + /npm-run-path/4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + + /npm-run-path/5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + + /npmlog/5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + optional: true + + /npmlog/6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + dev: false + + /nsfwjs/2.4.2_@tensorflow+tfjs@4.2.0: + resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==} + peerDependencies: + '@tensorflow/tfjs': ^3.18.0 + dependencies: + '@nsfw-filter/gif-frames': 1.0.2 + '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5 + dev: false + + /nth-check/1.0.2: + resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} + dependencies: + boolbase: 1.0.0 + dev: false + + /num2fraction/1.2.2: + resolution: {integrity: sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==} + dev: false + + /number-is-nan/1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + dev: false + + /nwsapi/2.2.2: + resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} + dev: false + + /oauth-sign/0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + dev: false + + /oauth/0.10.0: + resolution: {integrity: sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==} + dev: false + + /oauth/0.9.15: + resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} + dev: false + + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-copy/0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + dev: false + + /object-inspect/1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + + /object-keys/1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: false + + /object-visit/1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: false + + /object.assign/4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: false + + /object.defaults/1.1.0: + resolution: {integrity: sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==} + engines: {node: '>=0.10.0'} + dependencies: + array-each: 1.0.1 + array-slice: 1.1.0 + for-own: 1.0.0 + isobject: 3.0.1 + dev: false + + /object.map/1.0.1: + resolution: {integrity: sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==} + engines: {node: '>=0.10.0'} + dependencies: + for-own: 1.0.0 + make-iterator: 1.0.1 + dev: false + + /object.pick/1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: false + + /object.reduce/1.0.1: + resolution: {integrity: sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==} + engines: {node: '>=0.10.0'} + dependencies: + for-own: 1.0.0 + make-iterator: 1.0.1 + dev: false + + /oblivious-set/1.1.1: + resolution: {integrity: sha512-Oh+8fK09mgGmAshFdH6hSVco6KZmd1tTwNFWj35OvzdmJTMZtAkbn05zar2iG3v6sDs1JLEtOiBGNb6BHwkb2w==} + dev: false + + /omggif/1.0.10: + resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + dev: false + + /on-finished/2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime/5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + + /onetime/6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + + /only/0.0.2: + resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} + dev: false + + /opencollective-postinstall/2.0.3: + resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} + hasBin: true + dev: false + + /opentype.js/0.4.11: + resolution: {integrity: sha512-GthxucX/6aftfLdeU5Ho7o7zmQcC8uVtqdcelVq12X++ndxwBZG8Xb5rFEKT7nEcWDD2P1x+TNuJ70jtj1Mbpw==} + hasBin: true + dev: false + + /optionator/0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.3 + dev: false + + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + + /ordered-read-streams/1.0.1: + resolution: {integrity: sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==} + dependencies: + readable-stream: 2.3.7 + dev: false + + /os-filter-obj/2.0.0: + resolution: {integrity: sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==} + engines: {node: '>=4'} + dependencies: + arch: 2.2.0 + dev: false + + /os-locale/1.4.0: + resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} + engines: {node: '>=0.10.0'} + dependencies: + lcid: 1.0.0 + dev: false + + /os-utils/0.0.14: + resolution: {integrity: sha512-ajB8csaHLBvJOYsHJkp8YdO2FvlBbf/ZxaYQwXXRDyQ84UoE+uTuLXxqd0shekXMX6Qr/pt/DDyLMRAMsgfWzg==} + dev: false + + /ospath/1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + dev: true + + /p-cancelable/0.4.1: + resolution: {integrity: sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==} + engines: {node: '>=4'} + dev: false + + /p-cancelable/2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + dev: false + + /p-cancelable/3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + dev: false + + /p-event/2.3.1: + resolution: {integrity: sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==} + engines: {node: '>=6'} + dependencies: + p-timeout: 2.0.1 + dev: false + + /p-finally/1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + dev: false + + /p-is-promise/1.1.0: + resolution: {integrity: sha512-zL7VE4JVS2IFSkR2GQKDSPEVxkoH43/p7oEnwpdCndKYJO0HVeRB7fA8TJwuLOTBREtK0ea8eHaxdwcpob5dmg==} + engines: {node: '>=4'} + dev: false + + /p-limit/2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: false + + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + + /p-locate/4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: false + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + + /p-map/4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + + /p-queue/6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + dev: false + + /p-timeout/2.0.1: + resolution: {integrity: sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==} + engines: {node: '>=4'} + dependencies: + p-finally: 1.0.0 + dev: false + + /p-timeout/3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + dependencies: + p-finally: 1.0.0 + dev: false + + /p-try/2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: false + + /packet-reader/1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + dev: false + + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-data-uri/0.2.0: + resolution: {integrity: sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w==} + dependencies: + data-uri-to-buffer: 0.0.3 + dev: false + + /parse-filepath/1.0.2: + resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==} + engines: {node: '>=0.8'} + dependencies: + is-absolute: 1.0.0 + map-cache: 0.2.2 + path-root: 0.1.1 + dev: false + + /parse-json/2.2.0: + resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} + engines: {node: '>=0.10.0'} + dependencies: + error-ex: 1.3.2 + dev: false + + /parse-node-version/1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + dev: false + + /parse-passwd/1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + dev: false + + /parse-srcset/1.0.2: + resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + dev: false + + /parse5-htmlparser2-tree-adapter/6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + dependencies: + parse5: 6.0.1 + dev: false + + /parse5/5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + dev: false + + /parse5/6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: false + + /parse5/7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.4.0 + + /parseurl/1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + + /pascalcase/0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + dev: false + + /passthrough-counter/1.0.0: + resolution: {integrity: sha512-Wy8PXTLqPAN0oEgBrlnsXPMww3SYJ44tQ8aVrGAI4h4JZYCS0oYqsPqtPR8OhJpv6qFbpbB7XAn0liKV7EXubA==} + dev: false + + /path-dirname/1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + dev: false + + /path-exists/2.1.0: + resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} + engines: {node: '>=0.10.0'} + dependencies: + pinkie-promise: 2.0.1 + dev: false + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + /path-is-absolute/1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-key/2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + dev: false + + /path-key/3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-key/4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-root-regex/0.1.2: + resolution: {integrity: sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==} + engines: {node: '>=0.10.0'} + dev: false + + /path-root/0.1.1: + resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==} + engines: {node: '>=0.10.0'} + dependencies: + path-root-regex: 0.1.2 + dev: false + + /path-to-regexp/6.2.1: + resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + dev: false + + /path-type/1.1.0: + resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} + engines: {node: '>=0.10.0'} + dependencies: + graceful-fs: 4.2.10 + pify: 2.3.0 + pinkie-promise: 2.0.1 + dev: false + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + + /pause-stream/0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /peek-readable/5.0.0: + resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==} + engines: {node: '>=14.16'} + dev: false + + /pend/1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + /performance-now/2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + + /pg-connection-string/2.5.0: + resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} + dev: false + + /pg-int8/1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + dev: false + + /pg-pool/3.5.2_pg@8.8.0: + resolution: {integrity: sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.8.0 + dev: false + + /pg-protocol/1.5.0: + resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==} + dev: false + + /pg-types/2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + dev: false + + /pg/8.8.0: + resolution: {integrity: sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.5.0 + pg-pool: 3.5.2_pg@8.8.0 + pg-protocol: 1.5.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + dev: false + + /pgpass/1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.1.0 + dev: false + + /phosphor-icons/1.4.2: + resolution: {integrity: sha512-vDyuRWLSEb87dxpoOGpP1GCjr/TFzA0Ljt0TtJcwXO7/iPdSZW0e/2m1jsANH1ML5ZyZXcjeWx6pzT0A0tgYDA==} + dev: false + + /photoswipe/5.3.4: + resolution: {integrity: sha512-SN+RWHqxJvdwzXJsh8KrG+ajjPpdTX5HpKglEd0k9o6o5fW+QHPkW8//Bo11MB+NQwTa/hFw8BDv2EdxiDXjNw==} + engines: {node: '>= 0.12.0'} + dev: false + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pify/2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + /pify/3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + dev: false + + /pify/4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + /pinkie-promise/2.0.1: + resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} + engines: {node: '>=0.10.0'} + dependencies: + pinkie: 2.0.4 + dev: false + + /pinkie/2.0.4: + resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} + engines: {node: '>=0.10.0'} + dev: false + + /plimit-lit/1.5.0: + resolution: {integrity: sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng==} + dependencies: + queue-lit: 1.5.0 + dev: false + + /plugin-error/1.0.1: + resolution: {integrity: sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==} + engines: {node: '>= 0.10'} + dependencies: + ansi-colors: 1.1.0 + arr-diff: 4.0.0 + arr-union: 3.1.0 + extend-shallow: 3.0.2 + dev: false + + /pluralize/8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + dev: false + + /pngjs-nozlib/1.0.0: + resolution: {integrity: sha512-N1PggqLp9xDqwAoKvGohmZ3m4/N9xpY0nDZivFqQLcpLHmliHnCp9BuNCsOeqHWMuEEgFjpEaq9dZq6RZyy0fA==} + engines: {iojs: '>= 1.0.0', node: '>=0.10.0'} + dev: false + + /pngjs/3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + dev: false + + /pngjs/5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: false + + /posix-character-classes/0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + dev: false + + /postcss-calc/5.3.1: + resolution: {integrity: sha512-iBcptYFq+QUh9gzP7ta2btw50o40s4uLI4UDVgd5yRAZtUDWc5APdl5yQDd2h/TyiZNbJrv0HiYhT102CMgN7Q==} + dependencies: + postcss: 5.2.18 + postcss-message-helpers: 2.0.0 + reduce-css-calc: 1.3.0 + dev: false + + /postcss-colormin/2.2.2: + resolution: {integrity: sha512-XXitQe+jNNPf+vxvQXIQ1+pvdQKWKgkx8zlJNltcMEmLma1ypDRDQwlLt+6cP26fBreihNhZxohh1rcgCH2W5w==} + dependencies: + colormin: 1.1.2 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-convert-values/2.6.1: + resolution: {integrity: sha512-SE7mf25D3ORUEXpu3WUqQqy0nCbMuM5BEny+ULE/FXdS/0UMA58OdzwvzuHJRpIFlk1uojt16JhaEogtP6W2oA==} + dependencies: + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-discard-comments/2.0.4: + resolution: {integrity: sha512-yGbyBDo5FxsImE90LD8C87vgnNlweQkODMkUZlDVM/CBgLr9C5RasLGJxxh9GjVOBeG8NcCMatoqI1pXg8JNXg==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-discard-duplicates/2.1.0: + resolution: {integrity: sha512-+lk5W1uqO8qIUTET+UETgj9GWykLC3LOldr7EehmymV0Wu36kyoHimC4cILrAAYpHQ+fr4ypKcWcVNaGzm0reA==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-discard-empty/2.1.0: + resolution: {integrity: sha512-IBFoyrwk52dhF+5z/ZAbzq5Jy7Wq0aLUsOn69JNS+7YeuyHaNzJwBIYE0QlUH/p5d3L+OON72Fsexyb7OK/3og==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-discard-overridden/0.1.1: + resolution: {integrity: sha512-IyKoDL8QNObOiUc6eBw8kMxBHCfxUaERYTUe2QF8k7j/xiirayDzzkmlR6lMQjrAM1p1DDRTvWrS7Aa8lp6/uA==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-discard-unused/2.2.3: + resolution: {integrity: sha512-nCbFNfqYAbKCw9J6PSJubpN9asnrwVLkRDFc4KCwyUEdOtM5XDE/eTW3OpqHrYY1L4fZxgan7LLRAAYYBzwzrg==} + dependencies: + postcss: 5.2.18 + uniqs: 2.0.0 + dev: false + + /postcss-filter-plugins/2.0.3: + resolution: {integrity: sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-merge-idents/2.1.7: + resolution: {integrity: sha512-9DHmfCZ7/hNHhIKnNkz4CU0ejtGen5BbTRJc13Z2uHfCedeCUsK2WEQoAJRBL+phs68iWK6Qf8Jze71anuysWA==} + dependencies: + has: 1.0.3 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-merge-longhand/2.0.2: + resolution: {integrity: sha512-ma7YvxjdLQdifnc1HFsW/AW6fVfubGyR+X4bE3FOSdBVMY9bZjKVdklHT+odknKBB7FSCfKIHC3yHK7RUAqRPg==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-merge-rules/2.1.2: + resolution: {integrity: sha512-Wgg2FS6W3AYBl+5L9poL6ZUISi5YzL+sDCJfM7zNw/Q1qsyVQXXZ2cbVui6mu2cYJpt1hOKCGj1xA4mq/obz/Q==} + dependencies: + browserslist: 1.7.7 + caniuse-api: 1.6.1 + postcss: 5.2.18 + postcss-selector-parser: 2.2.3 + vendors: 1.0.4 + dev: false + + /postcss-message-helpers/2.0.0: + resolution: {integrity: sha512-tPLZzVAiIJp46TBbpXtrUAKqedXSyW5xDEo1sikrfEfnTs+49SBZR/xDdqCiJvSSbtr615xDsaMF3RrxS2jZlA==} + dev: false + + /postcss-minify-font-values/1.0.5: + resolution: {integrity: sha512-vFSPzrJhNe6/8McOLU13XIsERohBJiIFFuC1PolgajOZdRWqRgKITP/A4Z/n4GQhEmtbxmO9NDw3QLaFfE1dFQ==} + dependencies: + object-assign: 4.1.1 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-minify-gradients/1.0.5: + resolution: {integrity: sha512-DZhT0OE+RbVqVyGsTIKx84rU/5cury1jmwPa19bViqYPQu499ZU831yMzzsyC8EhiZVd73+h5Z9xb/DdaBpw7Q==} + dependencies: + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-minify-params/1.2.2: + resolution: {integrity: sha512-hhJdMVgP8vasrHbkKAk+ab28vEmPYgyuDzRl31V3BEB3QOR3L5TTIVEWLDNnZZ3+fiTi9d6Ker8GM8S1h8p2Ow==} + dependencies: + alphanum-sort: 1.0.2 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + uniqs: 2.0.0 + dev: false + + /postcss-minify-selectors/2.1.1: + resolution: {integrity: sha512-e13vxPBSo3ZaPne43KVgM+UETkx3Bs4/Qvm6yXI9HQpQp4nyb7HZ0gKpkF+Wn2x+/dbQ+swNpCdZSbMOT7+TIA==} + dependencies: + alphanum-sort: 1.0.2 + has: 1.0.3 + postcss: 5.2.18 + postcss-selector-parser: 2.2.3 + dev: false + + /postcss-normalize-charset/1.1.1: + resolution: {integrity: sha512-RKgjEks83l8w4yEhztOwNZ+nLSrJ+NvPNhpS+mVDzoaiRHZQVoG7NF2TP5qjwnaN9YswUhj6m1E0S0Z+WDCgEQ==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-normalize-url/3.0.8: + resolution: {integrity: sha512-WqtWG6GV2nELsQEFES0RzfL2ebVwmGl/M8VmMbshKto/UClBo+mznX8Zi4/hkThdqx7ijwv+O8HWPdpK7nH/Ig==} + dependencies: + is-absolute-url: 2.1.0 + normalize-url: 1.9.1 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-ordered-values/2.2.3: + resolution: {integrity: sha512-5RB1IUZhkxDCfa5fx/ogp/A82mtq+r7USqS+7zt0e428HJ7+BHCxyeY39ClmkkUtxdOd3mk8gD6d9bjH2BECMg==} + dependencies: + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-reduce-idents/2.4.0: + resolution: {integrity: sha512-0+Ow9e8JLtffjumJJFPqvN4qAvokVbdQPnijUDSOX8tfTwrILLP4ETvrZcXZxAtpFLh/U0c+q8oRMJLr1Kiu4w==} + dependencies: + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-reduce-initial/1.0.1: + resolution: {integrity: sha512-jJFrV1vWOPCQsIVitawGesRgMgunbclERQ/IRGW7r93uHrVzNQQmHQ7znsOIjJPZ4yWMzs5A8NFhp3AkPHPbDA==} + dependencies: + postcss: 5.2.18 + dev: false + + /postcss-reduce-transforms/1.0.4: + resolution: {integrity: sha512-lGgRqnSuAR5i5uUg1TA33r9UngfTadWxOyL2qx1KuPoCQzfmtaHjp9PuwX7yVyRxG3BWBzeFUaS5uV9eVgnEgQ==} + dependencies: + has: 1.0.3 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + dev: false + + /postcss-selector-parser/2.2.3: + resolution: {integrity: sha512-3pqyakeGhrO0BQ5+/tGTfvi5IAUAhHRayGK8WFSu06aEv2BmHoXw/Mhb+w7VY5HERIuC+QoUI7wgrCcq2hqCVA==} + dependencies: + flatten: 1.0.3 + indexes-of: 1.0.1 + uniq: 1.0.1 + dev: false + + /postcss-svgo/2.1.6: + resolution: {integrity: sha512-y5AdQdgBoF4rbpdbeWAJuxE953g/ylRfVNp6mvAi61VCN/Y25Tu9p5mh3CyI42WbTRIiwR9a1GdFtmDnNPeskQ==} + dependencies: + is-svg: 2.1.0 + postcss: 5.2.18 + postcss-value-parser: 3.3.1 + svgo: 0.7.2 + dev: false + + /postcss-unique-selectors/2.0.2: + resolution: {integrity: sha512-WZX8r1M0+IyljoJOJleg3kYm10hxNYF9scqAT7v/xeSX1IdehutOM85SNO0gP9K+bgs86XERr7Ud5u3ch4+D8g==} + dependencies: + alphanum-sort: 1.0.2 + postcss: 5.2.18 + uniqs: 2.0.0 + dev: false + + /postcss-value-parser/3.3.1: + resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==} + dev: false + + /postcss-zindex/2.2.0: + resolution: {integrity: sha512-uhRZ2hRgj0lorxm9cr62B01YzpUe63h0RXMXQ4gWW3oa2rpJh+FJAiEAytaFCPU/VgaBS+uW2SJ1XKyDNz1h4w==} + dependencies: + has: 1.0.3 + postcss: 5.2.18 + uniqs: 2.0.0 + dev: false + + /postcss/5.2.18: + resolution: {integrity: sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==} + engines: {node: '>=0.12'} + dependencies: + chalk: 1.1.3 + js-base64: 2.6.4 + source-map: 0.5.7 + supports-color: 3.2.3 + dev: false + + /postcss/8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: false + + /postgres-array/2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + dev: false + + /postgres-bytea/1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-date/1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-interval/1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + dev: false + + /prebuild-install/7.1.1: + resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.1 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.7 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.31.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + + /prelude-ls/1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + dev: false + + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + /prepend-http/1.0.4: + resolution: {integrity: sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==} + engines: {node: '>=0.10.0'} + dev: false + + /prepend-http/2.0.0: + resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} + engines: {node: '>=4'} + dev: false + + /pretty-bytes/5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + dev: true + + /pretty-hrtime/1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + dev: false + + /pretty/2.0.0: + resolution: {integrity: sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==} + engines: {node: '>=0.10.0'} + dependencies: + condense-newlines: 0.2.1 + extend-shallow: 2.0.1 + js-beautify: 1.14.7 + + /prismjs/1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + dev: false + + /private-ip/2.3.3: + resolution: {integrity: sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw==} + dependencies: + ip-regex: 4.3.0 + ipaddr.js: 2.0.1 + is-ip: 3.1.0 + netmask: 2.0.2 + dev: false + + /private-ip/2.3.4: + resolution: {integrity: sha512-ts/YFVwfBeLq61f9+KsOhXW6RH0wvY0gU50R6QZYzgFhggyyLK6WDFeYdjfi/HMnBm2hecLvsR3PB3JcRxDk+A==} + dependencies: + ip-regex: 4.3.0 + ipaddr.js: 2.0.1 + is-ip: 3.1.0 + netmask: 2.0.2 + dev: false + + /probe-image-size/7.2.3: + resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==} + dependencies: + lodash.merge: 4.6.2 + needle: 2.9.1 + stream-parser: 0.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + /progress/2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: false + optional: true + + /promise-inflight/1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + dev: false + + /promise-limit/2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + dev: false + + /promise-retry/2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + dev: false + + /promise/7.3.1: + resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} + dependencies: + asap: 2.0.6 + + /proto-list/1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + /proxy-from-env/1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + dev: true + + /ps-tree/1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /pseudomap/1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + + /psl/1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + + /pug-attrs/3.0.0: + resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} + dependencies: + constantinople: 4.0.1 + js-stringify: 1.0.2 + pug-runtime: 3.0.1 + + /pug-code-gen/3.0.2: + resolution: {integrity: sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==} + dependencies: + constantinople: 4.0.1 + doctypes: 1.1.0 + js-stringify: 1.0.2 + pug-attrs: 3.0.0 + pug-error: 2.0.0 + pug-runtime: 3.0.1 + void-elements: 3.1.0 + with: 7.0.2 + + /pug-error/2.0.0: + resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==} + + /pug-filters/4.0.0: + resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==} + dependencies: + constantinople: 4.0.1 + jstransformer: 1.0.0 + pug-error: 2.0.0 + pug-walk: 2.0.0 + resolve: 1.22.1 + + /pug-lexer/5.0.1: + resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==} + dependencies: + character-parser: 2.2.0 + is-expression: 4.0.0 + pug-error: 2.0.0 + + /pug-linker/4.0.0: + resolution: {integrity: sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==} + dependencies: + pug-error: 2.0.0 + pug-walk: 2.0.0 + + /pug-load/3.0.0: + resolution: {integrity: sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==} + dependencies: + object-assign: 4.1.1 + pug-walk: 2.0.0 + + /pug-parser/6.0.0: + resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==} + dependencies: + pug-error: 2.0.0 + token-stream: 1.0.0 + + /pug-runtime/3.0.1: + resolution: {integrity: sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==} + + /pug-strip-comments/2.0.0: + resolution: {integrity: sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==} + dependencies: + pug-error: 2.0.0 + + /pug-walk/2.0.0: + resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==} + + /pug/3.0.2: + resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==} + dependencies: + pug-code-gen: 3.0.2 + pug-filters: 4.0.0 + pug-lexer: 5.0.1 + pug-linker: 4.0.0 + pug-load: 3.0.0 + pug-parser: 6.0.0 + pug-runtime: 3.0.1 + pug-strip-comments: 2.0.0 + + /pump/2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /pump/3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + /pumpify/1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + dev: false + + /punycode/1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + dev: false + + /punycode/2.1.1: + resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + engines: {node: '>=6'} + dev: false + + /punycode/2.2.0: + resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==} + engines: {node: '>=6'} + + /pureimage/0.3.15: + resolution: {integrity: sha512-QpQYEV8nxVb84en7D0nKXwG0bdmwmlsSg9QnqxpEOExvUXdbmo6Lw/UoxSXD9z+ryvWDkgWqZsIM3iPCAh4dXg==} + engines: {node: '>=0.8'} + dependencies: + jpeg-js: 0.4.4 + opentype.js: 0.4.11 + pngjs: 3.4.0 + dev: false + + /q/1.4.1: + resolution: {integrity: sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /q/1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /qrcode/1.5.1: + resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.2 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: false + + /qs/6.10.4: + resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + + /qs/6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} + dev: false + + /query-string/4.3.4: + resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==} + engines: {node: '>=0.10.0'} + dependencies: + object-assign: 4.1.1 + strict-uri-encode: 1.1.0 + dev: false + + /query-string/5.1.1: + resolution: {integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==} + engines: {node: '>=0.10.0'} + dependencies: + decode-uri-component: 0.2.2 + object-assign: 4.1.1 + strict-uri-encode: 1.1.0 + dev: false + + /querystring/0.2.0: + resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + dev: false + + /querystring/0.2.1: + resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + dev: false + + /querystringify/2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: false + + /queue-lit/1.5.0: + resolution: {integrity: sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA==} + dev: false + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: false + + /random-seed/0.3.0: + resolution: {integrity: sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==} + engines: {node: '>= 0.6.0'} + dependencies: + json-stringify-safe: 5.0.1 + dev: false + + /randombytes/2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + + /rangestr/0.0.1: + resolution: {integrity: sha512-9CRCUX/w4+fNMzlYgA8GeJz7BZwBPwaGm3FhAm9Hi50k8wNy2CyiJQa8awygWJay87uVVCV0/FwbLcD6+/A9KQ==} + dev: false + + /rangetouch/2.0.1: + resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==} + dev: false + + /ratelimiter/3.4.1: + resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==} + dev: false + + /raw-body/2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: false + + /rc/1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.7 + strip-json-comments: 2.0.1 + dev: false + + /rdf-canonize/3.3.0: + resolution: {integrity: sha512-gfSNkMua/VWC1eYbSkVaL/9LQhFeOh0QULwv7Or0f+po8pMgQ1blYQFe1r9Mv2GJZXw88Cz/drnAnB9UlNnHfQ==} + engines: {node: '>=12'} + dependencies: + setimmediate: 1.0.5 + dev: false + + /re2/1.18.0: + resolution: {integrity: sha512-MoCYZlJ9YUgksND9asyNF2/x532daXU/ARp1UeJbQ5flMY6ryKNEhrWt85aw3YluzOJlC3vXpGgK2a1jb0b4GA==} + requiresBuild: true + dependencies: + install-artifact-from-github: 1.3.2 + nan: 2.17.0 + node-gyp: 9.3.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + + /read-pkg-up/1.0.1: + resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} + engines: {node: '>=0.10.0'} + dependencies: + find-up: 1.1.2 + read-pkg: 1.1.0 + dev: false + + /read-pkg/1.1.0: + resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} + engines: {node: '>=0.10.0'} + dependencies: + load-json-file: 1.1.0 + normalize-package-data: 2.5.0 + path-type: 1.1.0 + dev: false + + /readable-stream/1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: false + + /readable-stream/2.3.7: + resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readable-web-to-node-stream/3.0.2: + resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==} + engines: {node: '>=8'} + dependencies: + readable-stream: 3.6.0 + dev: false + + /readdir-glob/1.1.2: + resolution: {integrity: sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==} + dependencies: + minimatch: 5.1.2 + dev: false + + /readdirp/3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /rechoir/0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.1 + dev: false + + /reconnecting-websocket/4.4.0: + resolution: {integrity: sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==} + dev: false + + /redis-errors/1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + /redis-info/3.1.0: + resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==} + dependencies: + lodash: 4.17.21 + dev: false + + /redis-lock/0.1.4: + resolution: {integrity: sha512-7/+zu86XVQfJVx1nHTzux5reglDiyUCDwmW7TSlvVezfhH2YLc/Rc8NE0ejQG+8/0lwKzm29/u/4+ogKeLosiA==} + engines: {node: '>=0.6'} + dev: false + + /redis-parser/3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + dependencies: + redis-errors: 1.2.0 + + /redis/4.5.1: + resolution: {integrity: sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==} + dependencies: + '@redis/bloom': 1.1.0_@redis+client@1.4.2 + '@redis/client': 1.4.2 + '@redis/graph': 1.1.0_@redis+client@1.4.2 + '@redis/json': 1.0.4_@redis+client@1.4.2 + '@redis/search': 1.1.0_@redis+client@1.4.2 + '@redis/time-series': 1.0.4_@redis+client@1.4.2 + dev: true + + /reduce-css-calc/1.3.0: + resolution: {integrity: sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==} + dependencies: + balanced-match: 0.4.2 + math-expression-evaluator: 1.4.0 + reduce-function-call: 1.0.3 + dev: false + + /reduce-function-call/1.0.3: + resolution: {integrity: sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /reflect-metadata/0.1.13: + resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + dev: false + + /regenerator-runtime/0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false + + /regex-not/1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + dev: false + + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + /remove-bom-buffer/3.0.0: + resolution: {integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + is-utf8: 0.2.1 + dev: false + + /remove-bom-stream/1.2.0: + resolution: {integrity: sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==} + engines: {node: '>= 0.10'} + dependencies: + remove-bom-buffer: 3.0.0 + safe-buffer: 5.2.1 + through2: 2.0.5 + dev: false + + /remove-trailing-separator/1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + dev: false + + /rename/1.0.4: + resolution: {integrity: sha512-YMM6Fn3lrFOCjhORKjj+z/yizj8WSzv3F3YUlpJA20fteWCb0HbJU19nvuRBPUM5dWgxJcHP+kix3M+5NowJyA==} + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + dev: false + + /repeat-element/1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + dev: false + + /repeat-string/1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + + /replace-ext/1.0.1: + resolution: {integrity: sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==} + engines: {node: '>= 0.10'} + dev: false + + /replace-homedir/1.0.0: + resolution: {integrity: sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==} + engines: {node: '>= 0.10'} + dependencies: + homedir-polyfill: 1.0.3 + is-absolute: 1.0.0 + remove-trailing-separator: 1.1.0 + dev: false + + /replacestream/4.0.3: + resolution: {integrity: sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==} + dependencies: + escape-string-regexp: 1.0.5 + object-assign: 4.1.1 + readable-stream: 2.3.7 + dev: false + + /request-progress/3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + dependencies: + throttleit: 1.0.0 + dev: true + + /request/2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + dependencies: + aws-sign2: 0.7.0 + aws4: 1.12.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.5 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.3 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 3.4.0 + dev: false + + /require-all/3.0.0: + resolution: {integrity: sha512-jPGN876lc5exWYrMcgZSd7U42P0PmVQzxnQB13fCSzmyGnqQWW4WUz5DosZ/qe24hz+5o9lSvW2epBNZ1xa6Fw==} + engines: {node: '>= 0.8'} + dev: false + + /require-directory/2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + + /require-from-string/2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: false + + /require-main-filename/1.0.1: + resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + dev: false + + /require-main-filename/2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: false + + /requires-port/1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: false + + /resolve-alpn/1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: false + + /resolve-dir/1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + dev: false + + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + /resolve-options/1.1.0: + resolution: {integrity: sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==} + engines: {node: '>= 0.10'} + dependencies: + value-or-function: 3.0.0 + dev: false + + /resolve-path/1.4.0: + resolution: {integrity: sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==} + engines: {node: '>= 0.8'} + dependencies: + http-errors: 1.6.3 + path-is-absolute: 1.0.1 + + /resolve-url/0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + dev: false + + /resolve/1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /responselike/1.0.2: + resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} + dependencies: + lowercase-keys: 1.0.1 + dev: false + + /responselike/2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + dependencies: + lowercase-keys: 2.0.0 + dev: false + + /responselike/3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + dependencies: + lowercase-keys: 3.0.0 + dev: false + + /restore-cursor/3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /ret/0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + dev: false + + /retry/0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + dev: false + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rfdc/1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf/2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: false + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + + /rndstr/1.0.0: + resolution: {integrity: sha512-3KN+BHTiHcsyW1qjRw3Xhms8TQfTIN4fUVgqqJpj6FnmuCnto5/lLyppSmGfdTmOiKDWeuXU4XPp58I9fsoWFQ==} + dependencies: + rangestr: 0.0.1 + seedrandom: 2.4.2 + dev: false + + /rollup/3.12.1: + resolution: {integrity: sha512-t9elERrz2i4UU9z7AwISj3CQcXP39cWxgRWLdf4Tm6aKm1eYrqHIgjzXBgb67GNY1sZckTFFi0oMozh3/S++Ig==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: false + + /rollup/3.9.1: + resolution: {integrity: sha512-GswCYHXftN8ZKGVgQhTFUJB/NBXxrRGgO2NCy6E8s1rwEJ4Q9/VttNqcYfEvx4dTo4j58YqdC3OVztPzlKSX8w==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + + /rome/11.0.0: + resolution: {integrity: sha512-rRo6JOwpMLc3OkeTDRXkrmrDqnxDvZ75GS4f0jLDBNmRgDXWbu0F8eVnJoRn+VbK2AE7vWvhVOMBjnWowcopkQ==} + engines: {node: '>=14.*'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@rometools/cli-darwin-arm64': 11.0.0 + '@rometools/cli-darwin-x64': 11.0.0 + '@rometools/cli-linux-arm64': 11.0.0 + '@rometools/cli-linux-x64': 11.0.0 + '@rometools/cli-win32-arm64': 11.0.0 + '@rometools/cli-win32-x64': 11.0.0 + dev: true + + /rss-parser/3.12.0: + resolution: {integrity: sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==} + dependencies: + entities: 2.2.0 + xml2js: 0.4.23 + dev: false + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /rxjs/7.8.0: + resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} + dependencies: + tslib: 2.4.1 + dev: true + + /s-age/1.1.2: + resolution: {integrity: sha512-aSN2TlF39WLoZA/6cgYSJZhKt63kJ4EaadejPWjWY9/h4rksIqvfWY3gfd+3uAegSM1IXsA9aWeEhJtkxkFQtA==} + dev: false + + /safari-14-idb-fix/3.0.0: + resolution: {integrity: sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog==} + dev: false + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /safe-regex/1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + dependencies: + ret: 0.1.15 + dev: false + + /safer-buffer/2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + /sanitize-html/2.8.1: + resolution: {integrity: sha512-qK5neD0SaMxGwVv5txOYv05huC3o6ZAA4h5+7nJJgWMNFUNRjcjLO6FpwAtKzfKCZ0jrG6xTk6eVFskbvOGblg==} + dependencies: + deepmerge: 4.2.2 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.1 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.4.21 + dev: false + + /sass/1.57.1: + resolution: {integrity: sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.2.2 + source-map-js: 1.0.2 + dev: false + + /sax/1.2.1: + resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} + dev: false + + /sax/1.2.4: + resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + dev: false + + /saxes/6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + dev: false + + /schema-utils/3.1.1: + resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.11 + ajv: 6.12.6 + ajv-keywords: 3.5.2_ajv@6.12.6 + + /secure-json-parse/2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + + /seedrandom/2.4.2: + resolution: {integrity: sha512-uQ72txMoObtuJooiBLSVs5Yu2e9d/lHQz0boaqHjW8runXB9vR8nFtaZV54wYii613N0C8ZqTBLsfwDhAdpvqQ==} + dev: false + + /seedrandom/3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + dev: false + + /seek-bzip/1.0.6: + resolution: {integrity: sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==} + hasBin: true + dependencies: + commander: 2.20.3 + dev: false + + /semver-greatest-satisfied-range/1.1.0: + resolution: {integrity: sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==} + engines: {node: '>= 0.10'} + dependencies: + sver-compat: 1.5.0 + dev: false + + /semver-regex/2.0.0: + resolution: {integrity: sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==} + engines: {node: '>=6'} + dev: false + + /semver-truncate/1.1.2: + resolution: {integrity: sha512-V1fGg9i4CL3qesB6U0L6XAm4xOJiHmt4QAacazumuasc03BvtFGIMCduv01JWQ69Nv+JST9TqhSCiJoxoY031w==} + engines: {node: '>=0.10.0'} + dependencies: + semver: 5.7.1 + dev: false + + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: false + optional: true + + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + + /serialize-javascript/6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + dependencies: + randombytes: 2.1.0 + + /set-blocking/2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + + /set-value/2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + dev: false + + /setimmediate/1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: false + + /setprototypeof/1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + + /setprototypeof/1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + /sha.js/2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /sha1/1.1.1: + resolution: {integrity: sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==} + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + dev: false + + /sharp/0.31.3: + resolution: {integrity: sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg==} + engines: {node: '>=14.15.0'} + requiresBuild: true + dependencies: + color: 4.2.3 + detect-libc: 2.0.1 + node-addon-api: 5.0.0 + prebuild-install: 7.1.1 + semver: 7.3.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + + /shebang-command/1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + dependencies: + shebang-regex: 1.0.0 + dev: false + + /shebang-command/2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex/1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + dev: false + + /shebang-regex/3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /side-channel/1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + object-inspect: 1.12.3 + + /sigmund/1.0.1: + resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==} + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + /simple-concat/1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get/4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + + /simple-swizzle/0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + + /slash/3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: false + + /slice-ansi/3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi/4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /smart-buffer/4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: false + + /snapdragon-node/2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + dev: false + + /snapdragon-util/3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /snapdragon/0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /socks-proxy-agent/7.0.0: + resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} + engines: {node: '>= 10'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + + /socks/2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: false + + /sort-keys-length/1.0.1: + resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} + engines: {node: '>=0.10.0'} + dependencies: + sort-keys: 1.1.2 + dev: false + + /sort-keys/1.1.2: + resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==} + engines: {node: '>=0.10.0'} + dependencies: + is-plain-obj: 1.1.0 + dev: false + + /sort-keys/2.0.0: + resolution: {integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==} + engines: {node: '>=4'} + dependencies: + is-plain-obj: 1.1.0 + dev: false + + /sortablejs/1.14.0: + resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==} + dev: false + + /source-map-js/1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: false + + /source-map-resolve/0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + dev: false + + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + /source-map-url/0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + dev: false + + /source-map/0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + dev: false + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + /source-map/0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: false + + /sourcemap-codec/1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + dev: false + + /sparkles/1.0.1: + resolution: {integrity: sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==} + engines: {node: '>= 0.10'} + dev: false + + /spdx-correct/3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.12 + dev: false + + /spdx-exceptions/2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: false + + /spdx-expression-parse/3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.12 + dev: false + + /spdx-license-ids/3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + dev: false + + /speakeasy/2.0.0: + resolution: {integrity: sha512-lW2A2s5LKi8rwu77ewisuUOtlCydF/hmQSOJjpTqTj1gZLkNgTaYnyvfxy2WBr4T/h+9c4g8HIITfj83OkFQFw==} + engines: {node: '>= 0.10.0'} + dependencies: + base32.js: 0.0.1 + dev: false + + /split-string/3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + dev: false + + /split/0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /split2/4.1.0: + resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} + engines: {node: '>= 10.x'} + dev: false + + /sprintf-js/1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: false + + /sprintf-js/1.1.2: + resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + dev: false + + /sshpk/1.17.0: + resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + + /ssr-window/4.0.2: + resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==} + dev: false + + /ssri/9.0.1: + resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + minipass: 3.3.6 + dev: false + + /stack-trace/0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + dev: false + + /standard-as-callback/2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + /start-server-and-test/1.15.2: + resolution: {integrity: sha512-t5xJX04Hg7hqxiKHMJBz/n4zIMsE6G7hpAcerFAH+4Vh9le/LeyFcJERJM7WLiPygWF9TOg33oroJF1XOzJtYQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.3.4 + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 6.0.1_debug@4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /static-extend/0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + dev: false + + /statuses/1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + /statuses/2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /stream-combiner/0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /stream-exhaust/1.0.2: + resolution: {integrity: sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==} + + /stream-parser/0.3.1: + resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + dev: false + + /stream-shift/1.0.1: + resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} + dev: false + + /streamsearch/1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false + + /strict-event-emitter-types/2.0.0: + resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==} + dev: false + + /strict-uri-encode/1.1.0: + resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} + engines: {node: '>=0.10.0'} + dev: false + + /string-width/1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + dev: false + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + /string_decoder/0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + dev: false + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: false + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /stringz/2.1.0: + resolution: {integrity: sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==} + dependencies: + char-regex: 1.0.2 + dev: false + + /strip-ansi/3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: false + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-bom/2.0.0: + resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} + engines: {node: '>=0.10.0'} + dependencies: + is-utf8: 0.2.1 + dev: false + + /strip-bom/3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: false + + /strip-dirs/2.1.0: + resolution: {integrity: sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==} + dependencies: + is-natural-number: 4.0.1 + dev: false + + /strip-eof/1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + dev: false + + /strip-final-newline/2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + /strip-final-newline/3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + + /strip-json-comments/2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + /strip-outer/1.0.1: + resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} + engines: {node: '>=0.10.0'} + dependencies: + escape-string-regexp: 1.0.5 + dev: false + + /strnum/1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + + /strtok3/7.0.0: + resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==} + engines: {node: '>=14.16'} + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.0.0 + dev: false + + /summaly/2.7.0: + resolution: {integrity: sha512-pEz9LL8Gp0oPIQfn6TrnBCcv/HkFE14hxhH3W6LPGdopXlPXjRcMlDMJaO+VupUNMOGaMjCsjq7+0rWnu8sp7w==} + dependencies: + cheerio: 0.22.0 + debug: 4.3.3 + escape-regexp: 0.0.1 + got: 11.8.5 + html-entities: 2.3.2 + iconv-lite: 0.6.3 + jschardet: 3.0.0 + koa: 2.13.4 + private-ip: 2.3.3 + require-all: 3.0.0 + trace-redirect: 1.0.6 + transitivePeerDependencies: + - supports-color + dev: false + + /supports-color/2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + dev: false + + /supports-color/3.2.3: + resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} + engines: {node: '>=0.8.0'} + dependencies: + has-flag: 1.0.0 + dev: false + + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-color/8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag/1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /sver-compat/1.5.0: + resolution: {integrity: sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==} + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + dev: false + + /svgo/0.7.2: + resolution: {integrity: sha512-jT/g9FFMoe9lu2IT6HtAxTA7RR2XOrmcrmCtGnyB/+GQnV6ZjNn+KOHZbZ35yL81+1F/aB6OeEsJztzBQ2EEwA==} + engines: {node: '>=0.10.0'} + deprecated: This SVGO version is no longer supported. Upgrade to v2.x.x. + hasBin: true + dependencies: + coa: 1.0.4 + colors: 1.1.2 + csso: 2.3.2 + js-yaml: 3.7.0 + mkdirp: 0.5.6 + sax: 1.2.4 + whet.extend: 0.9.9 + dev: false + + /swc-loader/0.2.3_v4imsvpumnwpgduroyqmpcfjiy: + resolution: {integrity: sha512-D1p6XXURfSPleZZA/Lipb3A8pZ17fP4NObZvFCDjK/OKljroqDpPmsBdTraWhVBqUNpcWBQY1imWdoPScRlQ7A==} + peerDependencies: + '@swc/core': ^1.2.147 + webpack: '>=2' + dependencies: + '@swc/core': 1.3.26 + webpack: 5.75.0_@swc+core@1.3.26 + dev: true + + /swiper/8.4.5: + resolution: {integrity: sha512-zveyEFBBv4q1sVkbJHnuH4xCtarKieavJ4SxP0QEHvdpPLJRuD7j/Xg38IVVLbp7Db6qrPsLUePvxohYx39Agw==} + engines: {node: '>= 4.7.0'} + requiresBuild: true + dependencies: + dom7: 4.0.4 + ssr-window: 4.0.2 + dev: false + + /symbol-tree/3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: false + + /syslog-pro/1.0.0: + resolution: {integrity: sha512-7SNMJKtQBJlwBUp1jxFT7bXya71cnINXPCYJ2AVhlQE4MKL7o2QiPdAXbMdWRiLeykQ2rx+7TNrnoGzvzhO+eA==} + engines: {node: '>=10.0.0'} + dependencies: + moment: 2.29.4 + dev: false + + /systeminformation/5.16.9: + resolution: {integrity: sha512-QTlv3GGSromPeLVW3pzM6uxU8RbkacW9e0+ZX23GAXaX+XE0UToSygAxCJDHSty6RB9lAFHCHg+FfiXFChi/+w==} + engines: {node: '>=8.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true + dev: false + + /syuilo-password-strength/0.0.1: + resolution: {integrity: sha512-g9rPT3V1Q4WjWFZ/t5BdGC1mT/FpYnsLdBl+M5e6MlRkuE1RSR+R43wcY/3mKI59B9KEr+vxdWCuWNMD3oNHKA==} + dev: false + + /tapable/2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + /tar-fs/2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-stream/1.6.2: + resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} + engines: {node: '>= 0.8.0'} + dependencies: + bl: 1.2.3 + buffer-alloc: 1.2.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + readable-stream: 2.3.7 + to-buffer: 1.1.1 + xtend: 4.0.2 + dev: false + + /tar-stream/2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + + /tar/4.4.19: + resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} + engines: {node: '>=4.5'} + dependencies: + chownr: 1.1.4 + fs-minipass: 1.2.7 + minipass: 2.9.0 + minizlib: 1.3.3 + mkdirp: 0.5.6 + safe-buffer: 5.2.1 + yallist: 3.1.1 + dev: false + optional: true + + /tar/6.1.13: + resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 4.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: false + + /terser-webpack-plugin/5.3.6_v4imsvpumnwpgduroyqmpcfjiy: + resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.17 + '@swc/core': 1.3.26 + jest-worker: 27.5.1 + schema-utils: 3.1.1 + serialize-javascript: 6.0.0 + terser: 5.16.1 + webpack: 5.75.0_@swc+core@1.3.26 + + /terser/5.16.1: + resolution: {integrity: sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.2 + acorn: 8.8.1 + commander: 2.20.3 + source-map-support: 0.5.21 + + /tesseract.js-core/3.0.2: + resolution: {integrity: sha512-2fD76ka9nO/C616R0fq+M9Zu91DA3vEfyozp0jlxaJOBmpfeprtgRP3cqVweZh2darE1kK/DazoxZ65g7WU99Q==} + dev: false + + /tesseract.js/3.0.3_eslint@8.31.0: + resolution: {integrity: sha512-eZ1+OGWvF5IMExAzIwnDf3S3kf2FeC+i4qrMTRvBSlZeHc3ONy0vCmaKmBQz6scjB6C1W2w2x0r4lCEh95qBnw==} + requiresBuild: true + dependencies: + babel-eslint: 10.1.0_eslint@8.31.0 + bmp-js: 0.1.0 + file-type: 12.4.2 + idb-keyval: 3.2.0 + is-electron: 2.2.1 + is-url: 1.2.4 + node-fetch: 2.6.8 + opencollective-postinstall: 2.0.3 + regenerator-runtime: 0.13.11 + resolve-url: 0.2.1 + tesseract.js-core: 3.0.2 + wasm-feature-detect: 1.4.0 + zlibjs: 0.3.1 + transitivePeerDependencies: + - encoding + - eslint + - supports-color + dev: false + + /text-table/0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + /textarea-caret/3.1.0: + resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==} + dev: false + + /textextensions/3.3.0: + resolution: {integrity: sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==} + engines: {node: '>=8'} + dev: false + + /thenify-all/1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + + /thenify/3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + + /three/0.146.0: + resolution: {integrity: sha512-1lvNfLezN6OJ9NaFAhfX4sm5e9YCzHtaRgZ1+B4C+Hv6TibRMsuBAM5/wVKzxjpYIlMymvgsHEFrrigEfXnb2A==} + dev: false + + /throttle-debounce/5.0.0: + resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==} + engines: {node: '>=12.22'} + dev: false + + /throttleit/1.0.0: + resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} + dev: true + + /through/2.3.4: + resolution: {integrity: sha512-DwbmSAcABsMazNkLOJJSLRC3gfh4cPxUxJCn9npmvbcI6undhgoJ2ShvEOgZrW8BH62Gyr9jKboGbfFcmY5VsQ==} + dev: false + + /through/2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + /through2-filter/3.0.0: + resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==} + dependencies: + through2: 2.0.5 + xtend: 4.0.2 + dev: false + + /through2/2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.7 + xtend: 4.0.2 + dev: false + + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.0 + dev: false + + /time-stamp/1.1.0: + resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} + engines: {node: '>=0.10.0'} + dev: false + + /timed-out/4.0.1: + resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} + engines: {node: '>=0.10.0'} + dev: false + + /tinycolor2/1.5.2: + resolution: {integrity: sha512-h80m9GPFGbcLzZByXlNSEhp1gf8Dy+VX/2JCGUZsWLo7lV1mnE/XlxGYgRBoMLJh1lIDXP0EMC4RPTjlRaV+Bg==} + dev: false + + /tmp/0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + + /to-absolute-glob/2.0.2: + resolution: {integrity: sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==} + engines: {node: '>=0.10.0'} + dependencies: + is-absolute: 1.0.0 + is-negated-glob: 1.0.0 + dev: false + + /to-buffer/1.1.1: + resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} + dev: false + + /to-fast-properties/2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-object-path/0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /to-regex-range/2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + dev: false + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /to-regex/3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + dev: false + + /to-through/2.0.0: + resolution: {integrity: sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==} + engines: {node: '>= 0.10'} + dependencies: + through2: 2.0.5 + dev: false + + /toidentifier/1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + /token-stream/1.0.0: + resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==} + + /token-types/5.0.1: + resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==} + engines: {node: '>=14.16'} + dependencies: + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + dev: false + + /tough-cookie/2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + dependencies: + psl: 1.9.0 + punycode: 2.2.0 + + /tough-cookie/4.1.2: + resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.2.0 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: false + + /tr46/0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /tr46/3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + dependencies: + punycode: 2.2.0 + dev: false + + /trace-redirect/1.0.6: + resolution: {integrity: sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==} + dev: false + + /traverse/0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + dev: false + + /trim-repeated/1.0.0: + resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} + engines: {node: '>=0.10.0'} + dependencies: + escape-string-regexp: 1.0.5 + dev: false + + /ts-loader/9.4.2_3fkjkrd3audxnith3e7fo4fnxi: + resolution: {integrity: sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.12.0 + micromatch: 4.0.5 + semver: 7.3.8 + typescript: 4.9.4 + webpack: 5.75.0_@swc+core@1.3.26 + dev: false + + /ts-node/10.9.1_fodzh64fuekdilycyvke2qmf2e: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@swc/core': 1.3.26 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 18.11.18 + acorn: 8.8.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: false + + /tsc-alias/1.8.2: + resolution: {integrity: sha512-ukBkcNekOgwtnSWYLD5QsMX3yQWg7JviAs8zg3qJGgu4LGtY3tsV4G6vnqvOXIDkbC+XL9vbhObWSpRA5/6wbg==} + hasBin: true + dependencies: + chokidar: 3.5.3 + commander: 9.5.0 + globby: 11.1.0 + mylas: 2.1.13 + normalize-path: 3.0.0 + plimit-lit: 1.5.0 + dev: false + + /tsconfig-paths/4.1.2: + resolution: {integrity: sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==} + engines: {node: '>=6'} + dependencies: + json5: 2.2.3 + minimist: 1.2.7 + strip-bom: 3.0.0 + dev: false + + /tslib/2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + + /tsscmp/1.0.6: + resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} + engines: {node: '>=0.6.x'} + dev: false + + /tunnel-agent/0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + + /tweetnacl/0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + + /twemoji-parser/14.0.0: + resolution: {integrity: sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA==} + dev: false + + /type-check/0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + dev: false + + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + + /type-detect/4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: false + + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + /type-fest/0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-is/1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + + /type/1.2.0: + resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} + dev: false + + /type/2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + dev: false + + /typedarray-to-buffer/3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: false + + /typedarray/0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + dev: false + + /typeorm/0.3.11_zfbzyadn2rnu3hf3pysto5crhm: + resolution: {integrity: sha512-pzdOyWbVuz/z8Ww6gqvBW4nylsM0KLdUCDExr2gR20/x1khGSVxQkjNV/3YqliG90jrWzrknYbYscpk8yxFJVg==} + engines: {node: '>= 12.9.0'} + hasBin: true + peerDependencies: + '@google-cloud/spanner': ^5.18.0 + '@sap/hana-client': ^2.12.25 + better-sqlite3: ^7.1.2 || ^8.0.0 + hdb-pool: ^0.1.6 + ioredis: ^5.0.4 + mongodb: ^3.6.0 + mssql: ^7.3.0 + mysql2: ^2.2.5 + oracledb: ^5.1.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 + peerDependenciesMeta: + '@google-cloud/spanner': + optional: true + '@sap/hana-client': + optional: true + better-sqlite3: + optional: true + hdb-pool: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + dependencies: + '@sqltools/formatter': 1.2.5 + app-root-path: 3.1.0 + buffer: 6.0.3 + chalk: 4.1.2 + cli-highlight: 2.1.11 + date-fns: 2.29.3 + debug: 4.3.4 + dotenv: 16.0.3 + glob: 7.2.3 + ioredis: 5.2.4 + js-yaml: 4.1.0 + mkdirp: 1.0.4 + pg: 8.8.0 + reflect-metadata: 0.1.13 + sha.js: 2.4.11 + ts-node: 10.9.1_fodzh64fuekdilycyvke2qmf2e + tslib: 2.4.1 + uuid: 8.3.2 + xml2js: 0.4.23 + yargs: 17.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /typescript/4.9.4: + resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} + engines: {node: '>=4.2.0'} + hasBin: true + + /ulid/2.3.0: + resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==} + hasBin: true + dev: false + + /unbzip2-stream/1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + dependencies: + buffer: 5.7.1 + through: 2.3.8 + dev: false + + /unc-path-regex/0.1.2: + resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} + engines: {node: '>=0.10.0'} + dev: false + + /undertaker-registry/1.0.1: + resolution: {integrity: sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==} + engines: {node: '>= 0.10'} + dev: false + + /undertaker/1.3.0: + resolution: {integrity: sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==} + engines: {node: '>= 0.10'} + dependencies: + arr-flatten: 1.1.0 + arr-map: 2.0.2 + bach: 1.2.0 + collection-map: 1.0.0 + es6-weak-map: 2.0.3 + fast-levenshtein: 1.1.4 + last-run: 1.1.1 + object.defaults: 1.1.0 + object.reduce: 1.0.1 + undertaker-registry: 1.0.1 + dev: false + + /undici/5.15.0: + resolution: {integrity: sha512-wCAZJDyjw9Myv+Ay62LAoB+hZLPW9SmKbQkbHIhMw/acKSlpn7WohdMUc/Vd4j1iSMBO0hWwU8mjB7a5p5bl8g==} + engines: {node: '>=12.18'} + dependencies: + busboy: 1.6.0 + dev: false + + /union-value/1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + dev: false + + /uniq/1.0.1: + resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} + dev: false + + /uniqs/2.0.0: + resolution: {integrity: sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==} + dev: false + + /unique-filename/2.0.1: + resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + unique-slug: 3.0.0 + dev: false + + /unique-slug/3.0.0: + resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + dev: false + + /unique-stream/2.3.1: + resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==} + dependencies: + json-stable-stringify-without-jsonify: 1.0.1 + through2-filter: 3.0.0 + dev: false + + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + + /universalify/0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: false + + /universalify/2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + + /unload/2.4.1: + resolution: {integrity: sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==} + dev: false + + /unpipe/1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + + /unset-value/1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + dev: false + + /untildify/4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /unzipper/0.10.11: + resolution: {integrity: sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==} + dependencies: + big-integer: 1.6.51 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.10 + listenercount: 1.0.1 + readable-stream: 2.3.7 + setimmediate: 1.0.5 + dev: false + + /update-browserslist-db/1.0.10_browserslist@4.21.4: + resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.4 + escalade: 3.1.1 + picocolors: 1.0.0 + + /uri-js/4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.2.0 + + /urix/0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + dev: false + + /url-parse-lax/3.0.0: + resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} + engines: {node: '>=4'} + dependencies: + prepend-http: 2.0.0 + dev: false + + /url-parse/1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: false + + /url-polyfill/1.1.12: + resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==} + dev: false + + /url-to-options/1.0.1: + resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==} + engines: {node: '>= 4'} + dev: false + + /url/0.10.3: + resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + dependencies: + punycode: 1.3.2 + querystring: 0.2.0 + dev: false + + /urlsafe-base64/1.0.0: + resolution: {integrity: sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA==} + dev: false + + /use/3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + dev: false + + /utf-8-validate/5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.6.0 + dev: false + + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /util/0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.10 + which-typed-array: 1.1.9 + dev: false + + /uuid/3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: false + + /uuid/7.0.3: + resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} + hasBin: true + dev: false + + /uuid/8.0.0: + resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} + hasBin: true + dev: false + + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + /uuid/9.0.0: + resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + hasBin: true + dev: false + + /v8-compile-cache-lib/3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: false + + /v8flags/3.2.0: + resolution: {integrity: sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==} + engines: {node: '>= 0.10'} + dependencies: + homedir-polyfill: 1.0.3 + dev: false + + /validate-npm-package-license/3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + dev: false + + /value-or-function/3.0.0: + resolution: {integrity: sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==} + engines: {node: '>= 0.10'} + dev: false + + /vanilla-tilt/1.8.0: + resolution: {integrity: sha512-wVCHyyfRuiRdKhDTNxKPb60lkagmywDSqLgFETEr71Sm646AvGxuf/14Kx9A8FaISyYvMoKQHk6FTqt+YLGhEw==} + dev: false + + /vary/1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + + /vendors/1.0.4: + resolution: {integrity: sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==} + dev: false + + /verror/1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + + /vinyl-fs/3.0.3: + resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==} + engines: {node: '>= 0.10'} + dependencies: + fs-mkdirp-stream: 1.0.0 + glob-stream: 6.1.0 + graceful-fs: 4.2.10 + is-valid-glob: 1.0.0 + lazystream: 1.0.1 + lead: 1.0.0 + object.assign: 4.1.4 + pumpify: 1.5.1 + readable-stream: 2.3.7 + remove-bom-buffer: 3.0.0 + remove-bom-stream: 1.2.0 + resolve-options: 1.1.0 + through2: 2.0.5 + to-through: 2.0.0 + value-or-function: 3.0.0 + vinyl: 2.2.1 + vinyl-sourcemap: 1.1.0 + dev: false + + /vinyl-sourcemap/1.1.0: + resolution: {integrity: sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==} + engines: {node: '>= 0.10'} + dependencies: + append-buffer: 1.0.2 + convert-source-map: 1.9.0 + graceful-fs: 4.2.10 + normalize-path: 2.1.1 + now-and-later: 2.0.1 + remove-bom-buffer: 3.0.0 + vinyl: 2.2.1 + dev: false + + /vinyl-sourcemaps-apply/0.2.1: + resolution: {integrity: sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==} + dependencies: + source-map: 0.5.7 + dev: false + + /vinyl/2.2.1: + resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==} + engines: {node: '>= 0.10'} + dependencies: + clone: 2.1.2 + clone-buffer: 1.0.0 + clone-stats: 1.0.0 + cloneable-readable: 1.1.3 + remove-trailing-separator: 1.1.0 + replace-ext: 1.0.1 + dev: false + + /vite/4.1.0-beta.2_sass@1.57.1: + resolution: {integrity: sha512-B1V2qkELCaxgg1YptKyCmpY3/6LBXWW5iD5H6L4BizvWNhp2hGL7wAwBblfjqCuudVv9kcnJiL5uY2zqvZFr5Q==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.16.17 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.12.1 + sass: 1.57.1 + optionalDependencies: + fsevents: 2.3.2 + dev: false + + /void-elements/3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + + /vue-isyourpasswordsafe/2.0.0: + resolution: {integrity: sha512-j3ORj18R9AgFiP2UOM35KuZbSeJAUiwCSyeRBFN3CGFYTJSKsxqU9qGqOHOz6OhLAYKMTin8JOmqugAbF9O+Bg==} + dependencies: + sha1: 1.1.1 + dev: false + + /vue-plyr/7.0.0: + resolution: {integrity: sha512-NvbO/ZzV1IxlBQQbQlon5Sk8hKuGAj3k4k0XVdi7gM4oSqu8mZMhJ3WM3FfAtNfV790jbLnb8P3dHYqaBqIv6g==} + dependencies: + plyr: github.com/sampotts/plyr/d434c9af16e641400aaee93188594208d88f2658 + vue: 2.7.14 + dev: false + + /vue-prism-editor/2.0.0-alpha.2_vue@3.2.45: + resolution: {integrity: sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.2.45 + dev: false + + /vue/2.7.14: + resolution: {integrity: sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==} + dependencies: + '@vue/compiler-sfc': 2.7.14 + csstype: 3.1.1 + dev: false + + /vue/3.2.45: + resolution: {integrity: sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==} + dependencies: + '@vue/compiler-dom': 3.2.45 + '@vue/compiler-sfc': 3.2.45 + '@vue/runtime-dom': 3.2.45 + '@vue/server-renderer': 3.2.45_vue@3.2.45 + '@vue/shared': 3.2.45 + dev: false + + /vuedraggable/4.1.0_vue@3.2.45: + resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} + peerDependencies: + vue: ^3.0.1 + dependencies: + sortablejs: 1.14.0 + vue: 3.2.45 + dev: false + + /w3c-xmlserializer/4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + dependencies: + xml-name-validator: 4.0.0 + dev: false + + /wait-on/6.0.1_debug@4.3.4: + resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} + engines: {node: '>=10.0.0'} + hasBin: true + dependencies: + axios: 0.25.0_debug@4.3.4 + joi: 17.7.0 + lodash: 4.17.21 + minimist: 1.2.7 + rxjs: 7.8.0 + transitivePeerDependencies: + - debug + dev: true + + /wasm-feature-detect/1.4.0: + resolution: {integrity: sha512-9z4Yk3SeHQdb7E4g6ywQYcUt1CHr9HFiCIA5h29rv0gmW4lCE5dnDhheiJI5qzVPSDnXHyXQPLGPyucsuIzacw==} + dev: false + + /watchpack/2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.10 + + /web-push/3.5.0: + resolution: {integrity: sha512-JC0V9hzKTqlDYJ+LTZUXtW7B175qwwaqzbbMSWDxHWxZvd3xY0C2rcotMGDavub2nAAFw+sXTsqR65/KY2A5AQ==} + engines: {node: '>= 6'} + hasBin: true + dependencies: + asn1.js: 5.4.1 + http_ece: 1.1.0 + https-proxy-agent: 5.0.1 + jws: 4.0.0 + minimist: 1.2.7 + urlsafe-base64: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /web-streams-polyfill/3.2.1: + resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} + engines: {node: '>= 8'} + + /webidl-conversions/3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /webidl-conversions/7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: false + + /webpack-sources/3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + + /webpack/5.75.0_@swc+core@1.3.26: + resolution: {integrity: sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.4 + '@types/estree': 0.0.51 + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/wasm-edit': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + acorn: 8.8.1 + acorn-import-assertions: 1.8.0_acorn@8.8.1 + browserslist: 4.21.4 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.12.0 + es-module-lexer: 0.9.3 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.10 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.1.1 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.6_v4imsvpumnwpgduroyqmpcfjiy + watchpack: 2.4.0 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + /websocket/1.0.34: + resolution: {integrity: sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==} + engines: {node: '>=4.0.0'} + dependencies: + bufferutil: 4.0.7 + debug: 2.6.9 + es5-ext: 0.10.62 + typedarray-to-buffer: 3.1.5 + utf-8-validate: 5.0.10 + yaeti: 0.0.6 + transitivePeerDependencies: + - supports-color + dev: false + + /whatwg-encoding/2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + dependencies: + iconv-lite: 0.6.3 + dev: false + + /whatwg-mimetype/3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + dev: false + + /whatwg-url/11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + dev: false + + /whatwg-url/5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /whet.extend/0.9.9: + resolution: {integrity: sha512-mmIPAft2vTgEILgPeZFqE/wWh24SEsR/k+N9fJ3Jxrz44iDFy9aemCxdksfURSHYFCLmvs/d/7Iso5XjPpNfrA==} + engines: {node: '>=0.6.0'} + dev: false + + /which-module/1.0.0: + resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} + dev: false + + /which-module/2.0.0: + resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} + dev: false + + /which-typed-array/1.1.9: + resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + is-typed-array: 1.1.10 + dev: false + + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + + /wide-align/1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: false + + /with/7.0.2: + resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} + engines: {node: '>= 10.0.0'} + dependencies: + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + assert-never: 1.2.1 + babel-walk: 3.0.0-canary-5 + + /word-wrap/1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + + /workerpool/6.2.1: + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + dev: false + + /wrap-ansi/2.1.0: + resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} + engines: {node: '>=0.10.0'} + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + dev: false + + /wrap-ansi/6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /ws/8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xev/3.0.2: + resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==} + dev: false + + /xml-js/1.6.11: + resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} + hasBin: true + dependencies: + sax: 1.2.4 + dev: false + + /xml-name-validator/4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: false + + /xml2js/0.4.19: + resolution: {integrity: sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==} + dependencies: + sax: 1.2.4 + xmlbuilder: 9.0.7 + dev: false + + /xml2js/0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.2.4 + xmlbuilder: 11.0.1 + dev: false + + /xmlbuilder/11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: false + + /xmlbuilder/9.0.7: + resolution: {integrity: sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==} + engines: {node: '>=4.0'} + dev: false + + /xmlchars/2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: false + + /xtend/4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + + /y18n/3.2.2: + resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} + dev: false + + /y18n/4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false + + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false + + /yaeti/0.0.6: + resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} + engines: {node: '>=0.10.32'} + dev: false + + /yallist/2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + + /yallist/3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false + optional: true + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yaml-ast-parser/0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + dev: false + + /yargs-parser/18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + + /yargs-parser/20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + dev: false + + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: false + + /yargs-parser/21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: false + + /yargs-parser/5.0.1: + resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==} + dependencies: + camelcase: 3.0.0 + object.assign: 4.1.4 + dev: false + + /yargs-unparser/2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: false + + /yargs/15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.0 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: false + + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: false + + /yargs/17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + /yargs/7.1.2: + resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==} + dependencies: + camelcase: 3.0.0 + cliui: 3.2.0 + decamelize: 1.2.0 + get-caller-file: 1.0.3 + os-locale: 1.4.0 + read-pkg-up: 1.0.1 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 1.0.2 + which-module: 1.0.0 + y18n: 3.2.2 + yargs-parser: 5.0.1 + dev: false + + /yauzl/2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + /ylru/1.3.2: + resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==} + engines: {node: '>= 4.0.0'} + dev: false + + /yn/3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: false + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + /zip-stream/4.1.0: + resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + compress-commons: 4.1.1 + readable-stream: 3.6.0 + dev: false + + /zlibjs/0.3.1: + resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} + dev: false + + github.com/misskey-dev/browser-image-resizer/0380d12c8e736788ea7f4e6e985175521ea7b23c: + resolution: {tarball: https://codeload.github.com/misskey-dev/browser-image-resizer/tar.gz/0380d12c8e736788ea7f4e6e985175521ea7b23c} + name: browser-image-resizer + version: 2.2.1-misskey.3 + dev: false + + github.com/sampotts/plyr/d434c9af16e641400aaee93188594208d88f2658: + resolution: {tarball: https://codeload.github.com/sampotts/plyr/tar.gz/d434c9af16e641400aaee93188594208d88f2658} + name: plyr + version: 3.7.0 + dependencies: + core-js: 3.27.1 + custom-event-polyfill: 1.0.7 + loadjs: 4.2.0 + rangetouch: 2.0.1 + url-polyfill: 1.1.12 + dev: false diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 000000000..87d240173 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - 'packages/backend' + - 'packages/client' + - 'packages/sw' diff --git a/release.json b/release.json new file mode 100644 index 000000000..075c49d7f --- /dev/null +++ b/release.json @@ -0,0 +1,5 @@ +{ + "version": "13.1.0", + "notes": "This release includes many changes, including:\n\n• New post and thread layout\n• Automatic subdomain blocks\n• Customizable default reactions\n• Federation improvements\n• Many bug fixes and performance improvements", + "screenshots": [] +} diff --git a/rome.json b/rome.json new file mode 100644 index 000000000..6b74808ed --- /dev/null +++ b/rome.json @@ -0,0 +1,9 @@ +{ + "$schema": "./node_modules/rome/configuration_schema.json", + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + } +} \ No newline at end of file diff --git a/scripts/clean-all.js b/scripts/clean-all.js index 456b88032..e347ee6a9 100644 --- a/scripts/clean-all.js +++ b/scripts/clean-all.js @@ -1,4 +1,5 @@ const fs = require('fs'); +const execa = require('execa'); (async () => { fs.rmSync(__dirname + '/../packages/backend/built', { recursive: true, force: true }); @@ -12,4 +13,9 @@ const fs = require('fs'); fs.rmSync(__dirname + '/../built', { recursive: true, force: true }); fs.rmSync(__dirname + '/../node_modules', { recursive: true, force: true }); + + execa('pnpm', ['store', 'prune'], { + cwd: __dirname + '/../', + stdio: 'inherit' + }); })(); diff --git a/scripts/dev.js b/scripts/dev.js index b0fe12ee3..7a61070f5 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -1,31 +1,31 @@ const execa = require('execa'); (async () => { - await execa('yarn', ['clean'], { + await execa('pnpm', ['clean'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, }); - execa('yarn', ['dlx', 'gulp', 'watch'], { + execa('pnpm', ['dlx', 'gulp', 'watch'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, }); - execa('yarn', ['workspace', 'backend', 'watch'], { + execa('pnpm', ['--filter', 'backend', 'watch'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, }); - execa('yarn', ['workspace', 'client', 'watch'], { + execa('pnpm', ['--filter', 'client', 'watch'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, }); - execa('yarn', ['workspace', 'sw', 'watch'], { + execa('pnpm', ['--filter', 'sw', 'watch'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, @@ -33,7 +33,7 @@ const execa = require('execa'); const start = async () => { try { - await execa('yarn', ['start'], { + await execa('pnpm', ['start'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr,