({overlay:{zIndex:1e3,position:"fixed",display:"flex",justifyContent:"center",alignItems:"center",top:0,left:0,bottom:0,right:0,background:"rgba(64, 64, 64, .65)",backdropFilter:"blur(16px)",WebkitBackdropFilter:"blur(16px)",opacity:0,transition:"opacity .15s","&.active":{opacity:1}},content:{width:"calc(50vw - 32px)",height:"calc(75vh - 32px)",overflow:"auto",padding:16,"@media screen and (max-width: 1200px)":{width:"calc(100vw - 64px)",height:"calc(100vh - 64px)",padding:32},"& .top":{display:"flex",alignItems:"center","& input":{background:"none",border:"none",outline:"none",fontSize:24,display:"block",flexGrow:1,color:"white","&::placeholder":{color:"rgba(255, 255, 255, .25)"}}},color:"#e0e0e0"},results:{"& .loading":{textAlign:"center",marginTop:128,fontSize:24},"& .empty":{fontSize:24,fontStyle:"italic",opacity:.25},"& a":{display:"flex",alignItems:"center",color:"white !important",textDecoration:"none !important",padding:16,fontSize:24,margin:"0 -16",borderRadius:3,opacity:.75,outline:"none",background:"transparent",borderBottom:"1px solid rgba(255, 255, 255, .05)",cursor:"pointer",transition:"background .15s, opacity .15s, border-color .15s !important","&:hover, &:focus":{opacity:1,background:"rgba(156, 156, 156, .25)",borderColor:"transparent"},"& .title":{flexGrow:1},"& .current":{fontSize:12,color:t.light.primary,"body.dark &":{color:t.dark.primary}}}},close:{position:"relative",display:"flex",justifyContent:"center",alignItems:"center",cursor:"pointer",opacity:.25,width:64,height:64,borderRadius:3,transition:"opacity .15s","&:hover":{opacity:1},"&:before, &:after":{content:'" "',background:"white",borderRadius:2,width:48,height:2,position:"absolute",transformOrigin:"center"},"&:before":{transform:"rotate(45deg)"},"&:after":{transform:"rotate(-45deg)"}}})),ta=To(t=>({holder:{position:"relative",display:"inline-flex",verticalAlign:"middle",alignItems:"center",justifyContent:"center",width:"1.5em",height:"1.5em"},spinner:{width:"100%",height:"100%",animation:"$rotate 1.17s linear infinite"},"@keyframes rotate":{"0%":{transform:"rotate(0deg)"},"100%":{transform:"rotate(360deg)"}},path:{strokeDasharray:200,strokeDashoffset:0,transformOrigin:"33px 33px !important",fill:"none",strokeWidth:3,strokeLinecap:"round",cx:"33px",cy:"33px",r:"30px",animation:"$dash 1s ease-in-out infinite",stroke:"white","&.black":{stroke:"black"},"body.dark-mode-animate &":{transition:"color .3s"},"&.primary":{stroke:t.light.primary,"body.dark &":{stroke:t.dark.primary},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate)":{stroke:t.dark.primary}}},"&.primary-contrast":{stroke:t.light.primaryContrast,"body.dark &":{stroke:t.dark.primaryContrast},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate)":{stroke:t.dark.primaryContrast}}},"&.background":{stroke:t.light.background,"body.dark &":{stroke:t.dark.background},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate)":{stroke:t.dark.background}}},"&.text":{stroke:t.light.text,"body.dark &":{stroke:t.dark.text},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate)":{stroke:t.dark.text}}}},"@keyframes dash":{"0%":{strokeDashoffset:200},"50%":{strokeDashoffset:50,transform:"rotate(45deg)"},"100%":{strokeDashoffset:200,transform:"rotate(360deg)"}}}));function ea(t,e){const r=this.theme.classes(ta);return e.create("div",{class:r.holder},e.create("svg",{class:r.spinner,viewBox:"0 0 66 66",xmlns:"http://www.w3.org/2000/svg"},e.create("circle",{class:`${r.path} ${t.color||""}`,xmlns:"http://www.w3.org/2000/svg"})))}function ra(t,e){const r=this.theme.classes(Qs),n=v(),i=v(),o=v(),s=()=>{let t=void 0,e=void 0,r=void 0,i=void 0,o=void 0;n.$.querySelectorAll("a[tabindex]").forEach(n=>{i||(i=n),n===document.activeElement?t=n:t?r||(r=n):e=n,o=n});const s={};return s.next=r||i,s.prev=e||o,s};this.track({bind(){i.$.focus(),n.$.classList.add("active"),o.resolve(document.getElementById("-codedoc-toc")||e.create("fragment",null)),"backdropFilter"in n.$.style||"-webkit-backdrop-filter"in n.$.style||(n.$.style.background="rgba(64, 64, 64, .95)")}});const a=ee(localStorage.getItem("-codedoc-search-query")||""),c=ee(!1),u=this.expose.out("query"),f=this.expose.in("results",Object($t.b)()).to(Object(Ut.b)(Dt())).to(ne(t=>{const e=t.map(t=>{const e=us();return e&&(t=e.namespace+t),{link:t,title:d(t)}});return a.value.length>0&&o.$.querySelectorAll("a").forEach(r=>{var n;(null===(n=r.textContent)||void 0===n?void 0:n.toLowerCase().includes(a.value.toLowerCase()))&&r.getAttribute("href")&&!t.includes(r.getAttribute("href")||"")&&e.push({link:r.getAttribute("href")||"",title:r.textContent})}),e})).to(Object(pt.a)(t=>{t.length>0&&(localStorage.setItem("-codedoc-search-query",a.value),localStorage.setItem("-codedoc-search-res",JSON.stringify(t)))})).to(Object(Ut.b)(Mo(tt(JSON.parse(localStorage.getItem("-codedoc-search-res")||"[]")))));a.to(Ft(t=>t&&t.trim().length>0)).to(c.from(ne(()=>!0)),u.from(Object(Ut.b)(Ho(1e3)))),f.to(ne(()=>!1)).to(c);const h=jo(a,f,c).to(ne(([t,e,r])=>!!r||(!t||0==t.trim().length||e.length>0))),d=t=>{var e;return(null===(e=o.$.querySelector(`a[href="${t}"]`))||void 0===e?void 0:e.textContent)||t},l=(t=!0)=>{n.$.remove(),t&&localStorage.removeItem("-codedoc-search-query")};return e.create("div",{class:r.overlay,_ref:n,onkeydown:t=>{const e=t.key;if("Escape"===e&&(t.preventDefault(),t.stopPropagation(),l()),"ArrowDown"===e){const e=s();e.next&&(e.next.focus(),t.preventDefault(),t.stopPropagation())}if("ArrowUp"===e){const e=s();e.prev&&(e.prev.focus(),t.preventDefault(),t.stopPropagation())}"ArrowLeft"!==e&&"ArrowRight"!==e||t.stopPropagation()}},e.create("div",{class:r.content},e.create("div",{class:"top"},e.create("input",{placeholder:t.placeholder,type:"text",_ref:i,_state:a}),e.create("div",{class:r.close,onclick:()=>{a.value.length>0?a.value="":l()}})),e.create("div",{class:r.results},e.create("div",{class:"loading",hidden:c.to(ne(t=>!t))},e.create(ea,null)),e.create("div",{class:"empty",hidden:h},"No Results!"),e.create("div",{hidden:c},e.create(Zs,{of:f,each:t=>e.create("a",{href:t.sub("link"),tabindex:"0",onclick:()=>{l(!1),window.dispatchEvent(new CustomEvent("on-navigation-search",{detail:{query:a.value}}))}},e.create("span",{class:"title"},t.sub("title")),e.create("span",{class:"current",hidden:t.sub("link").to(ne(t=>t!==location.pathname))},"Search on Current Page"))})))))}function na(t,e){const r=this.theme.classes(Fs),n=this.expose.in("results"),i=this.expose.out("query",it()),o=v(),s=t=>{"f"===t.key&&(t.ctrlKey||t.metaKey)&&(t.preventDefault(),o.$.click())};return this.track({bind(){document.addEventListener("keydown",s)},clear(){document.removeEventListener("keydown",s)}}),e.create("div",{_ref:o,class:r.holder,id:"-codedoc-search-btn",onclick:()=>{e.render(e.create(ra,{placeholder:t.label||"Search the docs...",query:t=>i.send(t),results:n})).on(document.body)}},e.create("span",{class:"label"},t.label||"Search the docs..."),e.create("span",{class:"icon-font"},"search"))}function ia(t,e){const r=new B.a,n=new RegExp(t.pick),i=new RegExp(t.drop),o={},s=r.pipe(Yo(e=>{return e in o?ue({result:o[e]}):zs.getJSON("https://api.github.com/search/code?q="+encodeURIComponent(e)+"+in:file+path:"+t.root+"+extension:md"+`+repo:${t.user}/${t.repo}`).pipe((r=()=>ue(void 0),function(t){var e=new Us(r),n=t.lift(e);return e.caught=n}));var r}),Object(q.a)(e=>e?function(t){return void 0!==t.result}(e)?e.result:e.items.map(t=>t.path).filter(t=>n.test(t)).filter(t=>!i.test(t)).map(t=>t.substr(0,t.length-3)).map(e=>e.substr(t.root.length)).map(t=>"/index"===t?"/":t):[]),Dt());return le(r,s).pipe(Object(st.a)(([t,e])=>{e.length>0&&(o[t]=e)})).subscribe(),e.create(na,{label:t.label,query:r,results:s})}const oa=To(t=>({tocToggle:{display:"inline-flex",justifyContent:"center",alignItems:"center",width:48,height:48,cursor:"pointer",opacity:.25,overflow:"hidden",position:"relative",transition:"opacity .15s","&:hover":{opacity:1}},bar:{width:24,height:2,borderRadius:2,position:"absolute",background:t.light.text,transformOrigin:"center",transition:"transform .15s, opacity .15s","&:first-child":{transform:"translateY(-6px)"},"&:last-child":{transform:"translateY(6px)"},"body.dark &":{background:t.dark.text},".active>&":{opacity:0,"&:first-child":{transform:"translateY(0) rotate(45deg)",opacity:1},"&:last-child":{transform:"translateY(0) rotate(-45deg)",opacity:1}}}}));function sa(t,e){const r=this.theme.classes(oa),n=v(),i=ee(!1);return this.track({bind(){const t=document.getElementById("-codedoc-toc");t&&(n.resolve(t),"true"===localStorage.getItem("-codedoc-toc-active")&&(i.value=!0),setTimeout(()=>t.classList.add("animated"),1)),window.codedocToggleToC=t=>{i.value=void 0!==t?t:!i.value}}}),this.track(i.to(Object(pt.a)(t=>{n.resolved&&(t?n.$.classList.add("active"):n.$.classList.remove("active")),localStorage.setItem("-codedoc-toc-active",!0===t?"true":"false")}))),e.create("div",{class:Oo`${r.tocToggle} ${Ro({active:i})}`,onclick:()=>i.value=!i.value},e.create("div",{class:r.bar}),e.create("div",{class:r.bar}),e.create("div",{class:r.bar}))}const aa=To(t=>({dmSwitch:{overflow:"hidden",display:"inline-flex",width:48,height:48,cursor:"pointer",alignItems:"center",justifyContent:"center",position:"relative",opacity:.25,"&:hover":{opacity:1},"body.dark-mode-animate &":{transition:"opacity .1s, transform .3s"},"& div":{position:"absolute",background:t.light.text,"body.dark-mode-animate &":{transition:"transform .3s, background .3s, opacity .3s"},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate) &":{background:t.dark.text}},"body.dark &":{background:t.dark.text}},"& .arc, & .darc":{width:16,height:16,borderRadius:16},"& .darc":{background:t.light.background,transform:"translateX(24px)",opacity:0},"& .ray":{width:6,height:2,borderRadius:2},"& .ray.one":{transform:"rotate(0deg) translateX(14px)"},"& .ray.two":{transform:"rotate(45deg) translateX(14px)"},"& .ray.three":{transform:"rotate(90deg) translateX(14px)"},"& .ray.four":{transform:"rotate(135deg) translateX(14px)"},"& .ray.five":{transform:"rotate(180deg) translateX(14px)"},"& .ray.six":{transform:"rotate(225deg) translateX(14px)"},"& .ray.seven":{transform:"rotate(270deg) translateX(14px)"},"& .ray.eight":{transform:"rotate(315deg) translateX(14px)"},"@media (prefers-color-scheme: dark)":{"body:not(.dark-mode-animate) &":{transform:"rotate(-45deg)","& .arc":{transform:"scale(1.2)"},"& .darc":{transform:"translateX(6px)",background:t.dark.background,opacity:1},"& .ray":{transform:"scale(0.001)",opacity:0}}},"body.dark &":{transform:"rotate(-45deg)","& .arc":{transform:"scale(1.2)"},"& .darc":{transform:"translateX(6px)",background:t.dark.background,opacity:1},"& .ray":{transform:"scale(0.001)",opacity:0}}}}));var ca;function ua(t,e){const r=this.theme.classes(aa),n=function(){const t=ee(ca.Light).bind();if(window.matchMedia){const e=window.matchMedia("(prefers-color-scheme: dark)");e.matches&&(t.value=ca.Dark),e.addListener(()=>{e.matches?t.value=ca.Dark:t.value=ca.Light})}return t}(),i=ee();let o=!1;return n.to(i),this.track(i.to(Object(pt.a)(t=>{t===ca.Light?document.body.classList.remove("dark"):document.body.classList.add("dark"),o&&(t!==n.value?localStorage.setItem("dark-mode",t===ca.Light?"false":"true"):localStorage.removeItem("dark-mode"))}))),this.track({bind(){localStorage.getItem("dark-mode")&&(i.value="true"===localStorage.getItem("dark-mode")?ca.Dark:ca.Light),document.body.classList.add("dark-mode-animate"),o=!0}}),e.create("div",{class:r.dmSwitch,onclick:()=>i.value=i.value===ca.Light?ca.Dark:ca.Light},e.create("div",{class:"arc"}),e.create("div",{class:"darc"}),e.create("div",{class:"ray one"}),e.create("div",{class:"ray two"}),e.create("div",{class:"ray three"}),e.create("div",{class:"ray four"}),e.create("div",{class:"ray five"}),e.create("div",{class:"ray six"}),e.create("div",{class:"ray seven"}),e.create("div",{class:"ray eight"}))}!function(t){t[t.Dark=0]="Dark",t[t.Light=1]="Light"}(ca||(ca={}));Zi(),oo(),po(),bo(),qo(),ls(),lo(),ps(),bs(),vs(),Object(ys.a)(),ms(),ks();const fa={"qcaKEY878Mn2dFQW/lSrDg==":Ss,"fz894w7KG2/tX4kLbbA1Kg==":Es,"+SrlfVhZ/PRQ5WhUlZbTaA==":ia,"XsNW3ht5ee+RmVUActEo9g==":sa,"Y1WWvCKxkgk1yh8xbCfXqw==":ua,"v641FmLj+AeGp0uuFTI6ug==":cs},ha=rn(),da=window.__sdh_transport;window.__sdh_transport=function(t,e,r){if(e in fa){const n=document.getElementById(t);ha.render(ha.create(fa[e],r)).after(n),n.remove()}else da&&da(t,e,r)}},function(t,e,r){"use strict";r.d(e,"a",(function(){return o}));var n=r(67),i=r(60);function o(t){const e=Object(n.a)();return e?(t.__transport_info=Object(i.b)(t.name,e),t):t}},function(t,e,r){"use strict";function n(t){"loading"!=document.readyState?setTimeout(t,1):window.addEventListener("DOMContentLoaded",t)}r.d(e,"a",(function(){return n}))},function(t,e,r){"use strict";function n(t){return!!t.clear&&"function"==typeof t.clear}r.d(e,"a",(function(){return n}))},function(t,e,r){"use strict";function n(t){return void 0!==t&&"function"==typeof t.from&&"function"==typeof t.to&&"observable"in t&&"function"==typeof t.subscribe}r.d(e,"a",(function(){return n}))},function(t,e,r){"use strict";r.d(e,"a",(function(){return a}));var n=r(1),i=r(7);function o(){}var s=r(32);function a(t,e,r){return function(n){return n.lift(new c(t,e,r))}}var c=function(){function t(t,e,r){this.nextOrObserver=t,this.error=e,this.complete=r}return t.prototype.call=function(t,e){return e.subscribe(new u(t,this.nextOrObserver,this.error,this.complete))},t}(),u=function(t){function e(e,r,n,i){var a=t.call(this,e)||this;return a._tapNext=o,a._tapError=o,a._tapComplete=o,a._tapError=n||o,a._tapComplete=i||o,Object(s.a)(r)?(a._context=a,a._tapNext=r):r&&(a._context=r,a._tapNext=r.next||o,a._tapError=r.error||o,a._tapComplete=r.complete||o),a}return n.a(e,t),e.prototype._next=function(t){try{this._tapNext.call(this._context,t)}catch(t){return void this.destination.error(t)}this.destination.next(t)},e.prototype._error=function(t){try{this._tapError.call(this._context,t)}catch(t){return void this.destination.error(t)}this.destination.error(t)},e.prototype._complete=function(){try{this._tapComplete.call(this._context)}catch(t){return void this.destination.error(t)}return this.destination.complete()},e}(i.a)}]);
\ No newline at end of file
diff --git a/docs/dist/codedoc-bundle.meta.json b/docs/dist/codedoc-bundle.meta.json
deleted file mode 100644
index 50fa9db..0000000
--- a/docs/dist/codedoc-bundle.meta.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "init": [
- {
- "name": "initJssCs",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/transport/setup-jss.js",
- "hash": "c/OJpUDX26Qm4IbMYtLbjg=="
- },
- {
- "name": "installTheme",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/content/theme.ts",
- "hash": "obU6UstdkSAvgbysOh3/eg=="
- },
- {
- "name": "codeSelection",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/code/selection.js",
- "hash": "4VXGhMNJRz8Eyjdvm6ntYg=="
- },
- {
- "name": "sameLineLengthInCodes",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/code/same-line-length.js",
- "hash": "nEpV43sODVDt+zjIO7H9+A=="
- },
- {
- "name": "initHintBox",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/code/line-hint/index.js",
- "hash": "9M6+/niHbbHMYKbOF0DTzg=="
- },
- {
- "name": "initCodeLineRef",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/code/line-ref/index.js",
- "hash": "rPwNL8eX+bbHwAgvTQ8Iag=="
- },
- {
- "name": "initSmartCopy",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/code/smart-copy.js",
- "hash": "xFnLgdNzBUv9BdaGDgvJDA=="
- },
- {
- "name": "copyHeadings",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/heading/copy-headings.js",
- "hash": "i1yTTWSH2AaFOCy2yKgs0Q=="
- },
- {
- "name": "contentNavHighlight",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/page/contentnav/highlight.js",
- "hash": "SpIa+6Gg/KMV7Wb4QvBzcg=="
- },
- {
- "name": "loadDeferredIFrames",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/transport/deferred-iframe.js",
- "hash": "naHAbpxvOw4i/sUpn2LnRQ=="
- },
- {
- "name": "smoothLoading",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/transport/smooth-loading.js",
- "hash": "vXAT5HUat2IZoc8ZEN/OKA=="
- },
- {
- "name": "tocHighlight",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/page/toc/toc-highlight.js",
- "hash": "suB+mCUXKx/0sad/yURMug=="
- },
- {
- "name": "postNavSearch",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/page/toc/search/post-nav/index.js",
- "hash": "/izvKWQZGCWZbwwWyiivfw=="
- }
- ],
- "components": [
- {
- "name": "ToCPrevNext",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/page/toc/prevnext/index.js",
- "hash": "qcaKEY878Mn2dFQW/lSrDg=="
- },
- {
- "name": "CollapseControl",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/collapse/collapse-control.js",
- "hash": "fz894w7KG2/tX4kLbbA1Kg=="
- },
- {
- "name": "GithubSearch",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/misc/github/search.js",
- "hash": "+SrlfVhZ/PRQ5WhUlZbTaA=="
- },
- {
- "name": "ToCToggle",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/page/toc/toggle/index.js",
- "hash": "XsNW3ht5ee+RmVUActEo9g=="
- },
- {
- "name": "DarkModeSwitch",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/components/darkmode/index.js",
- "hash": "Y1WWvCKxkgk1yh8xbCfXqw=="
- },
- {
- "name": "ConfigTransport",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/transport/config.js",
- "hash": "v641FmLj+AeGp0uuFTI6ug=="
- }
- ],
- "renderer": {
- "name": "getRenderer",
- "filename": "/Users/nicco/Documents/git/autorestic/.codedoc/node_modules/@codedoc/core/dist/es6/transport/renderer.js",
- "hash": "DuikI/Y5reNcodaSzsxs0w=="
- }
-}
\ No newline at end of file
diff --git a/docs/dist/codedoc-styles.css b/docs/dist/codedoc-styles.css
deleted file mode 100644
index 3b4ff83..0000000
--- a/docs/dist/codedoc-styles.css
+++ /dev/null
@@ -1,871 +0,0 @@
-.heading-0-0-1 {
- cursor: pointer;
- position: relative;
-}
-.anchor-0-0-2 {
- top: 0;
- left: -32px;
- bottom: 0;
- display: flex;
- opacity: 0;
- position: absolute;
- transform: translateX(-8px);
- transition: opacity .1s, transform .1s;
- align-items: center;
- padding-right: 8px;
-}
-.heading-0-0-1:hover .anchor-0-0-2 {
- opacity: 0.5;
- transform: none;
-}
-.heading-0-0-1:hover .anchor-0-0-2:hover {
- opacity: 1;
-}
-.code-0-0-3 {
- color: #e0e0e0;
- display: block;
- outline: none;
- padding: 24px 0;
- position: relative;
- font-size: 13px;
- background: #212121;
- box-shadow: 0 6px 12px rgba(0, 0, 0, .25);
- overflow-x: auto;
- user-select: none;
- border-radius: 3px;
- -webkit-user-select: none;
-}
-pre.with-bar .code-0-0-3 {
- padding-top: 0;
-}
-.code-0-0-3 .token.keyword {
- color: #7187ff;
-}
-.code-0-0-3 .token.string {
- color: #69f0ae;
-}
-.code-0-0-3 .token.number {
- color: #ffc400;
-}
-.code-0-0-3 .token.boolean {
- color: #ffc400;
-}
-.code-0-0-3 .token.operator {
- color: #18ffff;
-}
-.code-0-0-3 .token.function {
- color: #e0e0e0;
-}
-.code-0-0-3 .token.parameter {
- color: #e0e0e0;
-}
-.code-0-0-3 .token.comment {
- color: #757575;
-}
-.code-0-0-3 .token.tag {
- color: #ffa372;
-}
-.code-0-0-3 .token.builtin {
- color: #e0e0e0;
-}
-.code-0-0-3 .token.punctuation {
- color: #fcf7bb;
-}
-.code-0-0-3 .token.class-name {
- color: #e0e0e0;
-}
-.code-0-0-3 .token.attr-name {
- color: #f6d186;
-}
-.code-0-0-3 .token.attr-value {
- color: #69f0ae;
-}
-.code-0-0-3 .token.plain-text {
- color: #bdbdbd;
-}
-.code-0-0-3 .token.script {
- color: #e0e0e0;
-}
-.code-0-0-3 .token.placeholder {
- color: #18ffff;
-}
-.code-0-0-3 .token.selector {
- color: #ffa372;
-}
-.code-0-0-3 .token.property {
- color: #f6d186;
-}
-.code-0-0-3 .token.important {
- color: #be79df;
-}
-.code-0-0-3.scss .token.function, .code-0-0-3.css .token.function, .code-0-0-3.sass .token.function {
- color: #9aceff;
-}
-.code-0-0-3 .token.key {
- color: #f6d186;
-}
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .code-0-0-3 {
- color: #e0e0e0;
- background: #000000;
- box-shadow: 0 6px 12px #121212;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.keyword {
- color: #7187ff;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.string {
- color: #69f0ae;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.number {
- color: #ffc400;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.boolean {
- color: #ffc400;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.operator {
- color: #18ffff;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.function {
- color: #e0e0e0;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.parameter {
- color: #e0e0e0;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.comment {
- color: #757575;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.tag {
- color: #ffa372;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.builtin {
- color: #e0e0e0;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.punctuation {
- color: #fcf7bb;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.class-name {
- color: #e0e0e0;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.attr-name {
- color: #f6d186;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.attr-value {
- color: #69f0ae;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.plain-text {
- color: #bdbdbd;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.script {
- color: #e0e0e0;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.placeholder {
- color: #18ffff;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.selector {
- color: #ffa372;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.property {
- color: #f6d186;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.important {
- color: #be79df;
- }
- body:not(.dark-mode-animate) .code-0-0-3.scss .token.function, body:not(.dark-mode-animate) .code-0-0-3.css .token.function, body:not(.dark-mode-animate) .code-0-0-3.sass .token.function {
- color: #9aceff;
- }
- body:not(.dark-mode-animate) .code-0-0-3 .token.key {
- color: #f6d186;
- }
-}
- body.dark .code-0-0-3 {
- color: #e0e0e0;
- background: #000000;
- box-shadow: 0 6px 12px #121212;
- }
- body.dark .code-0-0-3 .token.keyword {
- color: #7187ff;
- }
- body.dark .code-0-0-3 .token.string {
- color: #69f0ae;
- }
- body.dark .code-0-0-3 .token.number {
- color: #ffc400;
- }
- body.dark .code-0-0-3 .token.boolean {
- color: #ffc400;
- }
- body.dark .code-0-0-3 .token.operator {
- color: #18ffff;
- }
- body.dark .code-0-0-3 .token.function {
- color: #e0e0e0;
- }
- body.dark .code-0-0-3 .token.parameter {
- color: #e0e0e0;
- }
- body.dark .code-0-0-3 .token.comment {
- color: #757575;
- }
- body.dark .code-0-0-3 .token.tag {
- color: #ffa372;
- }
- body.dark .code-0-0-3 .token.builtin {
- color: #e0e0e0;
- }
- body.dark .code-0-0-3 .token.punctuation {
- color: #fcf7bb;
- }
- body.dark .code-0-0-3 .token.class-name {
- color: #e0e0e0;
- }
- body.dark .code-0-0-3 .token.attr-name {
- color: #f6d186;
- }
- body.dark .code-0-0-3 .token.attr-value {
- color: #69f0ae;
- }
- body.dark .code-0-0-3 .token.plain-text {
- color: #bdbdbd;
- }
- body.dark .code-0-0-3 .token.script {
- color: #e0e0e0;
- }
- body.dark .code-0-0-3 .token.placeholder {
- color: #18ffff;
- }
- body.dark .code-0-0-3 .token.selector {
- color: #ffa372;
- }
- body.dark .code-0-0-3 .token.property {
- color: #f6d186;
- }
- body.dark .code-0-0-3 .token.important {
- color: #be79df;
- }
- body.dark .code-0-0-3.scss .token.function, body.dark .code-0-0-3.css .token.function, body.dark .code-0-0-3.sass .token.function {
- color: #9aceff;
- }
- body.dark .code-0-0-3 .token.key {
- color: #f6d186;
- }
- .lineCounter-0-0-4 {
- left: 0;
- color: transparent;
- width: 24px;
- height: 1.25rem;
- display: inline-flex;
- position: sticky;
- font-size: 10px;
- background: #212121;
- align-items: center;
- border-right: 2px solid rgba(255, 255, 255, .015);
- margin-right: 12px;
- padding-right: 12px;
- flex-direction: row-reverse;
- vertical-align: top;
- }
- .lineCounter-0-0-4.prim {
- color: #616161;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .lineCounter-0-0-4 {
- background: #000000;
- border-color: rgba(255, 255, 255, .015);
- }
- body:not(.dark-mode-animate) .lineCounter-0-0-4.prim {
- color: #616161;
- }
-}
- body.dark .lineCounter-0-0-4 {
- background: #000000;
- border-color: rgba(255, 255, 255, .015);
- }
- body.dark .lineCounter-0-0-4.prim {
- color: #616161;
- }
- .line-0-0-5 {
- cursor: pointer;
- height: 1.25rem;
- display: inline-block;
- min-width: 100%;
- background: transparent;
- transition: opacity .15s;
- }
- .has-selection .line-0-0-5:not(.selected) {
- opacity: 0.35;
- transition: opacity 3s;
- }
- .line-0-0-5.highlight {
- color: #ffffff;
- background: rgb(40, 46, 73);
- }
- .line-0-0-5.selected .lineCounter-0-0-4 {
- border-color: #7187ff !important;
- }
- .line-0-0-5:hover, .line-0-0-5.selected {
- background: #3b3b3b;
- }
- .line-0-0-5:hover .lineCounter-0-0-4 {
- border-color: rgba(255, 255, 255, .1);
- }
- body.dark .line-0-0-5:hover .lineCounter-0-0-4 {
- border-color: rgba(255, 255, 255, .1);
- }
- .line-0-0-5:hover .lineCounter-0-0-4, .line-0-0-5.selected .lineCounter-0-0-4 {
- color: #7187ff;
- background: #3b3b3b !important;
- }
- body.dark .line-0-0-5:hover, body.dark .line-0-0-5.selected {
- background: #1a1a1a !important;
- }
- body.dark .line-0-0-5:hover .lineCounter-0-0-4, body.dark .line-0-0-5.selected .lineCounter-0-0-4 {
- color: #7187ff;
- background: #1a1a1a !important;
- }
- body.dark .line-0-0-5.selected .lineCounter-0-0-4 {
- border-color: #7187ff !important;
- }
- .line-0-0-5.highlight .lineCounter-0-0-4 {
- background: rgb(40, 46, 73);
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .line-0-0-5.highlight {
- color: #ffffff;
- background: rgb(28, 29, 48);
- }
- body:not(.dark-mode-animate) .line-0-0-5.highlight .lineCounter-0-0-4 {
- background: rgb(28, 29, 48);
- }
-}
- body.dark .line-0-0-5.highlight {
- color: #ffffff;
- background: rgb(28, 29, 48);
- }
- body.dark .line-0-0-5.highlight .lineCounter-0-0-4 {
- background: rgb(28, 29, 48);
- }
- .wmbar-0-0-6 {
- left: 0;
- display: none;
- padding: 16px;
- position: sticky;
- }
- .wmbar-0-0-6>span {
- display: block;
- opacity: 0.5;
- flex-grow: 1;
- font-size: 12px;
- text-align: center;
- font-family: sans-serif;
- margin-right: 64px;
- }
- .wmbar-0-0-6>span:first-child, .wmbar-0-0-6>span:nth-child(2), .wmbar-0-0-6>span:nth-child(3) {
- width: 8px;
- height: 8px;
- opacity: 1;
- flex-grow: 0;
- margin-right: 8px;
- border-radius: 8px;
- }
- pre.with-bar .wmbar-0-0-6 {
- display: flex;
- }
- .wmbar-0-0-6>span:first-child:first-child, .wmbar-0-0-6>span:nth-child(2):first-child, .wmbar-0-0-6>span:nth-child(3):first-child {
- background: rgb(255, 95, 86);
- }
- .wmbar-0-0-6>span:first-child:nth-child(2), .wmbar-0-0-6>span:nth-child(2):nth-child(2), .wmbar-0-0-6>span:nth-child(3):nth-child(2) {
- background: rgb(255, 189, 46);
- }
- .wmbar-0-0-6>span:first-child:nth-child(3), .wmbar-0-0-6>span:nth-child(2):nth-child(3), .wmbar-0-0-6>span:nth-child(3):nth-child(3) {
- background: rgb(39, 201, 63);
- }
- .collapse-0-0-7>.label {
- cursor: pointer;
- margin: 8px 0;
- display: flex;
- align-items: center;
- user-select: none;
- }
- .collapse-0-0-7>.content {
- opacity: 0;
- max-height: 0;
- transition: opacity .3s;
- visibility: hidden;
- border-left: 2px solid rgba(224, 224, 224, 0.5);
- padding-left: 16px;
- }
- .collapse-0-0-7.open>.content {
- opacity: 1;
- max-height: none;
- visibility: visible;
- }
- .collapse-0-0-7.open>.label .icon-font {
- transform: rotate(90deg);
- }
- body.dark-mode-animate .collapse-0-0-7>.content {
- transition: transform .15s, opacity .15s, border-color .3s;
- }
- body.dark .collapse-0-0-7>.content {
- border-color: rgba(49, 49, 49, 0.5);
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .collapse-0-0-7>.content {
- border-color: rgba(49, 49, 49, 0.5);
- }
-}
- .collapse-0-0-7>.label .text {
- flex-grow: 1;
- }
- .collapse-0-0-7>.label .icon-font {
- margin-right: 32px;
- }
- .collapse-0-0-7>.label:hover {
- color: #1eb2a6;
- transition: color .15s;
- }
- body.dark .collapse-0-0-7>.label:hover {
- color: #1eb2a6;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .collapse-0-0-7>.label:hover {
- color: #1eb2a6;
- }
-}
- body.dark-mode-animate .collapse-0-0-7>.label .icon-font {
- transition: transform .15s;
- }
- .watermark-0-0-8 {
- color: #424242;
- cursor: pointer;
- display: inline-block;
- opacity: 0.2;
- font-size: 8px;
- transition: opacity .15s;
- text-decoration: none !important;
- }
- body.dark-mode-animate .watermark-0-0-8 {
- transition: opacity .15s, color .3s;
- }
- .watermark-0-0-8:hover {
- opacity: 1;
- text-decoration: none;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .watermark-0-0-8 {
- color: #eeeeee;
- }
-}
- body.dark .watermark-0-0-8 {
- color: #eeeeee;
- }
- .watermark-0-0-8 svg {
- width: 2.8rem;
- display: block;
- margin-top: .25rem;
- }
- .watermark-0-0-8 svg g {
- fill: #424242;
- }
- body.dark-mode-animate .watermark-0-0-8 svg g {
- transition: fill .3s;
- }
- body.dark .watermark-0-0-8 svg g {
- fill: #eeeeee;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .watermark-0-0-8 svg g {
- fill: #eeeeee;
- }
-}
- .header-0-0-9 {
- top: 0;
- right: 0;
- padding: 32px;
- z-index: 100;
- position: fixed;
- text-align: right;
- }
- .footer-0-0-10 {
- left: 0;
- right: 0;
- bottom: 0;
- height: 64px;
- display: flex;
- z-index: 102;
- position: fixed;
- background: rgba(245, 245, 245, 0.85);
- box-shadow: 0 -2px 6px rgba(0, 0, 0, .03);
- align-items: center;
- backdrop-filter: blur(12px);
- justify-content: center;
- -webkit-backdrop-filter: blur(12px);
- }
- body.dark-mode-animate .footer-0-0-10 {
- transition: background .3s;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .footer-0-0-10 {
- background: rgba(33, 33, 33, 0.85);
- }
-}
- body.dark .footer-0-0-10 {
- background: rgba(33, 33, 33, 0.85);
- }
- .footer-0-0-10 .main {
- overflow: hidden;
- flex-grow: 1;
- text-align: center;
- }
- .footer-0-0-10 .left {
- padding-left: 32px;
- }
- .footer-0-0-10 .right {
- padding-right: 32px;
- }
-@media screen and (max-width: 800px) {
- .footer-0-0-10 .left {
- padding-left: 16px;
- }
- .footer-0-0-10 .right {
- padding-right: 16px;
- }
-}
- .footer-0-0-10 .main>.inside {
- display: inline-flex;
- overflow: auto;
- max-width: 100%;
- align-items: center;
- }
- .footer-0-0-10 .main>.inside hr {
- width: 2px;
- border: none;
- height: 16px;
- margin: 16px;
- background: #e0e0e0;
- }
- .footer-0-0-10 .main>.inside a {
- text-decoration: none;
- }
- .footer-0-0-10 .main>.inside a:hover {
- text-decoration: underline ;
- }
- body.dark-mode-animate .footer-0-0-10 .main>.inside hr {
- transition: background .3s;
- }
- body.dark .footer-0-0-10 .main>.inside hr {
- background: #313131;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .footer-0-0-10 .main>.inside hr {
- background: #313131;
- }
-}
- .toc-0-0-11 {
- top: 0;
- left: 0;
- width: calc(50vw - 464px);
- bottom: 0;
- display: flex;
- z-index: 101;
- position: fixed;
- transform: translateX(-50vw);
- background: #f1f1f1;
- border-right: 1px solid #e7e7e7;
- flex-direction: column;
- padding-bottom: 64px;
- }
- body.dark-mode-animate .toc-0-0-11 {
- transition: background .3s, border-color .3s;
- }
- body.dark .toc-0-0-11 {
- background: #1f1f1f;
- border-color: #282828;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .toc-0-0-11 {
- background: #1f1f1f;
- border-color: #282828;
- }
-}
-@media screen and (max-width: 1200px) {
- .toc-0-0-11 {
- width: 100vw;
- transform: translateX(-110vw);
- }
-}
- .toc-0-0-11.animated {
- transition: transform .3s;
- }
- .toc-0-0-11.active {
- transform: translateX(0);
- }
- .toc-0-0-11 p {
- margin: 0;
- }
- .toc-0-0-11 a {
- border: 1px solid transparent;
- display: block;
- padding: 8px;
- margin-left: -8px;
- border-right: none;
- margin-right: 1px;
- border-radius: 3px;
- text-decoration: none;
- }
- body.dark-mode-animate .toc-0-0-11 a {
- transition: border-color .3s, background .3s;
- }
- .toc-0-0-11 a:hover {
- background: #f5f5f5;
- text-decoration: none;
- }
- .toc-0-0-11 a.current {
- background: #f5f5f5;
- border-color: #e7e7e7;
- margin-right: 0;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- }
- body.dark .toc-0-0-11 a.current {
- background: hsl(0, 0%, 13.2%);
- border-color: #282828;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .toc-0-0-11 a.current {
- background: #212121;
- border-color: #282828;
- }
-}
-@media screen and (max-width: 1200px) {
- .toc-0-0-11 a.current {
- border-right: 1px solid;
- margin-right: -8px;
- border-radius: 3px;
- }
-}
- body.dark .toc-0-0-11 a:hover {
- background: hsl(0, 0%, 13.2%);
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .toc-0-0-11 a:hover {
- background: hsl(0, 0%, 13.2%);
- }
-}
- body.dark-mode-animate .toc-0-0-11.animated {
- transition: transform .3s, background .3s, border-color .3s;
- }
- .content-0-0-12 {
- padding: 32px;
- overflow: auto;
- flex-grow: 1;
- margin-right: -1px;
- padding-right: 0;
- }
-@media screen and (max-width: 1200px) {
- .content-0-0-12 {
- margin-right: 0;
- padding-right: 32px;
- }
-}
- .contentnav-0-0-14 {
- right: 0;
- width: calc(50vw - 496px);
- bottom: 96px;
- position: fixed;
- font-size: 12px;
- border-left: 1px dashed #e0e0e0;
- margin-left: 64px;
- padding-left: 48px;
- }
-@media screen and (max-width: 1200px) {
- .contentnav-0-0-14 {
- display: none;
- }
-}
- .contentnav-0-0-14 a {
- color: #424242;
- display: block;
- opacity: 0.2;
- text-decoration: none;
- }
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) .contentnav-0-0-14 {
- border-color: #313131;
- }
- body:not(.dark-mode-animate) .contentnav-0-0-14 a {
- color: #eeeeee;
- }
- body:not(.dark-mode-animate) .contentnav-0-0-14 a:hover, body:not(.dark-mode-animate) .contentnav-0-0-14 a.active {
- color: #1eb2a6;
- }
-}
- body.dark .contentnav-0-0-14 {
- border-color: #313131;
- }
- body.dark .contentnav-0-0-14 a {
- color: #eeeeee;
- }
- body.dark .contentnav-0-0-14 a:hover, body.dark .contentnav-0-0-14 a.active {
- color: #1eb2a6;
- }
- body.dark-mode-animate .contentnav-0-0-14 a {
- transition: color .3s, opacity .3s;
- }
- .contentnav-0-0-14 a:hover, .contentnav-0-0-14 a.active {
- color: #1eb2a6;
- opacity: 1;
- }
- .contentnav-0-0-14 a.h2 {
- margin-left: 12px;
- }
- .contentnav-0-0-14 a.h3 {
- margin-left: 24px;
- }
- .contentnav-0-0-14 a.h4 {
- margin-left: 36px;
- }
- .contentnav-0-0-14 a.h5 {
- margin-left: 48px;
- }
- .contentnav-0-0-14 a.h6 {
- margin-left: 60px;
- }
-* {
- touch-action: manipulation;
- scroll-behavior: smooth;
- -webkit-tap-highlight-color: transparent;
-}
-body {
- color: #424242;
- width: 100vw;
- margin: 0;
- padding: 0;
- background: #f5f5f5;
- overflow-x: hidden;
- backface-visibility: hidden;
- -webkit-backface-visibility: hidden;
-}
-body.dark-mode-animate {
- transition: color .3s, background .3s;
-}
-a {
- color: #1eb2a6;
-}
-a:hover {
- text-decoration: underline;
- text-decoration-thickness: 2px;
-}
-body.dark-mode-animate a {
- transition: color .3s;
-}
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) a {
- color: #1eb2a6;
- }
-}
-body.dark a {
- color: #1eb2a6;
-}
-.container {
- margin: 0 auto;
- padding: 96px 16px;
- max-width: 768px;
- transition: opacity .15s;
-}
-hr {
- border: none;
- margin: 64px;
- background: none;
- border-top: 1px solid #e0e0e0;
-}
-body.dark-mode-animate hr {
- transition: border-color .3s;
-}
-body.dark hr {
- border-color: #313131;
-}
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) hr {
- border-color: #313131;
- }
-}
-blockquote {
- color: #757575;
- margin: 0;
- padding: 16px 40px;
- position: relative;
- background: #eeeeee;
- border-radius: 3px;
-}
-body.dark-mode-animate blockquote {
- transition: color .3s, background .3s;
-}
-blockquote:after {
- top: 16px;
- left: 16px;
- width: 8px;
- bottom: 16px;
- content: '';
- display: block;
- position: absolute;
- background: radial-gradient(circle at center, #e0e0e0 50%, transparent 52%),transparent;
- background-size: 4px 4px;
-}
-body.dark-mode-animate blockquote:after {
- transition: color .3s, background .3s;
-}
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) {
- color: #eeeeee;
- background: #212121;
- }
- body:not(.dark-mode-animate) blockquote {
- color: #cacaca;
- background: #282828;
- }
- body:not(.dark-mode-animate) blockquote:after {
- background: radial-gradient(circle at center, #363636 50%, transparent 52%),transparent;
- background-size: 4px 4px;
- }
-}
-body.dark {
- color: #eeeeee;
- background: #212121;
-}
-body.dark blockquote {
- color: #cacaca;
- background: #282828;
-}
-body.dark blockquote:after {
- background: radial-gradient(circle at center, #363636 50%, transparent 52%),transparent;
- background-size: 4px 4px;
-}
-img {
- max-width: 100%;
-}
-iframe {
- width: 100%;
- border: none;
- background: white;
- border-radius: 3px;
-}
-code {
- color: #616161;
- padding: 4px;
- font-size: .85em;
- background: #eeeeee;
- border-radius: 3px;
-}
-body.dark-mode-animate code {
- transition: color .3s, background .3s;
-}
-body.dark code {
- color: #e0e0e0;
- background: #282828;
-}
-@media (prefers-color-scheme: dark) {
- body:not(.dark-mode-animate) code {
- color: #e0e0e0;
- background: #282828;
- }
-}
\ No newline at end of file
diff --git a/docs/examples.html b/docs/examples.html
deleted file mode 100644
index f9527fb..0000000
--- a/docs/examples.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | 🐣 Examples link 🐣 Exampleslink List all the snapshots for all the backends1 autorestic -a exec snapshots
link Unlock a locked repositoryIf you accidentally cancelled a running operation this could be useful.
Only do this if you know what you are doing.
1 autorestic -b my-backend exec unlock
\ No newline at end of file
diff --git a/docs/md/examples.md b/docs/examples.md
similarity index 100%
rename from docs/md/examples.md
rename to docs/examples.md
diff --git a/docs/index.html b/docs/index.html
deleted file mode 100644
index 0d42254..0000000
--- a/docs/index.html
+++ /dev/null
@@ -1,64 +0,0 @@
-Autorestic | autorestic link autoresticHigh backup level CLI utility for restic .
Autorestic is a wrapper around the amazing restic . While being amazing the restic cli can be a bit overwhelming and difficult to manage if you have many different location that you want to backup to multiple locations. This utility is aimed at making this easier 🙂
-
- link ✈️ RoadmapI would like to make the official 1.0
release in the coming months. Until then please feel free to file issues or feature requests so that the tool is as flexible as possible :)
As of version 0.18
crons are supported wich where the last feature missing for a 1.0
. Will test this for a few weeks and then it's time for the first "real" release! 🎉 Also we now have waaay better docs 📒
link 🌈 FeaturesYAML config files, no CLI Incremental -> Minimal space is used Backup locations to multiple backends Snapshot policies and pruning Fully encrypted Pre/After hooks Exclude pattern/files Cron jobs for automatic backup Backup & Restore docker volumes
\ No newline at end of file
diff --git a/docs/md/index.md b/docs/index.md
similarity index 98%
rename from docs/md/index.md
rename to docs/index.md
index 3d7553d..aad20f7 100644
--- a/docs/md/index.md
+++ b/docs/index.md
@@ -1,4 +1,4 @@
-# autorestic
+# `autorestic`
High backup level CLI utility for [restic](https://restic.net/).
diff --git a/docs/installation.html b/docs/installation.html
deleted file mode 100644
index 6bba9e6..0000000
--- a/docs/installation.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | 🛳 Installation link 🛳 InstallationLinux & macOS. Windows is not supported. If you have problems installing please open an issue :)
Autorestic requires curl
, wget
and bzip2
to be installed. For most systems these should be already installed.
1 curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash
\ No newline at end of file
diff --git a/docs/md/installation.md b/docs/installation.md
similarity index 100%
rename from docs/md/installation.md
rename to docs/installation.md
diff --git a/docs/location/cron.html b/docs/location/cron.html
deleted file mode 100644
index 6e51605..0000000
--- a/docs/location/cron.html
+++ /dev/null
@@ -1,64 +0,0 @@
-Autorestic | Cron link CronOften it is usefull to trigger backups autmatically. For this we can specify a cron
attribute to each location.
Available since version 0.18
.autorestic.yml 1 locations :
2 my-location :
3 from : /data
4 to : my- backend
5 cron : '0 3 * * 0'
Here is a awesome website with some examples and an explorer
link Installing the cronThis has to be done only once, regadless of now many cros you have in your config file.
To actually enable cron jobs you need something to call autorestic cron
on a timed shedule.
-Note that the shedule has nothing to do with the cron
attribute in each location.
-My advise would be to trigger the command every 5min, but if you have a cronjob that runs only once a week, it's probably enough to shedule it once a day.
link CrontabHere is an example using crontab, but systemd would do too.
First, open your crontab in edit mode
1 crontab -e
Then paste this at the bottom of the file and save it. Note that in this specific example the .autorestic.yml
is located in /srv/
. You need to modify that part of course to fit your config file.
1
2 PATH = "/usr/local/bin:/usr/bin:/bin"
3
4
5 */5 * * * * autorestic -c /srv/.autorestic.yml cron
Now you can add as many cron
attributes as you wish ⏱
\ No newline at end of file
diff --git a/docs/md/location/cron.md b/docs/location/cron.md
similarity index 100%
rename from docs/md/location/cron.md
rename to docs/location/cron.md
diff --git a/docs/location/docker.html b/docs/location/docker.html
deleted file mode 100644
index 24eec87..0000000
--- a/docs/location/docker.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | Docker link Dockerautorestic supports docker volumes directly, without needing them to be mounted to the host filesystem.
Available since version 0.13
Let see an example.
docker-compose.yml 1 version : '3.7'
2
3 volumes :
4 data :
5 name : my- data
6
7 services :
8 api :
9 image : alpine
10 volumes :
11 - data: /foo/bar
.autorestic.yml 1 locations :
2 hello :
3 from : 'volume:my-data'
4 to :
5 - remote
6 options :
7 forget :
8 keep-last : 14
9
10 backends :
11 remote : ...
Now you can backup and restore as always.
1 autorestic -l hello backup
1 autorestic -l hello restore
If the volume does not exist on restore, autorestic will create it for you and then fill it with the data.
link LimitationsUnfortunately there are some limitations when backing up directly from a docker volume without mounting the volume to the host:
Incremental updates are not possible right now due to how the current docker mounting works. This means that it will take significantely more space. Exclude patterns and files also do not work as restic only sees a compressed tarball as source and not the actual data. If you are curious or have ideas how to improve this, please read more here . Any help is welcomed 🙂
\ No newline at end of file
diff --git a/docs/md/location/docker.md b/docs/location/docker.md
similarity index 100%
rename from docs/md/location/docker.md
rename to docs/location/docker.md
diff --git a/docs/location/exclude.html b/docs/location/exclude.html
deleted file mode 100644
index 4675f26..0000000
--- a/docs/location/exclude.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | Excluding files link Excluding filesIf you want to exclude certain files or folders it done easily by specifiyng the right flags in the location you desire to filter.
The flags are taken straight from the restic cli exclude rules so you can use any flag used there.
1 locations :
2 my-location :
3 from : /data
4 to : my- backend
5 options :
6 backup :
7 exclude :
8 - '*.nope'
9 - '*.abc'
10 exclude-file : .gitignore
\ No newline at end of file
diff --git a/docs/md/location/exclude.md b/docs/location/exclude.md
similarity index 100%
rename from docs/md/location/exclude.md
rename to docs/location/exclude.md
diff --git a/docs/location/forget.html b/docs/location/forget.html
deleted file mode 100644
index 196da80..0000000
--- a/docs/location/forget.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | Forget/Prune Policies link Forget/Prune PoliciesAutorestic supports declaring snapshot policies for location to avoid keeping old snapshot around if you don't need them.
This is based on Restic's snapshots policies , and can be enabled for each location as shown below:
Note This is a full example, of course you also can specify only one of them
.autorestic.yml 1 locations :
2 etc :
3 from : /etc
4 to : local
5 options :
6 forget :
7 keep-last : 5
8 keep-hourly : 3
9 keep-daily : 4
10 keep-weekly : 1
11 keep-monthly : 12
12 keep-yearly : 7
13 keep-within : '2w'
\ No newline at end of file
diff --git a/docs/md/location/forget.md b/docs/location/forget.md
similarity index 100%
rename from docs/md/location/forget.md
rename to docs/location/forget.md
diff --git a/docs/location/hooks.html b/docs/location/hooks.html
deleted file mode 100644
index e71dc6e..0000000
--- a/docs/location/hooks.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | Hooks link HooksSometimes you might want to stop an app/db before backing up data and start the service again after the backup has completed. This is what the hooks are made for. Simply add them to your location config. You can have as many commands as you wish.
.autorestic.yml 1 locations :
2 my-location :
3 from : /data
4 to : my- backend
5 hooks :
6 before :
7 - echo "Hello"
8 - echo "Human"
9 after :
10 - echo "kthxbye"
\ No newline at end of file
diff --git a/docs/md/location/hooks.md b/docs/location/hooks.md
similarity index 100%
rename from docs/md/location/hooks.md
rename to docs/location/hooks.md
diff --git a/docs/location/overview.html b/docs/location/overview.html
deleted file mode 100644
index 76e29c1..0000000
--- a/docs/location/overview.html
+++ /dev/null
@@ -1,63 +0,0 @@
-Autorestic | 🗂 Locations link 🗂 LocationsLocations can be seen as the input to the backup process. Generally this is simply a folder.
-The paths can be relative from the config file. A location can have multiple backends, so that the data is secured across multiple servers.
.autorestic.yml 1 locations :
2 my-location-name :
3 from : path/to/backup
4 to :
5 - name- of- backend
6 - also- backup- to- this- backend
link from
This is the source of the location.
link How are paths resolved?Paths can be absolute or relative. If relative they are resolved relative to the location of the config file. Tilde ~
paths are also supported for home folder resolution.
link to
This is einther a single backend or an array of backends. The backends have to be configured in the same config file.
\ No newline at end of file
diff --git a/docs/md/location/overview.md b/docs/location/overview.md
similarity index 100%
rename from docs/md/location/overview.md
rename to docs/location/overview.md
diff --git a/docs/qa.html b/docs/qa.html
deleted file mode 100644
index 7bd1045..0000000
--- a/docs/qa.html
+++ /dev/null
@@ -1,63 +0,0 @@
-Autorestic | ❓ QA link ❓ QAlink My config file was moved?This happens when autorestic needs to write to the config file. This happend e.g. when we are generating a key for you.
-Unfortunately during this process formatting and comments are lost. That is why autorestic will place a copy of your old config next to the one we are writing to.
\ No newline at end of file
diff --git a/docs/md/qa.md b/docs/qa.md
similarity index 100%
rename from docs/md/qa.md
rename to docs/qa.md
diff --git a/docs/quick.html b/docs/quick.html
deleted file mode 100644
index 096d41b..0000000
--- a/docs/quick.html
+++ /dev/null
@@ -1,62 +0,0 @@
-Autorestic | 🚀 Quickstart link 🚀 Quickstartlink Installation1 curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash
link Write a simple config file1 vim .autorestic.yml
For a quick overview:
locations
can be seen as the inputs and backends
the output where the data is stored and backed up.One location
can have one or multiple backends
for redudancy. One backend
can also be the target for multiple locations
. Backup the config file as it will contain the generated keys . If you don't have a copy of that keys, the backups are useless as they are encrypted and data will be not recoverable..autorestic.yml 1 locations :
2 home :
3 from : /home/me
4 to : remote
5
6 important :
7 from : /path/to/important/stuff
8 to :
9 - remote
10 - hdd
11
12 backends :
13 remote :
14 type : s3
15 path : 's3.amazonaws.com/bucket_name'
16 AWS_ACCESS_KEY_ID : account_id
17 AWS_SECRET_ACCESS_KEY : account_key
18
19 hdd :
20 type : local
21 path : /mnt/my_external_storage
link Check1 autorestic check -a
This checks if the config file has any issues. If this is the first time this can take longer as autorestic will setup the backends.
Now is good time to backup the config . After you run autorestic at least once we will add the generated encryption keys to the config.
link Backup1 autorestic backup -a
This will do a backup of all locations.
link Restore1 autorestic restore -l home --from hdd --to /path/where/to/restore
This will restore the location home
from the backend hdd
to the given path.
\ No newline at end of file
diff --git a/docs/md/quick.md b/docs/quick.md
similarity index 100%
rename from docs/md/quick.md
rename to docs/quick.md
diff --git a/package.json b/package.json
index f61d737..39c928d 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,10 @@
"private": true,
"scripts": {
"build": "tsc",
- "build:watch": "tsc -w",
- "dev": "tsnd --no-notify --respawn ./src/autorestic.ts",
- "move": "mv bin/autorestic-linux bin/autorestic_linux_x64 && mv bin/autorestic-macos bin/autorestic_macos_x64",
- "bin": "yarn run build && pkg lib/autorestic.js --targets latest-macos-x64,latest-linux-x64 --out-path bin && yarn run move",
- "docs:build": "codedoc build",
+ "dev": "tsc -w",
+ "move": "mv bin/index-linux bin/autorestic_linux_x64 && mv bin/index-macos bin/autorestic_macos_x64",
+ "bin": "yarn run build && pkg lib/index.js --targets latest-macos-x64,latest-linux-x64 --out-path bin && yarn run move",
+ "docs:build": "codedoc install && codedoc build",
"docs:dev": "codedoc serve"
},
"devDependencies": {
@@ -22,9 +21,9 @@
"axios": "0.19.x",
"clitastic": "0.0.1",
"colors": "1.x.x",
+ "commander": "^6.2.0",
"cron-parser": "2.x.x",
"js-yaml": "3.x.x",
- "minimist": "1.x.x",
"uhrwerk": "1.x.x"
}
}
diff --git a/src/autorestic.ts b/src/autorestic.ts
deleted file mode 100644
index 7220539..0000000
--- a/src/autorestic.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import 'colors'
-import minimist from 'minimist'
-
-import { init } from './config'
-import handlers, { error, help } from './handlers'
-import { Config } from './types'
-import { readLock, writeLock, unlock } from './lock'
-
-process.on('uncaughtException', (err) => {
- console.log(err.message)
- unlock()
- process.exit(1)
-})
-
-export const { _: commands, ...flags } = minimist(process.argv.slice(2), {
- alias: {
- c: 'config',
- v: 'version',
- h: 'help',
- a: 'all',
- l: 'location',
- b: 'backend',
- d: 'dry-run',
- },
- boolean: ['a', 'd'],
- string: ['l', 'b'],
-})
-
-export const VERSION = '0.20'
-export const INSTALL_DIR = '/usr/local/bin'
-export const VERBOSE = flags.verbose
-
-export let config: Config
-
-async function main() {
- config = init()
-
- // Don't let 2 instances run on the same config
- const lock = readLock()
- if (lock.running) {
- console.log('An instance of autorestic is already running for this config file'.red)
- return
- }
- writeLock({
- ...lock,
- running: true,
- })
-
- // For dev
- // return await handlers['cron']([], { ...flags, all: true })
-
- if (commands.length < 1 || commands[0] === 'help') return help()
-
- const command: string = commands[0]
- const args: string[] = commands.slice(1)
-
- const fn = handlers[command] || error
- await fn(args, flags)
-}
-
-main()
- .catch((e: Error) => console.error(e.message))
- .finally(unlock)
diff --git a/src/backend.ts b/src/backend.ts
index 566f89e..7b75334 100644
--- a/src/backend.ts
+++ b/src/backend.ts
@@ -1,74 +1,66 @@
import { Writer } from 'clitastic'
-import { config, VERBOSE } from './autorestic'
+import { config, VERBOSE } from './'
import { Backend, Backends, Locations } from './types'
import { exec, pathRelativeToConfigFile, filterObjectByKey } from './utils'
-
-
const ALREADY_EXISTS = /(?=.*already)(?=.*config).*/
export const getPathFromBackend = (backend: Backend): string => {
- switch (backend.type) {
- case 'local':
- return pathRelativeToConfigFile(backend.path)
- case 'b2':
- case 'azure':
- case 'gs':
- case 's3':
- case 'sftp':
- case 'rest':
- return `${backend.type}:${backend.path}`
- default:
- throw new Error(`Unknown backend type.`)
- }
+ switch (backend.type) {
+ case 'local':
+ return pathRelativeToConfigFile(backend.path)
+ case 'b2':
+ case 'azure':
+ case 'gs':
+ case 's3':
+ case 'sftp':
+ case 'rest':
+ return `${backend.type}:${backend.path}`
+ default:
+ throw new Error(`Unknown backend type.`)
+ }
}
export const getEnvFromBackend = (backend: Backend) => {
- const { type, path, key, ...rest } = backend
- return {
- RESTIC_PASSWORD: key,
- RESTIC_REPOSITORY: getPathFromBackend(backend),
- ...rest,
- }
+ const { type, path, key, ...rest } = backend
+ return {
+ RESTIC_PASSWORD: key,
+ RESTIC_REPOSITORY: getPathFromBackend(backend),
+ ...rest,
+ }
}
export const getBackendsFromLocations = (locations: Locations): string[] => {
- const backends = new Set()
- for (const to of Object.values(locations).map(location => location.to))
- Array.isArray(to) ? to.forEach(t => backends.add(t)) : backends.add(to)
- return Array.from(backends)
+ const backends = new Set()
+ for (const to of Object.values(locations).map((location) => location.to)) Array.isArray(to) ? to.forEach((t) => backends.add(t)) : backends.add(to)
+ return Array.from(backends)
}
export const checkAndConfigureBackend = (name: string, backend: Backend) => {
- const writer = new Writer(name.blue + ' : ' + 'Configuring... ⏳')
- try {
- const env = getEnvFromBackend(backend)
+ const writer = new Writer(name.blue + ' : ' + 'Configuring... ⏳')
+ try {
+ const env = getEnvFromBackend(backend)
- const { out, err } = exec('restic', ['init'], { env })
+ const { out, err } = exec('restic', ['init'], { env })
- if (err.length > 0 && !ALREADY_EXISTS.test(err))
- throw new Error(`Could not load the backend "${name}": ${err}`)
+ if (err.length > 0 && !ALREADY_EXISTS.test(err)) throw new Error(`Could not load the backend "${name}": ${err}`)
- if (VERBOSE && out.length > 0) console.log(out)
+ if (VERBOSE && out.length > 0) console.log(out)
- writer.done(name.blue + ' : ' + 'Done ✓'.green)
- } catch (e) {
- writer.done(name.blue + ' : ' + 'Error ⚠️ ' + e.message.red)
- }
+ writer.done(name.blue + ' : ' + 'Done ✓'.green)
+ } catch (e) {
+ writer.done(name.blue + ' : ' + 'Error ⚠️ ' + e.message.red)
+ }
}
export const checkAndConfigureBackends = (backends?: Backends) => {
- if (!backends)
- backends = config.backends
+ if (!backends) backends = config.backends
- console.log('\nConfiguring Backends'.grey.underline)
- for (const [name, backend] of Object.entries(backends))
- checkAndConfigureBackend(name, backend)
+ console.log('\nConfiguring Backends'.grey.underline)
+ for (const [name, backend] of Object.entries(backends)) checkAndConfigureBackend(name, backend)
}
export const checkAndConfigureBackendsForLocations = (locations: Locations) => {
- checkAndConfigureBackends(
- filterObjectByKey(config.backends, getBackendsFromLocations(locations)),
- )
+ checkAndConfigureBackends(filterObjectByKey(config.backends, getBackendsFromLocations(locations)))
}
diff --git a/src/backup.ts b/src/backup.ts
index a29880e..47631f2 100644
--- a/src/backup.ts
+++ b/src/backup.ts
@@ -1,111 +1,103 @@
import { Writer } from 'clitastic'
import { mkdirSync } from 'fs'
-import { config, VERBOSE } from './autorestic'
+import { config, VERBOSE } from './'
import { getEnvFromBackend } from './backend'
import { LocationFromPrefixes } from './config'
import { Locations, Location, Backend } from './types'
import {
- exec,
- pathRelativeToConfigFile,
- getFlagsFromLocation,
- makeArrayIfIsNot,
- execPlain,
- MeasureDuration,
- fill,
- decodeLocationFromPrefix,
- checkIfDockerVolumeExistsOrFail,
- getPathFromVolume,
+ exec,
+ pathRelativeToConfigFile,
+ getFlagsFromLocation,
+ makeArrayIfIsNot,
+ execPlain,
+ MeasureDuration,
+ fill,
+ decodeLocationFromPrefix,
+ checkIfDockerVolumeExistsOrFail,
+ getPathFromVolume,
} from './utils'
-
-
export const backupFromFilesystem = (from: string, location: Location, backend: Backend, tags?: string[]) => {
- const path = pathRelativeToConfigFile(from)
+ const path = pathRelativeToConfigFile(from)
- const { out, err, status } = exec(
- 'restic',
- ['backup', '.', ...getFlagsFromLocation(location, 'backup')],
- { env: getEnvFromBackend(backend), cwd: path },
- )
+ const { out, err, status } = exec('restic', ['backup', '.', ...getFlagsFromLocation(location, 'backup')], {
+ env: getEnvFromBackend(backend),
+ cwd: path,
+ })
- if (VERBOSE) console.log(out, err)
- if (status != 0 || err.length > 0)
- throw new Error(err)
+ if (VERBOSE) console.log(out, err)
+ if (status != 0 || err.length > 0) throw new Error(err)
}
export const backupFromVolume = (volume: string, location: Location, backend: Backend) => {
- const tmp = getPathFromVolume(volume)
- try {
- mkdirSync(tmp)
- checkIfDockerVolumeExistsOrFail(volume)
-
- // For incremental backups. Unfortunately due to how the docker mounts work the permissions get lost.
- // execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine cp -aT /data /backup`)
- execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar cf /backup/archive.tar -C /data .`)
-
- backupFromFilesystem(tmp, location, backend)
- } catch (e) {
- throw e
- } finally {
- execPlain(`rm -rf ${tmp}`)
- }
+ const tmp = getPathFromVolume(volume)
+ try {
+ mkdirSync(tmp)
+ checkIfDockerVolumeExistsOrFail(volume)
+
+ // For incremental backups. Unfortunately due to how the docker mounts work the permissions get lost.
+ // execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine cp -aT /data /backup`)
+ execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar cf /backup/archive.tar -C /data .`)
+
+ backupFromFilesystem(tmp, location, backend)
+ } catch (e) {
+ throw e
+ } finally {
+ execPlain(`rm -rf ${tmp}`)
+ }
}
export const backupSingle = (name: string, to: string, location: Location) => {
- const delta = new MeasureDuration()
- const writer = new Writer(name + to.blue + ' : ' + 'Backing up... ⏳')
-
- try {
- const backend = config.backends[to]
- const [type, value] = decodeLocationFromPrefix(location.from)
-
- switch (type) {
-
- case LocationFromPrefixes.Filesystem:
- backupFromFilesystem(value, location, backend)
- break
-
- case LocationFromPrefixes.DockerVolume:
- backupFromVolume(value, location, backend)
- break
-
- }
-
- writer.done(`${name}${to.blue} : ${'Done ✓'.green} (${delta.finished(true)})`)
- } catch (e) {
- writer.done(`${name}${to.blue} : ${'Failed!'.red} (${delta.finished(true)}) ${e.message}`)
- }
+ const delta = new MeasureDuration()
+ const writer = new Writer(name + to.blue + ' : ' + 'Backing up... ⏳')
+
+ try {
+ const backend = config.backends[to]
+ const [type, value] = decodeLocationFromPrefix(location.from)
+
+ switch (type) {
+ case LocationFromPrefixes.Filesystem:
+ backupFromFilesystem(value, location, backend)
+ break
+
+ case LocationFromPrefixes.DockerVolume:
+ backupFromVolume(value, location, backend)
+ break
+ }
+
+ writer.done(`${name}${to.blue} : ${'Done ✓'.green} (${delta.finished(true)})`)
+ } catch (e) {
+ writer.done(`${name}${to.blue} : ${'Failed!'.red} (${delta.finished(true)}) ${e.message}`)
+ }
}
export const backupLocation = (name: string, location: Location) => {
- const display = name.yellow + ' ▶ '
- const filler = fill(name.length + 3)
- let first = true
-
- if (location.hooks && location.hooks.before)
- for (const command of makeArrayIfIsNot(location.hooks.before)) {
- const cmd = execPlain(command, {})
- console.log(cmd.out, cmd.err)
- }
-
- for (const t of makeArrayIfIsNot(location.to)) {
- backupSingle(first ? display : filler, t, location)
- if (first) first = false
- }
-
- if (location.hooks && location.hooks.after)
- for (const command of makeArrayIfIsNot(location.hooks.after)) {
- const cmd = execPlain(command)
- console.log(cmd.out, cmd.err)
- }
+ const display = name.yellow + ' ▶ '
+ const filler = fill(name.length + 3)
+ let first = true
+
+ if (location.hooks && location.hooks.before)
+ for (const command of makeArrayIfIsNot(location.hooks.before)) {
+ const cmd = execPlain(command, {})
+ console.log(cmd.out, cmd.err)
+ }
+
+ for (const t of makeArrayIfIsNot(location.to)) {
+ backupSingle(first ? display : filler, t, location)
+ if (first) first = false
+ }
+
+ if (location.hooks && location.hooks.after)
+ for (const command of makeArrayIfIsNot(location.hooks.after)) {
+ const cmd = execPlain(command)
+ console.log(cmd.out, cmd.err)
+ }
}
export const backupAll = (locations?: Locations) => {
- if (!locations)
- locations = config.locations
+ if (!locations) locations = config.locations
- console.log('\nBacking Up'.underline.grey)
- for (const [name, location] of Object.entries(locations))
- backupLocation(name, location)
+ console.log('\nBacking Up'.underline.grey)
+ for (const [name, location] of Object.entries(locations)) backupLocation(name, location)
}
diff --git a/src/config.ts b/src/config.ts
index 84c0e34..67b5568 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -5,7 +5,6 @@ import { homedir } from 'os'
import yaml from 'js-yaml'
import CronParser from 'cron-parser'
-import { flags } from './autorestic'
import { Backend, Config } from './types'
import { makeArrayIfIsNot, makeObjectKeysLowercase, rand } from './utils'
@@ -56,9 +55,9 @@ export const normalizeAndCheckLocations = (config: Config) => {
}
}
-const findConfigFile = (): string => {
+const findConfigFile = (custom: string): string => {
const config = '.autorestic.yml'
- const paths = [resolve(flags.config || ''), resolve('./' + config), homedir() + '/' + config]
+ const paths = [resolve(custom || ''), resolve('./' + config), homedir() + '/' + config]
for (const path of paths) {
try {
const file = statSync(path)
@@ -70,8 +69,8 @@ const findConfigFile = (): string => {
export let CONFIG_FILE: string = ''
-export const init = (): Config => {
- const file = findConfigFile()
+export const init = (custom: string): Config => {
+ const file = findConfigFile(custom)
CONFIG_FILE = file
const parsed = yaml.safeLoad(readFileSync(CONFIG_FILE).toString())
diff --git a/src/cron.ts b/src/cron.ts
index 5f52da4..fe1bd74 100644
--- a/src/cron.ts
+++ b/src/cron.ts
@@ -1,12 +1,11 @@
import CronParser from 'cron-parser'
-import { config } from './autorestic'
+import { config } from './'
import { checkAndConfigureBackendsForLocations } from './backend'
import { Location } from './types'
import { backupLocation } from './backup'
import { readLock, writeLock } from './lock'
-
const runCronForLocation = (name: string, location: Location) => {
const lock = readLock()
const parsed = CronParser.parseExpression(location.cron || '')
@@ -26,8 +25,7 @@ export const runCron = () => {
checkAndConfigureBackendsForLocations(Object.fromEntries(locationsWithCron))
console.log('\nRunning cron jobs'.underline.gray)
- for (const [name, location] of locationsWithCron)
- runCronForLocation(name, location)
+ for (const [name, location] of locationsWithCron) runCronForLocation(name, location)
console.log('\nFinished!'.underline + ' 🎉')
}
diff --git a/src/forget.ts b/src/forget.ts
index b4d47cc..7638481 100644
--- a/src/forget.ts
+++ b/src/forget.ts
@@ -1,75 +1,61 @@
import { Writer } from 'clitastic'
-import { config, VERBOSE } from './autorestic'
+import { config, VERBOSE } from './'
import { getEnvFromBackend } from './backend'
import { LocationFromPrefixes } from './config'
import { Locations, Location, Flags } from './types'
-import {
- exec,
- pathRelativeToConfigFile,
- getFlagsFromLocation,
- makeArrayIfIsNot,
- fill, decodeLocationFromPrefix, getPathFromVolume,
-} from './utils'
-
-
+import { exec, pathRelativeToConfigFile, getFlagsFromLocation, makeArrayIfIsNot, fill, decodeLocationFromPrefix, getPathFromVolume } from './utils'
export const forgetSingle = (name: string, to: string, location: Location, dryRun: boolean) => {
- const base = name + to.blue + ' : '
- const writer = new Writer(base + 'Removing old snapshots… ⏳')
-
- const backend = config.backends[to]
- const flags = getFlagsFromLocation(location, 'forget')
-
- const [type, value] = decodeLocationFromPrefix(location.from)
- let path: string
- switch (type) {
- case LocationFromPrefixes.Filesystem:
- path = pathRelativeToConfigFile(value)
- break
- case LocationFromPrefixes.DockerVolume:
- path = getPathFromVolume(value)
- break
- }
-
- if (flags.length == 0) {
- writer.done(base + 'Skipping, no policy declared')
- return
- }
- if (dryRun) flags.push('--dry-run')
-
- writer.replaceLn(base + 'Forgetting old snapshots… ⏳')
- const cmd = exec(
- 'restic',
- ['forget', '--path', path, '--prune', ...flags],
- { env: getEnvFromBackend(backend) },
- )
-
- if (VERBOSE) console.log(cmd.out, cmd.err)
- writer.done(base + 'Done ✓'.green)
+ const base = name + to.blue + ' : '
+ const writer = new Writer(base + 'Removing old snapshots… ⏳')
+
+ const backend = config.backends[to]
+ const flags = getFlagsFromLocation(location, 'forget')
+
+ const [type, value] = decodeLocationFromPrefix(location.from)
+ let path: string
+ switch (type) {
+ case LocationFromPrefixes.Filesystem:
+ path = pathRelativeToConfigFile(value)
+ break
+ case LocationFromPrefixes.DockerVolume:
+ path = getPathFromVolume(value)
+ break
+ }
+
+ if (flags.length == 0) {
+ writer.done(base + 'Skipping, no policy declared')
+ return
+ }
+ if (dryRun) flags.push('--dry-run')
+
+ writer.replaceLn(base + 'Forgetting old snapshots… ⏳')
+ const cmd = exec('restic', ['forget', '--path', path, '--prune', ...flags], { env: getEnvFromBackend(backend) })
+
+ if (VERBOSE) console.log(cmd.out, cmd.err)
+ writer.done(base + 'Done ✓'.green)
}
export const forgetLocation = (name: string, backup: Location, dryRun: boolean) => {
- const display = name.yellow + ' ▶ '
- const filler = fill(name.length + 3)
- let first = true
-
- for (const t of makeArrayIfIsNot(backup.to)) {
- const nameOrBlankSpaces: string = first ? display : filler
- forgetSingle(nameOrBlankSpaces, t, backup, dryRun)
- if (first) first = false
- }
+ const display = name.yellow + ' ▶ '
+ const filler = fill(name.length + 3)
+ let first = true
+
+ for (const t of makeArrayIfIsNot(backup.to)) {
+ const nameOrBlankSpaces: string = first ? display : filler
+ forgetSingle(nameOrBlankSpaces, t, backup, dryRun)
+ if (first) first = false
+ }
}
-export const forgetAll = (backups?: Locations, flags?: Flags) => {
- if (!backups) {
- backups = config.locations
- }
+export const forgetAll = (backups?: Locations, dryRun = false) => {
+ if (!backups) {
+ backups = config.locations
+ }
- console.log('\nRemoving old snapshots according to policy'.underline.grey)
- const dryRun = flags ? flags['dry-run'] : false
- if (dryRun) console.log('Running in dry-run mode, not touching data\n'.yellow)
+ console.log('\nRemoving old snapshots according to policy'.underline.grey)
+ if (dryRun) console.log('Running in dry-run mode, not touching data\n'.yellow)
- for (const [name, backup] of Object.entries(backups))
- forgetLocation(name, backup, dryRun)
+ for (const [name, backup] of Object.entries(backups)) forgetLocation(name, backup, dryRun)
}
diff --git a/src/handlers.ts b/src/handlers.ts
deleted file mode 100644
index 51f057b..0000000
--- a/src/handlers.ts
+++ /dev/null
@@ -1,244 +0,0 @@
-import { chmodSync, renameSync, unlinkSync } from 'fs'
-import { tmpdir } from 'os'
-import { join, resolve } from 'path'
-
-import axios from 'axios'
-import { Writer } from 'clitastic'
-
-import { config, INSTALL_DIR, VERSION } from './autorestic'
-import { checkAndConfigureBackends, getEnvFromBackend, checkAndConfigureBackendsForLocations } from './backend'
-import { backupAll } from './backup'
-import { runCron } from './cron'
-import { forgetAll } from './forget'
-import showAll from './info'
-import { restoreSingle } from './restore'
-import { Backends, Flags, Locations } from './types'
-import {
- checkIfCommandIsAvailable,
- checkIfResticIsAvailable,
- downloadFile,
- exec,
- filterObjectByKey,
- makeArrayIfIsNot,
-} from './utils'
-
-
-
-export type Handlers = {
- [command: string]: (args: string[], flags: Flags) => void
-}
-
-const parseBackend = (flags: Flags): Backends => {
- if (!flags.all && !flags.backend)
- throw new Error(
- 'No backends specified.'.red +
- '\n--all [-a]\t\t\t\tCheck all.' +
- '\n--backend [-b] myBackend\t\tSpecify one or more backend',
- )
- if (flags.all) return config.backends
- else {
- const backends = makeArrayIfIsNot(flags.backend)
- for (const backend of backends)
- if (!config.backends[backend])
- throw new Error('Invalid backend: '.red + backend)
- return filterObjectByKey(config.backends, backends)
- }
-}
-
-const parseLocations = (flags: Flags): Locations => {
- if (!flags.all && !flags.location)
- throw new Error(
- 'No locations specified.'.red +
- '\n--all [-a]\t\t\t\tBackup all.' +
- '\n--location [-l] site1\t\t\tSpecify one or more locations',
- )
-
- if (flags.all) {
- return config.locations
- } else {
- const locations = makeArrayIfIsNot(flags.location)
- for (const location of locations)
- if (!config.locations[location])
- throw new Error('Invalid location: '.red + location)
- return filterObjectByKey(config.locations, locations)
- }
-}
-
-const handlers: Handlers = {
- check(args, flags) {
- checkIfResticIsAvailable()
- const backends = parseBackend(flags)
- checkAndConfigureBackends(backends)
- },
- backup(args, flags) {
- checkIfResticIsAvailable()
- const locations: Locations = parseLocations(flags)
- checkAndConfigureBackendsForLocations(locations)
- backupAll(locations)
-
- console.log('\nFinished!'.underline + ' 🎉')
- },
- cron(args, flags) {
- checkIfResticIsAvailable()
- runCron()
- },
- restore(args, flags) {
- checkIfResticIsAvailable()
-
- const locations = parseLocations(flags)
- const keys = Object.keys(locations)
- if (keys.length < 1) throw new Error(`You need to specify the location to restore with --location`.red)
- if (keys.length > 2) throw new Error(`Only one location is supported at a time when restoring`.red)
-
- restoreSingle(keys[0], flags.from, flags.to)
- },
- forget(args, flags) {
- checkIfResticIsAvailable()
- const locations: Locations = parseLocations(flags)
- checkAndConfigureBackendsForLocations(locations)
- forgetAll(locations, flags)
-
- console.log('\nFinished!'.underline + ' 🎉')
- },
- exec(args, flags) {
- checkIfResticIsAvailable()
- const backends = parseBackend(flags)
- for (const [name, backend] of Object.entries(backends)) {
- console.log(`\n${name}:\n`.grey.underline)
- const env = getEnvFromBackend(backend)
-
- const { out, err } = exec('restic', args, { env })
- console.log(out, err)
- }
- },
- info() {
- showAll()
- },
- async install() {
- try {
- checkIfResticIsAvailable()
- console.log('Restic is already installed')
- return
- } catch {
- }
-
- const w = new Writer('Checking latest version... ⏳')
- checkIfCommandIsAvailable('bzip2')
- const { data: json } = await axios({
- method: 'get',
- url: 'https://api.github.com/repos/restic/restic/releases/latest',
- responseType: 'json',
- })
-
- const archMap: { [a: string]: string } = {
- x32: '386',
- x64: 'amd64',
- }
-
- w.replaceLn('Downloading binary... 🌎')
- const name = `${json.name.replace(' ', '_')}_${process.platform}_${archMap[process.arch]}.bz2`
- const dl = json.assets.find((asset: any) => asset.name === name)
- if (!dl)
- return console.log(
- 'Cannot get the right binary.'.red,
- 'Please see https://bit.ly/2Y1Rzai',
- )
-
- const tmp = join(tmpdir(), name)
- const extracted = tmp.slice(0, -4) //without the .bz2
-
- await downloadFile(dl.browser_download_url, tmp)
-
- w.replaceLn('Decompressing binary... 📦')
- exec('bzip2', ['-dk', tmp])
- unlinkSync(tmp)
-
- w.replaceLn(`Moving to ${INSTALL_DIR} 🚙`)
- chmodSync(extracted, 0o755)
- renameSync(extracted, INSTALL_DIR + '/restic')
-
- w.done(
- `\nFinished! restic is installed under: ${INSTALL_DIR}`.underline + ' 🎉',
- )
- },
- uninstall() {
- for (const bin of ['restic', 'autorestic'])
- try {
- unlinkSync(INSTALL_DIR + '/' + bin)
- console.log(`Finished! ${bin} was uninstalled`)
- } catch (e) {
- console.log(`${bin} is already uninstalled`.red)
- }
- },
- async update() {
- checkIfResticIsAvailable()
- const w = new Writer('Checking for latest restic version... ⏳')
- exec('restic', ['self-update'])
-
- w.replaceLn('Checking for latest autorestic version... ⏳')
- const { data: json } = await axios({
- method: 'get',
- url:
- 'https://api.github.com/repos/cupcakearmy/autorestic/releases/latest',
- responseType: 'json',
- })
-
- if (json.tag_name != VERSION) {
- const platformMap: { [key: string]: string } = {
- darwin: 'macos',
- }
-
- const name = `autorestic_${platformMap[process.platform] || process.platform}_${process.arch}`
- const dl = json.assets.find((asset: any) => asset.name === name)
-
- const to = INSTALL_DIR + '/autorestic'
- w.replaceLn('Downloading binary... 🌎')
- await downloadFile(dl.browser_download_url, to)
-
- chmodSync(to, 0o755)
- }
-
- w.done('All up to date! 🚀')
- },
- version() {
- console.log('version'.grey, VERSION)
- },
-}
-
-export const help = () => {
- console.log(
- '\nAutorestic'.blue +
- ` - ${VERSION} - Easy Restic CLI Utility` +
- '\n' +
- '\nOptions:'.yellow +
- `\n -c, --config Specify config file. Default: .autorestic.yml` +
- '\n' +
- '\nCommands:'.yellow +
- '\n info Show all locations and backends' +
- '\n check [-b, --backend] [-a, --all] Check backends' +
- '\n backup [-l, --location] [-a, --all] Backup all or specified locations' +
- '\n forget [-l, --location] [-a, --all] [--dry-run] Forget old snapshots according to declared policies' +
- '\n restore [-l, --location] [--from backend] [--to ] Restore all or specified locations' +
- '\n' +
- '\n exec [-b, --backend] [-a, --all] -- [native options] Execute native restic command' +
- '\n' +
- '\n install install restic' +
- '\n uninstall uninstall restic' +
- '\n update update restic' +
- '\n help Show help' +
- '\n' +
- '\nExamples: '.yellow +
- 'https://git.io/Jf0x6' +
- '\n',
- )
-}
-
-export const error = () => {
- help()
- console.log(
- `Invalid Command:`.red.underline,
- `${process.argv.slice(2).join(' ')}`,
- )
-}
-
-export default handlers
diff --git a/src/handlers/backup.ts b/src/handlers/backup.ts
new file mode 100644
index 0000000..11e68d1
--- /dev/null
+++ b/src/handlers/backup.ts
@@ -0,0 +1,13 @@
+import { checkAndConfigureBackendsForLocations } from '../backend'
+import { backupAll } from '../backup'
+import { Flags, Locations } from '../types'
+import { checkIfResticIsAvailable, parseLocations } from '../utils'
+
+export default function backup({ location, all }: Flags) {
+ checkIfResticIsAvailable()
+ const locations: Locations = parseLocations(location, all)
+ checkAndConfigureBackendsForLocations(locations)
+ backupAll(locations)
+
+ console.log('\nFinished!'.underline + ' 🎉')
+}
diff --git a/src/handlers/check.ts b/src/handlers/check.ts
new file mode 100644
index 0000000..df1d862
--- /dev/null
+++ b/src/handlers/check.ts
@@ -0,0 +1,9 @@
+import { checkAndConfigureBackends } from '../backend'
+import { Flags } from '../types'
+import { checkIfResticIsAvailable, parseBackend } from '../utils'
+
+export default function check({ backend, all }: Flags) {
+ checkIfResticIsAvailable()
+ const backends = parseBackend(backend, all)
+ checkAndConfigureBackends(backends)
+}
diff --git a/src/handlers/cron.ts b/src/handlers/cron.ts
new file mode 100644
index 0000000..1d1512b
--- /dev/null
+++ b/src/handlers/cron.ts
@@ -0,0 +1,7 @@
+import { runCron } from '../cron'
+import { checkIfResticIsAvailable } from '../utils'
+
+export function cron() {
+ checkIfResticIsAvailable()
+ runCron()
+}
diff --git a/src/handlers/exec.ts b/src/handlers/exec.ts
new file mode 100644
index 0000000..35b0045
--- /dev/null
+++ b/src/handlers/exec.ts
@@ -0,0 +1,14 @@
+import { getEnvFromBackend } from '../backend'
+import { Flags } from '../types'
+import { checkIfResticIsAvailable, exec as execCLI, parseBackend } from '../utils'
+
+export default function exec({ backend, all }: Flags, args: string[]) {
+ checkIfResticIsAvailable()
+ const backends = parseBackend(backend, all)
+ for (const [name, backend] of Object.entries(backends)) {
+ console.log(`\n${name}:\n`.grey.underline)
+ const env = getEnvFromBackend(backend)
+ const { out, err } = execCLI('restic', args, { env })
+ console.log(out, err)
+ }
+}
diff --git a/src/handlers/forget.ts b/src/handlers/forget.ts
new file mode 100644
index 0000000..b98dbb2
--- /dev/null
+++ b/src/handlers/forget.ts
@@ -0,0 +1,13 @@
+import { checkAndConfigureBackendsForLocations } from '../backend'
+import { forgetAll } from '../forget'
+import { Flags, Locations } from '../types'
+import { checkIfResticIsAvailable, parseLocations } from '../utils'
+
+export default function forget({ location, all, dryRun }: Flags) {
+ checkIfResticIsAvailable()
+ const locations: Locations = parseLocations(location, all)
+ checkAndConfigureBackendsForLocations(locations)
+ forgetAll(locations, dryRun)
+
+ console.log('\nFinished!'.underline + ' 🎉')
+}
diff --git a/src/handlers/info.ts b/src/handlers/info.ts
new file mode 100644
index 0000000..8cd8831
--- /dev/null
+++ b/src/handlers/info.ts
@@ -0,0 +1,18 @@
+import { config } from '../'
+import { fill, treeToString } from '../utils'
+
+const showAll = () => {
+ console.log('\n\n' + fill(32, '_') + 'LOCATIONS:'.underline)
+ for (const [key, data] of Object.entries(config.locations)) {
+ console.log(`\n${key.blue.underline}:`)
+ console.log(treeToString(data, ['to:', 'from:', 'hooks:', 'options:', 'cron:']))
+ }
+
+ console.log('\n\n' + fill(32, '_') + 'BACKENDS:'.underline)
+ for (const [key, data] of Object.entries(config.backends)) {
+ console.log(`\n${key.blue.underline}:`)
+ console.log(treeToString(data, ['type:', 'path:', 'key:']))
+ }
+}
+
+export default showAll
diff --git a/src/handlers/install.ts b/src/handlers/install.ts
new file mode 100644
index 0000000..0d7e7cb
--- /dev/null
+++ b/src/handlers/install.ts
@@ -0,0 +1,50 @@
+import { join } from 'path'
+import { chmodSync, renameSync, unlinkSync } from 'fs'
+import { tmpdir } from 'os'
+
+import axios from 'axios'
+import { Writer } from 'clitastic'
+
+import { INSTALL_DIR } from '..'
+import { checkIfCommandIsAvailable, checkIfResticIsAvailable, downloadFile, exec } from '../utils'
+
+export default async function install() {
+ try {
+ checkIfResticIsAvailable()
+ console.log('Restic is already installed')
+ return
+ } catch {}
+
+ const w = new Writer('Checking latest version... ⏳')
+ checkIfCommandIsAvailable('bzip2')
+ const { data: json } = await axios({
+ method: 'get',
+ url: 'https://api.github.com/repos/restic/restic/releases/latest',
+ responseType: 'json',
+ })
+
+ const archMap: { [a: string]: string } = {
+ x32: '386',
+ x64: 'amd64',
+ }
+
+ w.replaceLn('Downloading binary... 🌎')
+ const name = `${json.name.replace(' ', '_')}_${process.platform}_${archMap[process.arch]}.bz2`
+ const dl = json.assets.find((asset: any) => asset.name === name)
+ if (!dl) return console.log('Cannot get the right binary.'.red, 'Please see https://bit.ly/2Y1Rzai')
+
+ const tmp = join(tmpdir(), name)
+ const extracted = tmp.slice(0, -4) //without the .bz2
+
+ await downloadFile(dl.browser_download_url, tmp)
+
+ w.replaceLn('Decompressing binary... 📦')
+ exec('bzip2', ['-dk', tmp])
+ unlinkSync(tmp)
+
+ w.replaceLn(`Moving to ${INSTALL_DIR} 🚙`)
+ chmodSync(extracted, 0o755)
+ renameSync(extracted, INSTALL_DIR + '/restic')
+
+ w.done(`\nFinished! restic is installed under: ${INSTALL_DIR}`.underline + ' 🎉')
+}
diff --git a/src/handlers/restore.ts b/src/handlers/restore.ts
new file mode 100644
index 0000000..72707b9
--- /dev/null
+++ b/src/handlers/restore.ts
@@ -0,0 +1,9 @@
+import { restoreSingle } from '../restore'
+import { Flags } from '../types'
+import { checkIfResticIsAvailable, checkIfValidLocation } from '../utils'
+
+export default function restore({ location, to, from }: Flags) {
+ checkIfResticIsAvailable()
+ checkIfValidLocation(location)
+ restoreSingle(location, from, to)
+}
diff --git a/src/handlers/uninstall.ts b/src/handlers/uninstall.ts
new file mode 100644
index 0000000..184ad34
--- /dev/null
+++ b/src/handlers/uninstall.ts
@@ -0,0 +1,13 @@
+import { unlinkSync } from 'fs'
+
+import { INSTALL_DIR } from '..'
+
+export function uninstall() {
+ for (const bin of ['restic', 'autorestic'])
+ try {
+ unlinkSync(INSTALL_DIR + '/' + bin)
+ console.log(`Finished! ${bin} was uninstalled`)
+ } catch (e) {
+ console.log(`${bin} is already uninstalled`.red)
+ }
+}
diff --git a/src/handlers/upgrade.ts b/src/handlers/upgrade.ts
new file mode 100644
index 0000000..3c6880b
--- /dev/null
+++ b/src/handlers/upgrade.ts
@@ -0,0 +1,37 @@
+import { chmodSync } from 'fs'
+
+import axios from 'axios'
+import { Writer } from 'clitastic'
+
+import { INSTALL_DIR, VERSION } from '..'
+import { checkIfResticIsAvailable, downloadFile, exec } from '../utils'
+
+export async function upgrade() {
+ checkIfResticIsAvailable()
+ const w = new Writer('Checking for latest restic version... ⏳')
+ exec('restic', ['self-update'])
+
+ w.replaceLn('Checking for latest autorestic version... ⏳')
+ const { data: json } = await axios({
+ method: 'get',
+ url: 'https://api.github.com/repos/cupcakearmy/autorestic/releases/latest',
+ responseType: 'json',
+ })
+
+ if (json.tag_name != VERSION) {
+ const platformMap: { [key: string]: string } = {
+ darwin: 'macos',
+ }
+
+ const name = `autorestic_${platformMap[process.platform] || process.platform}_${process.arch}`
+ const dl = json.assets.find((asset: any) => asset.name === name)
+
+ const to = INSTALL_DIR + '/autorestic'
+ w.replaceLn('Downloading binary... 🌎')
+ await downloadFile(dl.browser_download_url, to)
+
+ chmodSync(to, 0o755)
+ }
+
+ w.done('All up to date! 🚀')
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..e15f349
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,104 @@
+import 'colors'
+import { program } from 'commander'
+
+import { unlock, readLock, writeLock } from './lock'
+import { Config } from './types'
+import { init } from './config'
+
+import info from './handlers/info'
+import check from './handlers/check'
+import backup from './handlers/backup'
+import restore from './handlers/restore'
+import forget from './handlers/forget'
+import { cron } from './handlers/cron'
+import exec from './handlers/exec'
+import install from './handlers/install'
+import { uninstall } from './handlers/uninstall'
+import { upgrade } from './handlers/upgrade'
+
+export const VERSION = '0.20'
+export const INSTALL_DIR = '/usr/local/bin'
+
+process.on('uncaughtException', (err) => {
+ console.log(err.message)
+ unlock()
+ process.exit(1)
+})
+
+let queue: Function = () => {}
+const enqueue = (fn: Function) => (cmd: any) => {
+ queue = () => fn(cmd.opts())
+}
+
+program.storeOptionsAsProperties()
+program.name('autorestic').version(VERSION)
+
+program.option('-c, --config ', 'Config file').option('-v, --verbose', 'Verbosity', false)
+
+program.command('info').action(enqueue(info))
+
+program
+ .command('check')
+ .description('Checks and initializes backend as needed')
+ .option('-b, --backend ')
+ .option('-a, --all')
+ .action(enqueue(check))
+
+program.command('backup').description('Performs a backup').option('-b, --backend ').option('-a, --all').action(enqueue(backup))
+
+program
+ .command('restore')
+ .description('Restores data to a specified folder from a location')
+ .requiredOption('-l, --location ')
+ .option('--from ')
+ .requiredOption('--to ', 'Path to save the restored data to')
+ .action(enqueue(restore))
+
+program
+ .command('forget')
+ .description('This will prune and remove data according to your policies')
+ .option('-l, --location ')
+ .option('-a, --all')
+ .option('--dry-run')
+ .action(enqueue(forget))
+
+program
+ .command('cron')
+ .description('Intended to be triggered by an automated system like systemd or crontab.')
+ .option('-a, --all')
+ .action(enqueue(cron))
+
+program
+ .command('exec')
+ .description('Run any native restic command on desired backends')
+ .option('-b, --backend ')
+ .option('-a, --all')
+ .action(({ args, all, backend }) => {
+ queue = () => exec({ all, backend }, args)
+ })
+
+program.command('install').description('Installs both restic and autorestic to /usr/local/bin').action(enqueue(install))
+
+program.command('uninstall').description('Uninstalls autorestic from the system').action(enqueue(uninstall))
+
+program.command('upgrade').alias('update').description('Checks and installs new autorestic versions').action(enqueue(upgrade))
+
+const { verbose, config: configFile } = program.parse(process.argv)
+
+export const VERBOSE = verbose
+export let config: Config = init(configFile)
+
+try {
+ const lock = readLock()
+ if (lock.running) throw new Error('An instance of autorestic is already running for this config file'.red)
+
+ writeLock({
+ ...lock,
+ running: true,
+ })
+ queue()
+} catch (e) {
+ console.error(e.message)
+} finally {
+ unlock()
+}
diff --git a/src/info.ts b/src/info.ts
index 968927b..dc46faf 100644
--- a/src/info.ts
+++ b/src/info.ts
@@ -1,26 +1,18 @@
-import { config } from './autorestic'
+import { config } from './'
import { fill, treeToString } from './utils'
-
-
const showAll = () => {
- console.log('\n\n' + fill(32, '_') + 'LOCATIONS:'.underline)
- for (const [key, data] of Object.entries(config.locations)) {
- console.log(`\n${key.blue.underline}:`)
- console.log(treeToString(
- data,
- ['to:', 'from:', 'hooks:', 'options:', 'cron:'],
- ))
- }
+ console.log('\n\n' + fill(32, '_') + 'LOCATIONS:'.underline)
+ for (const [key, data] of Object.entries(config.locations)) {
+ console.log(`\n${key.blue.underline}:`)
+ console.log(treeToString(data, ['to:', 'from:', 'hooks:', 'options:', 'cron:']))
+ }
- console.log('\n\n' + fill(32, '_') + 'BACKENDS:'.underline)
- for (const [key, data] of Object.entries(config.backends)) {
- console.log(`\n${key.blue.underline}:`)
- console.log(treeToString(
- data,
- ['type:', 'path:', 'key:'],
- ))
- }
+ console.log('\n\n' + fill(32, '_') + 'BACKENDS:'.underline)
+ for (const [key, data] of Object.entries(config.backends)) {
+ console.log(`\n${key.blue.underline}:`)
+ console.log(treeToString(data, ['type:', 'path:', 'key:']))
+ }
}
-export default showAll
\ No newline at end of file
+export default showAll
diff --git a/src/lock.ts b/src/lock.ts
index 962d463..55ded75 100644
--- a/src/lock.ts
+++ b/src/lock.ts
@@ -1,7 +1,7 @@
import fs from 'fs'
-import { pathRelativeToConfigFile } from "./utils"
-import { Lockfile } from "./types"
+import { pathRelativeToConfigFile } from './utils'
+import { Lockfile } from './types'
export const getLockFileName = () => {
const LOCK_FILE = '.autorestic.lock'
@@ -12,11 +12,11 @@ export const readLock = (): Lockfile => {
const name = getLockFileName()
let lock = {
running: false,
- crons: {}
+ crons: {},
}
try {
lock = JSON.parse(fs.readFileSync(name, { encoding: 'utf-8' }))
- } catch { }
+ } catch {}
return lock
}
export const writeLock = (lock: Lockfile) => {
@@ -29,4 +29,4 @@ export const unlock = () => {
...readLock(),
running: false,
})
-}
\ No newline at end of file
+}
diff --git a/src/restore.ts b/src/restore.ts
index a776764..1759e85 100644
--- a/src/restore.ts
+++ b/src/restore.ts
@@ -1,78 +1,63 @@
import { Writer } from 'clitastic'
import { resolve } from 'path'
-import { config } from './autorestic'
+import { config } from './'
import { getEnvFromBackend } from './backend'
import { LocationFromPrefixes } from './config'
import { Backend } from './types'
-import {
- checkIfDockerVolumeExistsOrFail,
- decodeLocationFromPrefix,
- exec,
- execPlain,
- getPathFromVolume,
-} from './utils'
-
-
+import { checkIfDockerVolumeExistsOrFail, decodeLocationFromPrefix, exec, execPlain, getPathFromVolume } from './utils'
export const restoreToFilesystem = (from: string, to: string, backend: Backend) => {
- exec(
- 'restic',
- ['restore', 'latest', '--path', resolve(from), '--target', to],
- { env: getEnvFromBackend(backend) },
- )
+ exec('restic', ['restore', 'latest', '--path', resolve(from), '--target', to], { env: getEnvFromBackend(backend) })
}
export const restoreToVolume = (volume: string, backend: Backend) => {
- const tmp = getPathFromVolume(volume)
- try {
- restoreToFilesystem(tmp, tmp, backend)
- try {
- checkIfDockerVolumeExistsOrFail(volume)
- } catch {
- execPlain(`docker volume create ${volume}`)
- }
-
- // For incremental backups. Unfortunately due to how the docker mounts work the permissions get lost.
- // execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine cp -aT /backup /data`)
- execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar xf /backup/archive.tar -C /data`)
- } finally {
- execPlain(`rm -rf ${tmp}`)
- }
+ const tmp = getPathFromVolume(volume)
+ try {
+ restoreToFilesystem(tmp, tmp, backend)
+ try {
+ checkIfDockerVolumeExistsOrFail(volume)
+ } catch {
+ execPlain(`docker volume create ${volume}`)
+ }
+
+ // For incremental backups. Unfortunately due to how the docker mounts work the permissions get lost.
+ // execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine cp -aT /backup /data`)
+ execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar xf /backup/archive.tar -C /data`)
+ } finally {
+ execPlain(`rm -rf ${tmp}`)
+ }
}
export const restoreSingle = (locationName: string, from: string, to?: string) => {
- const location = config.locations[locationName]
-
- const baseText = locationName.green + '\t\t'
- const w = new Writer(baseText + `Restoring...`)
-
- let backendName: string = Array.isArray(location.to) ? location.to[0] : location.to
- if (from) {
- if (!location.to.includes(from)) {
- w.done(baseText + `Backend ${from} is not a valid location for ${locationName}`.red)
- return
- }
- backendName = from
- w.replaceLn(baseText + `Restoring from ${backendName.blue}...`)
- } else if (Array.isArray(location.to) && location.to.length > 1) {
- w.replaceLn(baseText + `Restoring from ${backendName.blue}...\tTo select a specific backend pass the ${'--from'.blue} flag`)
- }
- const backend = config.backends[backendName]
-
- const [type, value] = decodeLocationFromPrefix(location.from)
- switch (type) {
-
- case LocationFromPrefixes.Filesystem:
- if (!to) throw new Error(`You need to specify the restore path with --to`.red)
- restoreToFilesystem(value, to, backend)
- break
-
- case LocationFromPrefixes.DockerVolume:
- restoreToVolume(value, backend)
- break
-
- }
- w.done(locationName.green + '\t\tDone 🎉')
+ const location = config.locations[locationName]
+
+ const baseText = locationName.green + '\t\t'
+ const w = new Writer(baseText + `Restoring...`)
+
+ let backendName: string = Array.isArray(location.to) ? location.to[0] : location.to
+ if (from) {
+ if (!location.to.includes(from)) {
+ w.done(baseText + `Backend ${from} is not a valid location for ${locationName}`.red)
+ return
+ }
+ backendName = from
+ w.replaceLn(baseText + `Restoring from ${backendName.blue}...`)
+ } else if (Array.isArray(location.to) && location.to.length > 1) {
+ w.replaceLn(baseText + `Restoring from ${backendName.blue}...\tTo select a specific backend pass the ${'--from'.blue} flag`)
+ }
+ const backend = config.backends[backendName]
+
+ const [type, value] = decodeLocationFromPrefix(location.from)
+ switch (type) {
+ case LocationFromPrefixes.Filesystem:
+ if (!to) throw new Error(`You need to specify the restore path with --to`.red)
+ restoreToFilesystem(value, to, backend)
+ break
+
+ case LocationFromPrefixes.DockerVolume:
+ restoreToVolume(value, backend)
+ break
+ }
+ w.done(locationName.green + '\t\tDone 🎉')
}
-
diff --git a/src/types.ts b/src/types.ts
index 1380d22..b40c439 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -3,84 +3,77 @@ export type StringOrArray = string | string[]
// BACKENDS
type BackendLocal = {
- type: 'local'
- key: string
- path: string
+ type: 'local'
+ key: string
+ path: string
}
type BackendSFTP = {
- type: 'sftp'
- key: string
- path: string
- password?: string
+ type: 'sftp'
+ key: string
+ path: string
+ password?: string
}
type BackendREST = {
- type: 'rest'
- key: string
- path: string
- user?: string
- password?: string
+ type: 'rest'
+ key: string
+ path: string
+ user?: string
+ password?: string
}
type BackendS3 = {
- type: 's3'
- key: string
- path: string
- aws_access_key_id: string
- aws_secret_access_key: string
+ type: 's3'
+ key: string
+ path: string
+ aws_access_key_id: string
+ aws_secret_access_key: string
}
type BackendB2 = {
- type: 'b2'
- key: string
- path: string
- b2_account_id: string
- b2_account_key: string
+ type: 'b2'
+ key: string
+ path: string
+ b2_account_id: string
+ b2_account_key: string
}
type BackendAzure = {
- type: 'azure'
- key: string
- path: string
- azure_account_name: string
- azure_account_key: string
+ type: 'azure'
+ key: string
+ path: string
+ azure_account_name: string
+ azure_account_key: string
}
type BackendGS = {
- type: 'gs'
- key: string
- path: string
- google_project_id: string
- google_application_credentials: string
+ type: 'gs'
+ key: string
+ path: string
+ google_project_id: string
+ google_application_credentials: string
}
-export type Backend =
- | BackendAzure
- | BackendB2
- | BackendGS
- | BackendLocal
- | BackendREST
- | BackendS3
- | BackendSFTP
+export type Backend = BackendAzure | BackendB2 | BackendGS | BackendLocal | BackendREST | BackendS3 | BackendSFTP
export type Backends = { [name: string]: Backend }
// LOCATIONS
export type Location = {
- from: string
- to: StringOrArray
- cron?: string
- hooks?: {
- before?: StringOrArray
- after?: StringOrArray
- }
- options?: {
- [key: string]: {
- [key: string]: StringOrArray
- }
- }
+ from: string
+ to: StringOrArray
+ cron?: string
+ hooks?: {
+ before?: StringOrArray
+ after?: StringOrArray
+ }
+ options?: {
+ [key: string]: {
+ [key: string]: StringOrArray
+ }
+ }
}
export type Locations = { [name: string]: Location }
@@ -88,17 +81,17 @@ export type Locations = { [name: string]: Location }
// OTHER
export type Config = {
- locations: Locations
- backends: Backends
+ locations: Locations
+ backends: Backends
}
export type Lockfile = {
- running: boolean
- crons: {
- [name: string]: {
- lastRun: number
- }
- }
+ running: boolean
+ crons: {
+ [name: string]: {
+ lastRun: number
+ }
+ }
}
export type Flags = { [arg: string]: any }
diff --git a/src/utils.ts b/src/utils.ts
index 7b33d3d..fb42d01 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -1,13 +1,15 @@
-import axios from 'axios'
import { spawnSync, SpawnSyncOptions } from 'child_process'
import { createHash, randomBytes } from 'crypto'
import { createWriteStream, renameSync, unlinkSync } from 'fs'
import { homedir, tmpdir } from 'os'
import { dirname, isAbsolute, join, resolve } from 'path'
+
+import axios from 'axios'
import { Duration, Humanizer } from 'uhrwerk'
import { CONFIG_FILE, LocationFromPrefixes } from './config'
-import { Location } from './types'
+import { Backends, Location, Locations } from './types'
+import { config } from '.'
export const exec = (command: string, args: string[], { env, ...rest }: SpawnSyncOptions = {}) => {
const { stdout, stderr, status } = spawnSync(command, args, {
@@ -106,6 +108,35 @@ export const getFlagsFromLocation = (location: Location, command?: string): stri
return flags
}
+export function parseBackend(backends: string[] = [], all: boolean = false): Backends {
+ if (all) return config.backends
+ if (backends.length) {
+ for (const backend of backends) if (!config.backends[backend]) throw new Error('Invalid backend: '.red + backend)
+ return filterObjectByKey(config.backends, backends)
+ } else {
+ throw new Error(
+ 'No backends specified.'.red + '\n-a, --all, -a\t\t\tSelect all.' + '\n-b, --backend \t\tSpecify one or more backend'
+ )
+ }
+}
+
+export function checkIfValidLocation(location: string) {
+ if (!config.locations[location]) throw new Error('Invalid location: '.red + location)
+}
+
+export function parseLocations(locations: string[] = [], all: boolean = false): Locations {
+ if (all) {
+ return config.locations
+ }
+ if (locations.length) {
+ for (const location of locations) checkIfValidLocation(location)
+ return filterObjectByKey(config.locations, locations)
+ }
+ throw new Error(
+ 'No locations specified.'.red + '\n-a, --all\t\t\tSelect all.' + '\n-l, --location \t\t\tSpecify one or more location'
+ )
+}
+
export const makeArrayIfIsNot = (maybeArray: T | T[]): T[] => (Array.isArray(maybeArray) ? maybeArray : [maybeArray])
export const fill = (length: number, filler = ' '): string => new Array(length).fill(filler).join('')
diff --git a/tsconfig.json b/tsconfig.json
index 9ad2430..7230fda 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,6 +3,7 @@
"target": "esnext",
"module": "commonjs",
"outDir": "./lib",
+ "rootDir": "./src",
"strict": true,
"esModuleInterop": true
}
diff --git a/yarn.lock b/yarn.lock
index 5e88375..76ae2fd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3,21 +3,21 @@
"@babel/parser@^7.9.4":
- version "7.10.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315"
- integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA==
+ version "7.12.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.5.tgz#b4af32ddd473c0bfa643bd7ff0728b8e71b81ea0"
+ integrity sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==
"@babel/runtime@^7.9.2":
- version "7.10.3"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364"
- integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==
+ version "7.12.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
+ integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
dependencies:
regenerator-runtime "^0.13.4"
"@codedoc/cli@0.2.x":
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/@codedoc/cli/-/cli-0.2.1.tgz#03daa1b1e0cedff25c0b5dc29ab8c823b2dd28ef"
- integrity sha512-kdxbcKaxM3AUEoD70trMrUFitdbJ8mTS7u5ojJfzZ2uQtTIjO1D0XJLydsPyPXqLQf/TyOZJPEm03Q3d9Smt0A==
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/@codedoc/cli/-/cli-0.2.6.tgz#5e6e981f8eafefcab2b8c81ee6c14815baf2732c"
+ integrity sha512-zn92PvMamXCteZudz1i606qa4bPXcXveNgb6oQTAiW7Lq+bRMZHUyKvA3Q3jVwlQtV7SidJg3jA4RwkMllktog==
dependencies:
chalk "^4.0.0"
shelljs "^0.8.3"
@@ -46,11 +46,6 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"
-"@types/color-name@^1.1.1":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
- integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
-
"@types/js-yaml@3.x.x":
version "3.12.5"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb"
@@ -62,9 +57,9 @@
integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
"@types/node@14.x.x":
- version "14.0.14"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce"
- integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==
+ version "14.14.6"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f"
+ integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
"@types/strip-bom@^3.0.0":
version "3.0.0"
@@ -76,10 +71,10 @@
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
-ajv@^6.5.5:
- version "6.12.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
- integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
+ajv@^6.12.3:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
@@ -87,11 +82,10 @@ ajv@^6.5.5:
uri-js "^4.2.2"
ansi-styles@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
- integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
- "@types/color-name" "^1.1.1"
color-convert "^2.0.1"
anymatch@~3.1.1:
@@ -147,9 +141,9 @@ aws-sign2@~0.7.0:
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
- integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
axios@0.19.x:
version "0.19.2"
@@ -235,9 +229,9 @@ chalk@^4.0.0:
supports-color "^7.1.0"
chokidar@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
- integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b"
+ integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
@@ -245,7 +239,7 @@ chokidar@^3.4.0:
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
- readdirp "~3.4.0"
+ readdirp "~3.5.0"
optionalDependencies:
fsevents "~2.1.2"
@@ -280,6 +274,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
+commander@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75"
+ integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -291,9 +290,9 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cron-parser@2.x.x:
- version "2.15.0"
- resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.15.0.tgz#04803cd51d8efcfcc6f83ac08e60f3f8c40c7ec5"
- integrity sha512-rMFkrQw8+oG5OuwjiXesup4KeIlEG/IU82YtG4xyAHbO5jhKmYaHPp/ZNhq9+7TjSJ65E3zV3kQPUbmXSff2/g==
+ version "2.17.0"
+ resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.17.0.tgz#5707421a7e0a73ee74675d1c032a2f14123f2cf8"
+ integrity sha512-oTmzVEwlurRe51HqTm4afshVr8Rkxy9kFiWxh5e6SmrY2o9NDYU4S6SduanBZYXLgkLy0skA98y7/tztW/DmjQ==
dependencies:
is-nan "^1.3.0"
moment-timezone "^0.5.31"
@@ -458,9 +457,9 @@ fast-levenshtein@~2.0.6:
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fastq@^1.6.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"
- integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.9.0.tgz#e16a72f338eaca48e91b5c23593bcc2ef66b7947"
+ integrity sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==
dependencies:
reusify "^1.0.4"
@@ -527,6 +526,11 @@ fsevents@~2.1.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@@ -575,22 +579,17 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
-growly@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
- integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
-
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.3:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
- integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
- ajv "^6.5.5"
+ ajv "^6.12.3"
har-schema "^2.0.0"
has-flag@^4.0.0:
@@ -598,6 +597,13 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
hosted-git-info@^2.1.4:
version "2.8.8"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
@@ -662,6 +668,13 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.0.0"
+is-core-module@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946"
+ integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==
+ dependencies:
+ has "^1.0.3"
+
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
@@ -701,21 +714,11 @@ is-utf8@^0.2.0:
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
-is-wsl@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
- integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
-
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@@ -851,7 +854,7 @@ minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
-minimist@1.x.x, minimist@^1.1.3, minimist@^1.2.5:
+minimist@^1.1.3, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
@@ -876,9 +879,9 @@ moment-timezone@^0.5.31:
moment ">= 2.9.0"
"moment@>= 2.9.0":
- version "2.27.0"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
- integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
+ version "2.29.1"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
+ integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
ms@2.0.0:
version "2.0.0"
@@ -893,17 +896,6 @@ multistream@^2.1.1:
inherits "^2.0.1"
readable-stream "^2.0.5"
-node-notifier@^5.4.0:
- version "5.4.3"
- resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50"
- integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==
- dependencies:
- growly "^1.3.0"
- is-wsl "^1.1.0"
- semver "^5.5.0"
- shellwords "^0.1.1"
- which "^1.3.0"
-
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -1028,7 +1020,7 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-pkg-fetch@^2.6.7:
+pkg-fetch@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-2.6.9.tgz#c18c5fa9604c57a3df3d9630afb64e176bc8732d"
integrity sha512-EnVR8LRILXBvaNP+wJOSY02c3+qDDfyEyR+aqAHLhcc9PBnbxFT9UZ1+If49goPQzQPn26TzF//fc6KXZ0aXEg==
@@ -1046,9 +1038,9 @@ pkg-fetch@^2.6.7:
unique-temp-dir "^1.0.0"
pkg@4.4.x:
- version "4.4.8"
- resolved "https://registry.yarnpkg.com/pkg/-/pkg-4.4.8.tgz#145fb81f31eebfb90d2010dd2c4b663ca0db4009"
- integrity sha512-Fqqv0iaX48U3CFZxd6Dq6JKe7BrAWbgRAqMJkz/m8W3H5cqJ6suvsUWe5AJPRlN/AhbBYXBJ0XG9QlYPTXcVFA==
+ version "4.4.9"
+ resolved "https://registry.yarnpkg.com/pkg/-/pkg-4.4.9.tgz#be04f8d03795772b7c4394724ae7252d7c2a4519"
+ integrity sha512-FK4GqHtcCY2PPPVaKViU0NyRzpo6gCS7tPKN5b7AkElqjAOCH1bsRKgohEnxThr6DWfTGByGqba2YHGR/BqbmA==
dependencies:
"@babel/parser" "^7.9.4"
"@babel/runtime" "^7.9.2"
@@ -1059,7 +1051,7 @@ pkg@4.4.x:
into-stream "^5.1.1"
minimist "^1.2.5"
multistream "^2.1.1"
- pkg-fetch "^2.6.7"
+ pkg-fetch "^2.6.9"
progress "^2.0.3"
resolve "^1.15.1"
stream-meter "^1.0.4"
@@ -1124,10 +1116,10 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readdirp@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
- integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
+readdirp@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
+ integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
dependencies:
picomatch "^2.2.1"
@@ -1147,9 +1139,9 @@ redent@^1.0.0:
strip-indent "^1.0.1"
regenerator-runtime@^0.13.4:
- version "0.13.5"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
- integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+ version "0.13.7"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+ integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
repeating@^2.0.0:
version "2.0.1"
@@ -1192,10 +1184,11 @@ request@^2.88.0:
uuid "^3.3.2"
resolve@^1.0.0, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.15.1:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
- integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130"
+ integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==
dependencies:
+ is-core-module "^2.0.0"
path-parse "^1.0.6"
reusify@^1.0.4:
@@ -1211,9 +1204,9 @@ rimraf@^2.6.1:
glob "^7.1.3"
run-parallel@^1.1.9:
- version "1.1.9"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
- integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
+ version "1.1.10"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef"
+ integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
version "5.2.1"
@@ -1230,7 +1223,7 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-"semver@2 || 3 || 4 || 5", semver@^5.5.0:
+"semver@2 || 3 || 4 || 5":
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -1249,11 +1242,6 @@ shelljs@^0.8.3:
interpret "^1.0.0"
rechoir "^0.6.2"
-shellwords@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
- integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
-
signal-exit@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@@ -1299,9 +1287,9 @@ spdx-expression-parse@^3.0.0:
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
- integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce"
+ integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==
sprintf-js@~1.0.2:
version "1.0.3"
@@ -1362,9 +1350,9 @@ strip-json-comments@^2.0.0:
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
@@ -1399,24 +1387,23 @@ trim-newlines@^1.0.0:
integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
ts-node-dev@^1.0.0-pre.40, ts-node-dev@^1.0.0-pre.44:
- version "1.0.0-pre.49"
- resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.0.0-pre.49.tgz#28836f73fe9513f339ccb1c0bebdb2e2e25c52f0"
- integrity sha512-iJd4QPPOaCAByl/WuEdmDX8xDR2GmoWYu6aKvGudGUcfP1sJRjpaHb7oFDuvBspQF1xhxUdbjfHuvEtZPwKZFQ==
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.0.0.tgz#24a2270d225c29ce269de2a31f88b1b259fc84cb"
+ integrity sha512-leA/3TgGtnVU77fGngBwVZztqyDRXirytR7dMtMWZS5b2hGpLl+VDnB0F/gf3A+HEPSzS/KwxgXFP7/LtgX4MQ==
dependencies:
chokidar "^3.4.0"
dateformat "~1.0.4-1.2.3"
dynamic-dedupe "^0.3.0"
minimist "^1.2.5"
mkdirp "^1.0.4"
- node-notifier "^5.4.0"
resolve "^1.0.0"
rimraf "^2.6.1"
source-map-support "^0.5.12"
tree-kill "^1.2.2"
- ts-node "^8.10.2"
+ ts-node "^9.0.0"
tsconfig "^7.0.0"
-ts-node@^8.10.2, ts-node@^8.8.2:
+ts-node@^8.8.2:
version "8.10.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==
@@ -1427,6 +1414,17 @@ ts-node@^8.10.2, ts-node@^8.8.2:
source-map-support "^0.5.17"
yn "3.1.1"
+ts-node@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3"
+ integrity sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==
+ dependencies:
+ arg "^4.1.0"
+ diff "^4.0.1"
+ make-error "^1.1.1"
+ source-map-support "^0.5.17"
+ yn "3.1.1"
+
tsconfig@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7"
@@ -1457,9 +1455,9 @@ type-check@~0.3.2:
prelude-ls "~1.1.2"
typescript@3.9.x, typescript@^3.8.3:
- version "3.9.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
- integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
+ version "3.9.7"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
+ integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
uhrwerk@1.x.x:
version "1.0.2"
@@ -1486,9 +1484,9 @@ universalify@^0.1.0:
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
+ integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==
dependencies:
punycode "^2.1.0"
@@ -1519,13 +1517,6 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
-which@^1.3.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
- integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
- dependencies:
- isexe "^2.0.0"
-
word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"