Split app.js into one script per feature; versioning covers every public file; README for the new features
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c1f4a220f9
commit
1564941ea5
20 files changed
+2297
-2275
No files matched your search
@@ -18,7 +18,7 @@ const lrcLib = require('../lyrics');
|
||||
ok('word timing inside a line is read', l[1].words && l[1].words.length === 2 && l[1].words[0].t === 14000 && l[1].words[1].t === 14800 && l[1].text === 'Second line', l[1]);
|
||||
ok('a line that repeats (two times) appears twice, in order', l[2].text === 'Chorus' && l[3].text === 'Chorus' && l[3].t === 30250, l.slice(2));
|
||||
const client = (() => { // the same reader in the app itself must agree
|
||||
const src = fs.readFileSync(path.join(root, 'public', 'app.js'), 'utf8'), a = src.indexOf('function lyrParseLrc'), b = src.indexOf('\n}\n', a) + 3;
|
||||
const src = fs.readFileSync(path.join(root, 'public', 'lyrics-view.js'), 'utf8'), a = src.indexOf('function lyrParseLrc'), b = src.indexOf('\n}\n', a) + 3;
|
||||
return new Function(src.slice(a, b) + '; return lyrParseLrc;')();
|
||||
})();
|
||||
ok('and the app reads it the same way', JSON.stringify(client('[ti:x]\n[00:10.50]Hello there\n[00:14.00]<00:14.00>Second <00:14.80>line\n[00:20.00][00:30.25]Chorus\n')) === JSON.stringify(l));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const fs=require('fs'), vm=require('vm');
|
||||
const src=fs.readFileSync(''+require('path').join(__dirname,'..','public','app.js')+'','utf8');
|
||||
const a=src.indexOf("const shuffled = a =>"), b=src.indexOf("// ---- People (admin)");
|
||||
const src=['music.js','player.js','lyrics-view.js'].map(f=>fs.readFileSync(require('path').join(__dirname,'..','public',f),'utf8')).join('\n');
|
||||
const a=src.indexOf("const shuffled = a =>"), b=src.length;
|
||||
let code=src.slice(a,b);
|
||||
const listeners={};
|
||||
class FakeAudio{constructor(){this.paused=true;this.currentTime=0;this.duration=100;this.readyState=4;this.error=null;this._l={};this.src='';}
|
||||
@@ -8,7 +8,7 @@ class FakeAudio{constructor(){this.paused=true;this.currentTime=0;this.duration=
|
||||
play(){this.paused=false;this.fire('play');return Promise.resolve()} pause(){if(!this.paused){this.paused=true;this.fire('pause')}} getAttribute(){return this.src||null} load(){}}
|
||||
const toasts=[];const store={d:{},get(k,d){return this.d[k]??d},set(k,v){this.d[k]=v},del(k){delete this.d[k]}};
|
||||
const el=()=>({remove(){},classList:{toggle(){},add(){}},setAttribute(){},dataset:{},style:{},querySelector:()=>el(),querySelectorAll:()=>[],set innerHTML(v){},set textContent(v){}});
|
||||
const ctx={Audio:FakeAudio,store,toast:m=>toasts.push(m),px:{art:()=>'x'},icon:()=>'',esc:s=>s,fmtDur:()=>'',$:()=>el(),document:{querySelectorAll:()=>[],querySelector:()=>null},allowed:()=>true,
|
||||
const ctx={sleepT:{eot:false},sleepClear(){},Audio:FakeAudio,store,toast:m=>toasts.push(m),px:{art:()=>'x'},icon:()=>'',esc:s=>s,fmtDur:()=>'',$:()=>el(),document:{querySelectorAll:()=>[],querySelector:()=>null},allowed:()=>true,
|
||||
navigator:{onLine:true},addEventListener:(e,f)=>{listeners[e]=f},setTimeout,clearTimeout,fetch:()=>new Promise(()=>{}),URL:{createObjectURL:()=>'blob:x',revokeObjectURL(){}},
|
||||
Image:class{},MediaMetadata:class{},openSheet:()=>({}),closeSheet(){},actionSheet(){},Response,URLSearchParams,AbortController,Promise,Set,Map,Date,Math,saveStateHook:0,location:{hash:'#/tasks'}};
|
||||
vm.createContext(ctx); vm.runInContext(code+";this.pl=pl;this.next=next;this.prev=prev;this.setShuffle=setShuffle;this.setRepeat=setRepeat;this.playQueue=playQueue;this.advance=advance;this.cur=cur;this.recover=recover;this.srcOf=srcOf;",ctx);
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ const wait = ms => new Promise(r => setTimeout(r, ms));
|
||||
const home = await (await fetch(base + '/', { headers: { cookie } })).text(), cfg2 = await (await fetch(base + '/api/config', { headers: { cookie } })).json();
|
||||
ok('the app page links its code with the current build number, so a cached old copy can never be used', home.includes(`/app.js?v=${cfg2.build}`) && home.includes(`/style.css?v=${cfg2.build}`), home.match(/app\.js[^"]*/));
|
||||
const login = await (await fetch(base + '/login')).text(); ok('so does the sign-in page', login.includes(`/login.js?v=${cfg2.build}`), login.match(/login\.js[^"]*/));
|
||||
const va = await fetch(base + `/app.js?v=${cfg2.build}`, { headers: { cookie } }); ok('the versioned address serves the file', va.status === 200 && (await va.text()).includes('addPersonSheet'), va.status);
|
||||
const va = await fetch(base + `/app.js?v=${cfg2.build}`, { headers: { cookie } }); ok('the versioned address serves the file', va.status === 200 && (await va.text()).includes('routesOf'), va.status);
|
||||
// hardening: headers, cross-site writes, health check, backup, links setting
|
||||
const h1 = await fetch(base + '/login'); await h1.text();
|
||||
ok('responses carry security headers', h1.headers.get('x-content-type-options') === 'nosniff' && /frame-ancestors 'self'/.test(h1.headers.get('content-security-policy') || ''), [...h1.headers]);
|
||||
|
||||
Reference in new issue
Block a user