loading improvements
No files matched your search
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"core.min.js": "core.3db744fc07.min.js",
|
||||
"vendor.min.js": "vendor.9df222182a.min.js",
|
||||
"mermaid.min.js": "mermaid.f848a72d16.min.js",
|
||||
"all.min.css": "all.8d9fbb7ca6.min.css"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 563 KiB After Width: | Height: | Size: 469 KiB |
|
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 416 KiB After Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 175 KiB |
@@ -1,6 +1,6 @@
|
||||
<!-- index.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" ng-app="anonymous-github" ng-controller="mainController">
|
||||
<html lang="en" ng-controller="mainController">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
@@ -38,8 +38,16 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<link rel="stylesheet" href="/css/all.min.css" />
|
||||
<noscript>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
/>
|
||||
</noscript>
|
||||
<link rel="stylesheet" href="/css/__ALL_CSS__" />
|
||||
</head>
|
||||
<body keypress-events class="d-flex flex-column">
|
||||
<ng-include src="'partials/header.htm'"></ng-include>
|
||||
@@ -74,14 +82,37 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/script/bundle.min.js"></script>
|
||||
<script src="/script/__CORE_JS__"></script>
|
||||
<script>
|
||||
ace.config.set("basePath", "/script/external/ace/");
|
||||
PDFJS.workerSrc = "/script/external/pdf.worker.js";
|
||||
// Lazy-load mermaid only when a mermaid diagram is encountered
|
||||
window.loadMermaid = function () {
|
||||
if (window._mermaidLoaded || window._mermaidLoading) return;
|
||||
window._mermaidLoading = true;
|
||||
var s = document.createElement("script");
|
||||
s.src = "/script/__MERMAID_JS__";
|
||||
s.onload = function () {
|
||||
window._mermaidLoaded = true;
|
||||
window._mermaidLoading = false;
|
||||
if (typeof mermaid !== "undefined") {
|
||||
mermaid.initialize({ startOnLoad: false, theme: "default", securityLevel: "loose" });
|
||||
window.mermaidInitialized = true;
|
||||
var els = document.querySelectorAll(".mermaid:not([data-processed])");
|
||||
if (els.length) mermaid.init(undefined, els);
|
||||
}
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
};
|
||||
</script>
|
||||
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
|
||||
<script src="/script/__VENDOR_JS__" defer onload="
|
||||
ace.config.set('basePath', '/script/external/ace/');
|
||||
PDFJS.workerSrc = '/script/external/pdf.worker.js';
|
||||
angular.bootstrap(document, ['anonymous-github']);
|
||||
"></script>
|
||||
<script>
|
||||
(function () {
|
||||
window.addEventListener("load", function () {
|
||||
var s = document.createElement("script");
|
||||
s.src = "https://storage.ko-fi.com/cdn/scripts/overlay-widget.js";
|
||||
s.onload = function () {
|
||||
var isDark = localStorage.getItem("darkMode") === "true";
|
||||
kofiWidgetOverlay.draw("tdurieux", {
|
||||
type: "floating-chat",
|
||||
@@ -93,7 +124,9 @@
|
||||
? "#1A1815"
|
||||
: "#FAF9F6",
|
||||
});
|
||||
})();
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -193,6 +193,7 @@
|
||||
<div class="col-md-5 order-md-1">
|
||||
<img
|
||||
width="500"
|
||||
loading="lazy"
|
||||
src="/imgs/anonymize.png"
|
||||
class="featurette-image img-fluid mx-auto"
|
||||
alt="Anonymize form"
|
||||
@@ -214,6 +215,7 @@
|
||||
<div class="col-md-5">
|
||||
<img
|
||||
width="500"
|
||||
loading="lazy"
|
||||
src="/imgs/explorer.png"
|
||||
class="featurette-image img-fluid mx-auto"
|
||||
alt="Repository explorer"
|
||||
@@ -234,6 +236,7 @@
|
||||
<div class="col-md-5 order-md-1">
|
||||
<img
|
||||
width="500"
|
||||
loading="lazy"
|
||||
src="/imgs/dashboard.png"
|
||||
class="featurette-image img-fluid mx-auto"
|
||||
alt="Dashboard"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
!function(fe){"use strict";function i(e){if(!ye(e))return an;S(e.objectMaxDepth)&&(an.objectMaxDepth=_(e.objectMaxDepth)?e.objectMaxDepth:NaN),S(e.urlErrorParamsEnabled)&&x(e.urlErrorParamsEnabled)&&(an.urlErrorParamsEnabled=e.urlErrorParamsEnabled)}function _(e){return b(e)&&0<e}function T(s,o){return o=o||Error,function(){var e=arguments[0];for(t="["+(s?s+":":"")+e+"] http://errors.angularjs.org/1.8.2/"+(s?s+"/":"")+e,e=1;e<arguments.length;e++){var t=t+(1==e?"?":"&")+"p"+(e-1)+"=",i=encodeURIComponent,n=arguments[e];t+=i(n="function"==typeof n?n.toString().replace(/ \{[\s\S]*$/,""):void 0===n?"undefined":"string"!=typeof n?JSON.stringify(n):n)}return new o(t)}}function D(e){var t;return null!=e&&!g(e)&&(_e(e)||$e(e)||Se&&e instanceof Se||b(t="length"in Object(e)&&e.length)&&(0<=t&&t-1 in e||"function"==typeof e.item))}function de(e,t,i){if(e)if(je(e))for(s in e)"prototype"!==s&&"length"!==s&&"name"!==s&&e.hasOwnProperty(s)&&t.call(i,e[s],s,e);else if(_e(e)||D(e))for(var n="object"!=typeof e,s=0,o=e.length;s<o;s++)(n||s in e)&&t.call(i,e[s],s,e);else if(e.forEach&&e.forEach!==de)e.forEach(t,i,e);else if(u(e))for(s in e)t.call(i,e[s],s,e);else if("function"==typeof e.hasOwnProperty)for(s in e)e.hasOwnProperty(s)&&t.call(i,e[s],s,e);else for(s in e)cn.call(e,s)&&t.call(i,e[s],s,e);return e}function a(e,t,i){for(var n=Object.keys(e).sort(),s=0;s<n.length;s++)t.call(i,e[n[s]],n[s])}function w(i){return function(e,t){i(t,e)}}function p(e,t,i){for(var n=e.$$hashKey,s=0,o=t.length;s<o;++s){var a=t[s];if(ye(a)||je(a))for(var r=Object.keys(a),c=0,u=r.length;c<u;c++){var h=r[c],g=a[h];i&&ye(g)?j(g)?e[h]=new Date(g.valueOf()):f(g)?e[h]=new RegExp(g):g.nodeName?e[h]=g.cloneNode(!0):N(g)?e[h]=g.clone():"__proto__"!==h&&(ye(e[h])||(e[h]=_e(g)?[]:{}),p(e[h],[g],!0)):e[h]=g}}return n?e.$$hashKey=n:delete e.$$hashKey,e}function be(e){return p(e,hn.call(arguments,1),!1)}function n(e){return p(e,hn.call(arguments,1),!0)}function d(e){return parseInt(e,10)}function Oe(e,t){return be(Object.create(e),t)}function k(){}function De(e){return e}function E(e){return function(){return e}}function h(e){return je(e.toString)&&e.toString!==v}function ve(e){return void 0===e}function S(e){return void 0!==e}function ye(e){return null!==e&&"object"==typeof e}function u(e){return null!==e&&"object"==typeof e&&!pn(e)}function $e(e){return"string"==typeof e}function b(e){return"number"==typeof e}function j(e){return"[object Date]"===v.call(e)}function _e(e){return Array.isArray(e)||e instanceof Array}function Ne(e){switch(v.call(e)){case"[object Error]":case"[object Exception]":case"[object DOMException]":return 1;default:return e instanceof Error}}function je(e){return"function"==typeof e}function f(e){return"[object RegExp]"===v.call(e)}function g(e){return e&&e.window===e}function Ie(e){return e&&e.$evalAsync&&e.$watch}function x(e){return"boolean"==typeof e}function N(e){return!(!e||!(e.nodeName||e.prop&&e.attr&&e.find))}function we(e){return Ce(e.nodeName||e[0]&&e[0].nodeName)}function Le(e,t){t=e.indexOf(t);return 0<=t&&e.splice(t,1),t}function I(e,i,t){function s(e,t,i){if(--i<0)return"...";var n=t.$$hashKey;if(_e(e))for(var s=0,o=e.length;s<o;s++)t.push(a(e[s],i));else if(u(e))for(s in e)t[s]=a(e[s],i);else if(e&&"function"==typeof e.hasOwnProperty)for(s in e)e.hasOwnProperty(s)&&(t[s]=a(e[s],i));else for(s in e)cn.call(e,s)&&(t[s]=a(e[s],i));return n?t.$$hashKey=n:delete t.$$hashKey,t}function a(e,t){if(!ye(e))return e;if(-1!==(i=o.indexOf(e)))return r[i];if(g(e)||Ie(e))throw mn("cpws");var i=!1,n=function(e){switch(v.call(e)){case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Float32Array]":case"[object Float64Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return new e.constructor(a(e.buffer),e.byteOffset,e.length);case"[object ArrayBuffer]":var t;return e.slice?e.slice(0):(t=new ArrayBuffer(e.byteLength),new Uint8Array(t).set(new Uint8Array(e)),t);case"[object Boolean]":case"[object Number]":case"[object String]":case"[object Date]":return new e.constructor(e.valueOf());case"[object RegExp]":return(t=new RegExp(e.source,e.toString().match(/[^/]*$/)[0])).lastIndex=e.lastIndex,t;case"[object Blob]":return new e.constructor([e],{type:e.type})}if(je(e.cloneNode))return e.cloneNode(!0)}(e);return void 0===n&&(n=_e(e)?[]:Object.create(pn(e)),i=!0),o.push(e),r.push(n),i?s(e,n,t):n}var n,o=[],r=[];if(t=_(t)?t:NaN,i){if((n=i)&&b(n.length)&&bn.test(v.call(n))||"[object ArrayBuffer]"===v.call(i))throw mn("cpta");if(e===i)throw mn("cpi");return _e(i)?i.length=0:de(i,function(e,t){"$$hashKey"!==t&&delete i[t]}),o.push(e),r.push(i),s(e,i,t)}return a(e,t)}function Pe(e,t){return e===t||e!=e&&t!=t}function xe(e,t){if(e===t)return!0;if(null!==e&&null!==t){if(e!=e&&t!=t)return!0;var i,n=typeof e;if(n===typeof t&&"object"===n){if(!_e(e)){if(j(e))return!!j(t)&&Pe(e.getTime(),t.getTime());if(f(e))return!!f(t)&&e.toString()===t.toString();Line truncated
|
||||
${e}</blockquote>
|
||||
`}html(e,t){return e}heading(e,t,i){return`<h${t}>${e}</h${t}>
|
||||
`}hr(){return"<hr>\n"}list(e,t,i){var n=t?"ol":"ul";return"<"+n+(t&&1!==i?' start="'+i+'"':"")+">\n"+e+"</"+n+">\n"}listitem(e,t,i){return`<li>${e}</li>
|
||||
`}checkbox(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph(e){return`<p>${e}</p>
|
||||
`}table(e,t){return"<table>\n<thead>\n"+e+"</thead>\n"+(t=t&&`<tbody>${t}</tbody>`)+"</table>\n"}tablerow(e){return`<tr>
|
||||
${e}</tr>
|
||||
`}tablecell(e,t){var i=t.header?"th":"td";return(t.align?`<${i} align="${t.align}">`:`<${i}>`)+e+`</${i}>
|
||||
`}strong(e){return`<strong>${e}</strong>`}em(e){return`<em>${e}</em>`}codespan(e){return`<code>${e}</code>`}br(){return"<br>"}del(e){return`<del>${e}</del>`}link(e,t,i){var n=c(e);if(null===n)return i;let s='<a href="'+(e=n)+'"';return t&&(s+=' title="'+t+'"'),s+=">"+i+"</a>"}image(e,t,i){var n=c(e);if(null===n)return i;let s=`<img src="${e=n}" alt="${i}"`;return t&&(s+=` title="${t}"`),s+=">"}text(e){return e}}class O{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,i){return""+i}image(e,t,i){return""+i}br(){return""}}class D{options;renderer;textRenderer;constructor(e){this.options=e||t.defaults,this.options.renderer=this.options.renderer||new A,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new O}static parse(e,t){return new D(t).parse(e)}static parseInline(e,t){return new D(t).parseInline(e)}parse(n,s=!0){let o="";for(let i=0;i<n.length;i++){var a=n[i];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[a.type]){const n=a,s=this.options.extensions.renderers[n.type].call({parser:this},n);if(!1!==s||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(n.type)){o+=s||"";continue}}switch(a.type){case"space":continue;case"hr":o+=this.renderer.hr();continue;case"heading":{const n=a;o+=this.renderer.heading(this.parseInline(n.tokens),n.depth,this.parseInline(n.tokens,this.textRenderer).replace(F,(e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""));continue}case"code":{const n=a;o+=this.renderer.code(n.text,n.lang,!!n.escaped);continue}case"table":{const n=a;let e="",t="";for(let e=0;e<n.header.length;e++)t+=this.renderer.tablecell(this.parseInline(n.header[e].tokens),{header:!0,align:n.align[e]});e+=this.renderer.tablerow(t);let i="";for(let e=0;e<n.rows.length;e++){const o=n.rows[e];t="";for(let e=0;e<o.length;e++)t+=this.renderer.tablecell(this.parseInline(o[e].tokens),{header:!1,align:n.align[e]});i+=this.renderer.tablerow(t)}o+=this.renderer.table(e,i);continue}case"blockquote":{const n=a,s=this.parse(n.tokens);o+=this.renderer.blockquote(s);continue}case"list":{const n=a,s=n.ordered,e=n.start,r=n.loose;let i="";for(let t=0;t<n.items.length;t++){const o=n.items[t],c=o.checked,u=o.task;let e="";if(o.task){const n=this.renderer.checkbox(!!c);r?0<o.tokens.length&&"paragraph"===o.tokens[0].type?(o.tokens[0].text=n+" "+o.tokens[0].text,o.tokens[0].tokens&&0<o.tokens[0].tokens.length&&"text"===o.tokens[0].tokens[0].type&&(o.tokens[0].tokens[0].text=n+" "+o.tokens[0].tokens[0].text)):o.tokens.unshift({type:"text",text:n+" "}):e+=n+" "}e+=this.parse(o.tokens,r),i+=this.renderer.listitem(e,u,!!c)}o+=this.renderer.list(i,s,e);continue}case"html":{const n=a;o+=this.renderer.html(n.text,n.block);continue}case"paragraph":{const n=a;o+=this.renderer.paragraph(this.parseInline(n.tokens));continue}case"text":{let e=a,t=e.tokens?this.parseInline(e.tokens):e.text;for(;i+1<n.length&&"text"===n[i+1].type;)e=n[++i],t+="\n"+(e.tokens?this.parseInline(e.tokens):e.text);o+=s?this.renderer.paragraph(t):t;continue}default:{const n='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(n),"";throw new Error(n)}}}return o}parseInline(t,i){i=i||this.renderer;let n="";for(let e=0;e<t.length;e++){var s=t[e];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[s.type]){const t=this.options.extensions.renderers[s.type].call({parser:this},s);if(!1!==t||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(s.type)){n+=t||"";continue}}switch(s.type){case"escape":{const t=s;n+=i.text(t.text);break}case"html":{const t=s;n+=i.html(t.text);break}case"link":{const t=s;n+=i.link(t.href,t.title,this.parseInline(t.tokens,i));break}case"image":{const t=s;n+=i.image(t.href,t.title,t.text);break}case"strong":{const t=s;n+=i.strong(this.parseInline(t.tokens,i));break}case"em":{const t=s;n+=i.em(this.parseInline(t.tokens,i));break}case"codespan":{const t=s;n+=i.codespan(t.text);break}case"br":n+=i.br();break;case"del":{const t=s;n+=i.del(this.parseInline(t.tokens,i));break}case"text":{const t=s;n+=i.text(t.text);break}default:{const t='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(t),"";throw new Error(t)}}}return n}}class N{options;constructor(e){this.options=e||t.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}}class ce{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#e(T.lex,D.parse);parseInline=this.#e(T.lexInline,D.parseInline);Parser=D;Renderer=A;TextRenderer=OLine truncated
|
||||
`},marked.setOptions({renderer:i,pedantic:!1,gfm:!0,breaks:!1,sanitize:!1,smartLists:!0,smartypants:!1,xhtml:!1,headerIds:!1,katex:katex}),t&&marked.use(baseUrl(t)),marked.use(markedKatex({throwOnError:!1})),marked.use(markedMermaid()),DOMPurify.sanitize(marked.parse(e,{renderer:i}))}
|
||||
@@ -24,8 +24,18 @@ function markedMermaid(options) {
|
||||
renderer(token) {
|
||||
const id = 'mermaid-' + Math.random().toString(36).substr(2, 9);
|
||||
|
||||
// Initialize Mermaid if not already done
|
||||
if (typeof mermaid !== 'undefined' && !window.mermaidInitialized) {
|
||||
// Create a div that will be processed by Mermaid
|
||||
const div = `<div class="mermaid" id="${id}">${token.text}</div>`;
|
||||
|
||||
// Trigger lazy-load of mermaid if not yet loaded
|
||||
if (typeof mermaid === 'undefined' && typeof window.loadMermaid === 'function') {
|
||||
window.loadMermaid();
|
||||
}
|
||||
|
||||
// Schedule Mermaid rendering for after DOM insertion
|
||||
setTimeout(() => {
|
||||
if (typeof mermaid === 'undefined') return;
|
||||
if (!window.mermaidInitialized) {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'default',
|
||||
@@ -33,13 +43,6 @@ function markedMermaid(options) {
|
||||
});
|
||||
window.mermaidInitialized = true;
|
||||
}
|
||||
|
||||
// Create a div that will be processed by Mermaid
|
||||
const div = `<div class="mermaid" id="${id}">${token.text}</div>`;
|
||||
|
||||
// Schedule Mermaid rendering for after DOM insertion
|
||||
setTimeout(() => {
|
||||
if (typeof mermaid !== 'undefined') {
|
||||
try {
|
||||
const element = document.getElementById(id);
|
||||
if (element && !element.getAttribute('data-processed')) {
|
||||
@@ -49,8 +52,7 @@ function markedMermaid(options) {
|
||||
} catch (error) {
|
||||
console.error('Mermaid rendering error:', error);
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
}, 100);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
function markedMermaid(e){return{extensions:[{name:"mermaid",level:"block",start(e){return e.match(/^```mermaid/m)?.index},tokenizer(e,t){e=/^```mermaid\n([\s\S]*?)\n```/.exec(e);if(e)return{type:"mermaid",raw:e[0],text:e[1].trim()}},renderer(e){const t="mermaid-"+Math.random().toString(36).substr(2,9);e=`<div class="mermaid" id="${t}">${e.text}</div>`;return"undefined"==typeof mermaid&&"function"==typeof window.loadMermaid&&window.loadMermaid(),setTimeout(()=>{if("undefined"!=typeof mermaid){window.mermaidInitialized||(mermaid.initialize({startOnLoad:!1,theme:"default",securityLevel:"loose"}),window.mermaidInitialized=!0);try{var e=document.getElementById(t);e&&!e.getAttribute("data-processed")&&(mermaid.init(void 0,e),e.setAttribute("data-processed","true"))}catch(e){console.error("Mermaid rendering error:",e)}}},100),e}}]}}"undefined"==typeof PDFJS&&(("undefined"!=typeof window?window:this).PDFJS={}),function(){function r(e,t){return new n(this.slice(e,t))}function s(e,t){arguments.length<2&&(t=0);for(var n=0,i=e.length;n<i;++n,++t)this[t]=255&e[n]}function n(e){if("number"==typeof e)for(var t=[],n=0;n<e;++n)t[n]=0;else if("slice"in e)t=e.slice(0);else{t=[];for(var n=0,i=e.length;n<i;++n)t[n]=e[n]}return t.subarray=r,(t.buffer=t).byteLength=t.length,t.set=s,"object"==typeof e&&e.buffer&&(t.buffer=e.buffer),t}"undefined"!=typeof Uint8Array?(void 0===Uint8Array.prototype.subarray&&(Uint8Array.prototype.subarray=function(e,t){return new Uint8Array(this.slice(e,t))},Float32Array.prototype.subarray=function(e,t){return new Float32Array(this.slice(e,t))}),"undefined"==typeof Float64Array&&(window.Float64Array=Float32Array)):(window.Uint8Array=n,window.Uint32Array=n,window.Int32Array=n,window.Uint16Array=n,window.Float32Array=n,window.Float64Array=n)}(),window.URL||(window.URL=window.webkitURL),void 0===Object.create&&(Object.create=function(e){function t(){}return t.prototype=e,new t}),function(){if(void 0!==Object.defineProperty){var t=!0;try{Object.defineProperty(new Image,"id",{value:"test"});function e(){}e.prototype={get id(){}},Object.defineProperty(new e,"id",{value:"",configurable:!0,enumerable:!0,writable:!1})}catch(e){t=!1}if(t)return}Object.defineProperty=function(e,t,n){delete e[t],"get"in n&&e.__defineGetter__(t,n.get),"set"in n&&e.__defineSetter__(t,n.set),"value"in n&&(e.__defineSetter__(t,function(e){return this.__defineGetter__(t,function(){return e}),e}),e[t]=n.value)}}(),void 0===Object.keys&&(Object.keys=function(e){var t,n=[];for(t in e)e.hasOwnProperty(t)&&n.push(t);return n}),function(){var e;"undefined"==typeof FileReader||"readAsArrayBuffer"in(e=FileReader.prototype)||Object.defineProperty(e,"readAsArrayBuffer",{value:function(e){var t=new FileReader,s=this;t.onload=function(e){e=e.target.result;for(var t=new ArrayBuffer(e.length),n=new Uint8Array(t),i=0,r=e.length;i<r;i++)n[i]=e.charCodeAt(i);Object.defineProperty(s,"result",{value:t,enumerable:!0,writable:!1,configurable:!0}),(e=document.createEvent("HTMLEvents")).initEvent("load",!1,!1),s.dispatchEvent(e)},t.readAsBinaryString(e)}})}(),function(){var e=XMLHttpRequest.prototype;"overrideMimeType"in e||Object.defineProperty(e,"overrideMimeType",{value:function(){}}),"response"in e||"mozResponseArrayBuffer"in e||"mozResponse"in e||"responseArrayBuffer"in e||("undefined"!=typeof VBArray?Object.defineProperty(e,"response",{get:function(){return new Uint8Array(new VBArray(this.responseBody).toArray())}}):("function"==typeof e.overrideMimeType&&Object.defineProperty(e,"responseType",{set:function(){this.overrideMimeType("text/plain; charset=x-user-defined")}}),Object.defineProperty(e,"response",{get:function(){for(var e=this.responseText,t=e.length,n=new Uint8Array(t),i=0;i<t;++i)n[i]=255&e.charCodeAt(i);return n}})))}(),"btoa"in window||(window.btoa=function(e){for(var t="",n=0,i=e.length;n<i;n+=3)var r=255&e.charCodeAt(n),s=255&e.charCodeAt(n+1),o=255&e.charCodeAt(n+2),a=(3&r)<<4|s>>4,s=n+1<i?(15&s)<<2|o>>6:64,o=n+2<i?63&o:64,t=t+("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(r>>2)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(a)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(s)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(o));return t}),"atob"in window||(window.atob=function(e){if(1==(e=e.replace(/=+$/,"")).length%4)throw Error("bad atob input");for(var t,n,i=0,r=0,s="";n=e.charAt(r++);~n&&(t=i%4?64*t+n:n,i++%4)&&(s+=String.fromCharCode(255&t>>(-2*i&6))))n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(n);return s}),void 0===Function.prototype.bind&&(Function.prototype.bind=function(t){var n=this,i=Array.prototype.slice.call(arguments,1);return function(){var e=Array.prototype.concat.apply(i,arguments);return n.apply(t,e)}}),"dataset"in document.createElement("div")||Object.defineProperty(HTMLElement.prototype,"dataset",{get:function(){if(this._dataset)return this._dataset;for(var e={},t=0,n=tLine truncated
|
||||
@@ -3,7 +3,7 @@ dotenv();
|
||||
|
||||
import { createClient } from "redis";
|
||||
import { resolve, join } from "path";
|
||||
import { existsSync } from "fs";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import rateLimit from "express-rate-limit";
|
||||
import { slowDown } from "express-slow-down";
|
||||
import RedisStore from "rate-limit-redis";
|
||||
@@ -31,6 +31,40 @@ import { createLogger, serializeError } from "../core/logger";
|
||||
|
||||
const logger = createLogger("server");
|
||||
|
||||
// Lazily build the templated index.html on first request so the server
|
||||
// works even when started before `gulp` finishes.
|
||||
const indexHtmlPath = resolve("public", "index.html");
|
||||
const manifestPath = resolve("public", "asset-manifest.json");
|
||||
let indexHtmlCache: string | null = null;
|
||||
|
||||
function getIndexHtml(): string {
|
||||
if (indexHtmlCache) return indexHtmlCache;
|
||||
|
||||
let assetManifest: Record<string, string> = {};
|
||||
if (existsSync(manifestPath)) {
|
||||
try {
|
||||
assetManifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
||||
} catch {
|
||||
// manifest missing or malformed — fall back to unhashed names
|
||||
}
|
||||
}
|
||||
function asset(name: string): string {
|
||||
return assetManifest[name] || name;
|
||||
}
|
||||
|
||||
let html = existsSync(indexHtmlPath)
|
||||
? readFileSync(indexHtmlPath, "utf-8")
|
||||
: "";
|
||||
|
||||
html = html
|
||||
.replace("__CORE_JS__", asset("core.min.js"))
|
||||
.replace("__VENDOR_JS__", asset("vendor.min.js"))
|
||||
.replace("__MERMAID_JS__", asset("mermaid.min.js"))
|
||||
.replace("__ALL_CSS__", asset("all.min.css"));
|
||||
indexHtmlCache = html;
|
||||
return html;
|
||||
}
|
||||
|
||||
function indexResponse(req: express.Request, res: express.Response) {
|
||||
if (
|
||||
req.path.startsWith("/script") ||
|
||||
@@ -46,14 +80,13 @@ function indexResponse(req: express.Request, res: express.Response) {
|
||||
req.headers["accept"].indexOf("text/html") == -1
|
||||
) {
|
||||
const repoId = req.path.split("/")[2];
|
||||
// if it is not an html request, it assumes that the browser try to load a different type of resource
|
||||
return res.redirect(
|
||||
`/api/repo/${repoId}/file/${req.path.substring(
|
||||
req.path.indexOf(repoId) + repoId.length + 1
|
||||
)}`
|
||||
);
|
||||
}
|
||||
res.sendFile(resolve("public", "index.html"));
|
||||
res.type("html").send(getIndexHtml());
|
||||
}
|
||||
|
||||
export default async function start() {
|
||||
@@ -243,11 +276,27 @@ export default async function start() {
|
||||
// web view
|
||||
app.use("/w/", rate, webViewSpeedLimiter, router.webview);
|
||||
|
||||
// Hashed assets (e.g. core.a1b2c3d4e5.min.js) — immutable, cache for 1 year.
|
||||
// Strip the hash from the filename and serve the underlying file.
|
||||
app.get(
|
||||
/^\/(script|css)\/(.+)\.([a-f0-9]{10})\.(min\.\w+|\w+)$/,
|
||||
(req, res, next) => {
|
||||
const dir = req.params[0]; // "script" or "css"
|
||||
const base = req.params[1]; // e.g. "core"
|
||||
const ext = req.params[3]; // e.g. "min.js"
|
||||
const filePath = join("public", dir, `${base}.${ext}`);
|
||||
if (!existsSync(filePath)) return next();
|
||||
res.set("Cache-Control", "public, max-age=31536000, immutable");
|
||||
res.sendFile(resolve(filePath));
|
||||
}
|
||||
);
|
||||
|
||||
app.use(
|
||||
express.static(join("public"), {
|
||||
etag: true,
|
||||
lastModified: true,
|
||||
maxAge: 3600, // 1h
|
||||
maxAge: 86400000, // 1 day (fonts, images, partials)
|
||||
index: false, // don't serve index.html for "/" — indexResponse handles it
|
||||
})
|
||||
);
|
||||
|
||||
|
||||