book-index-ui 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +757 -760
- package/dist/{storage-entry-sPrgfaS5.cjs → storage-entry-QB1IoDUU.cjs} +1 -1
- package/dist/{storage-entry-CWocbrbM.js → storage-entry-UQLfmeLb.js} +250 -221
- package/dist/storage.cjs +1 -1
- package/dist/storage.d.ts +4 -0
- package/dist/storage.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ut=Object.create;var V=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var yt=Object.getPrototypeOf,gt=Object.prototype.hasOwnProperty;var pt=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ft(t))!gt.call(r,n)&&n!==e&&V(r,n,{get:()=>t[n],enumerable:!(s=dt(t,n))||s.enumerable});return r};var X=(r,t,e)=>(e=r!=null?ut(yt(r)):{},pt(t||!r||!r.__esModule?V(e,"default",{value:r,enumerable:!0}):e,r));const mt={official:0,draft:1},wt={0:"official",1:"draft"},_t={book:0,collection:2,work:3,entity:4},bt={0:"book",2:"collection",3:"work",4:"entity"},st=62n,nt=59n,it=19n,ot=8n,rt=(1n<<40n)-1n,kt=(1n<<3n)-1n,It=(1n<<11n)-1n,St=(1n<<8n)-1n,D="0123456789abcdefghijklmnopqrstuvwxyz",at=new Map;for(let r=0;r<D.length;r++)at.set(D[r],BigInt(r));function M(r){if(r===0n)return D[0];let t="";for(;r>0n;)t=D[Number(r%36n)]+t,r=r/36n;return t}function G(r){let t=0n;for(const e of r){const s=at.get(e);if(s===void 0)throw new Error(`Invalid Base36 character: ${e}`);t=t*36n+s}return t}const Q="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",ct=new Map;for(let r=0;r<Q.length;r++)ct.set(Q[r],BigInt(r));function lt(r){let t=0n;for(const e of r){const s=ct.get(e);if(s===void 0)throw new Error(`Invalid Base58 character: ${e}`);t=t*58n+s}return t}function k(r){return/[A-Z]/.test(r)?lt(r):G(r)}const xt=M,vt=G;function C(r){const t=Number(r>>st&1n),e=Number(r>>nt&kt),s=r>>it&rt,n=Number(r>>ot&It),i=Number(r&St);return{status:wt[t]??"draft",type:bt[e]??"book",timestamp:s,machineId:n,sequence:i}}function W(r,t,e,s,n){return BigInt(mt[r])<<st|BigInt(_t[t])<<nt|(e&rt)<<it|BigInt(s)<<ot|BigInt(n)}function P(r){return C(k(r))}function Et(r){return P(r).type}function Ct(r){return P(r).status}const N={book:"Book",collection:"Collection",work:"Work",entity:"Entity"},$t={Book:"book",Collection:"collection",Work:"work",Entity:"entity"},B=16;function J(r,t=B){let e=0;for(let s=0;s<r.length;s++)e=Math.imul(e,31)+r.charCodeAt(s)>>>0;return e%t}function b(...r){const t=r.join("/");return t.startsWith("//")?"//"+t.slice(2).replace(/\/+/g,"/"):t.replace(/\/+/g,"/")}function At(r){return r.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g,"")||"Undefined"}class q{constructor(t,e){this.fs=t,this.officialRoot=b(e,"book-index"),this.draftRoot=b(e,"book-index-draft")}getRootByStatus(t){return t==="draft"?this.draftRoot:this.officialRoot}getRootById(t){const e=k(t),s=C(e);return this.getRootByStatus(s.status)}getPath(t,e,s){const n=this.getRootById(e),i=e.padEnd(3,"_").substring(0,3),[o,c,l]=[i[0],i[1],i[2]],a=N[t];return b(n,a,o,c,l,`${e}-${At(s)}.json`)}async saveItem(t,e,s){const n=s.title||s.书名||"未命名",i=s.edition||"",o=i?`${n}${i}`:n,c=this.getPath(t,e,o),l=await this.findFileById(e);if(l&&l!==c)try{await this.fs.deleteFile(l)}catch{}const a=c.substring(0,c.lastIndexOf("/"));await this.fs.mkdir(a),s.id=e,s.type=t,await this.fs.writeFile(c,JSON.stringify(s,Lt,2));const h=this.getRootById(e),u=c.substring(h.length+1);return await this.updateIndexEntry(h,s,t,u),c}async updateIndexEntry(t,e,s,n){const i=e.id||"";if(!i)return;const o=`${s}s`,c=await this.loadShard(t,o,i);let l="";const a=e.authors;if(Array.isArray(a)&&a.length>0){const y=a[0];l=typeof y=="object"&&y!==null?y.name||"":String(y)}else typeof a=="string"&&(l=a);let h="";const u=e.publication_info;typeof u=="object"&&u!==null?h=u.year||"":typeof u=="string"&&(h=u);let d="";const f=e.current_location;typeof f=="object"&&f!==null?d=f.name||"":typeof f=="string"&&(d=f);const p=Array.isArray(e.additional_titles)?e.additional_titles.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0,I=Array.isArray(e.attached_texts)?e.attached_texts.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0;let v;const S=e.juan_count;typeof S=="number"?v=S:typeof S=="object"&&S!==null&&(v=S.number||void 0);const A=typeof e.measure_info=="string"?e.measure_info:"";let E=!1,x=!1;const j=e.resources;if(Array.isArray(j))for(const y of j){if(typeof y!="object"||y===null)continue;const w=y.types;if(Array.isArray(w))w.includes("text")&&(E=!0),w.includes("image")&&(x=!0);else{const $=y.type;($==="text"||$==="text+image")&&(E=!0),($==="image"||$==="text+image")&&(x=!0)}}const m={id:i,title:e.title||"未命名",type:N[s],path:n,author:l,year:h,holder:d};p&&p.length>0&&(m.additional_titles=p),I&&I.length>0&&(m.attached_texts=I),v&&(m.juan_count=v),A&&(m.measure_info=A);const L=typeof e.edition=="string"?e.edition:"";L&&(m.edition=L),E&&(m.has_text=!0),x&&(m.has_image=!0),c[i]=m,await this.saveShard(t,o,i,c)}async deleteItem(t){const e=await this.findFileById(t);if(!e)return!1;const s=k(t),n=C(s),i=this.getRootByStatus(n.status),o=`${n.type}s`,c=await this.loadShard(i,o,t);return c[t]&&(delete c[t],await this.saveShard(i,o,t,c)),await this.fs.deleteFile(e),!0}async findFileById(t){const e=t.padEnd(3,"_").substring(0,3),[s,n,i]=[e[0],e[1],e[2]];for(const o of[this.officialRoot,this.draftRoot])for(const c of["Book","Collection","Work"]){const l=b(o,c,s,n,i);if(await this.fs.exists(l))try{const h=(await this.fs.readdir(l)).find(u=>u.startsWith(`${t}-`)&&u.endsWith(".json"));if(h)return b(l,h)}catch{}}return null}async loadMetadata(t){try{const e=await this.fs.readFile(t);return JSON.parse(e)}catch{return{}}}async getItem(t){const e=await this.findFileById(t);if(!e)return null;const s=await this.loadMetadata(e);return Object.keys(s).length>0?s:null}async loadEntries(t,e){const s=e?[this.getRootByStatus(e)]:[this.officialRoot,this.draftRoot],n=[],i=`${t}s`;for(const o of s){const c=await this.loadAllShards(o,i);for(const[l,a]of Object.entries(c))n.push({id:l,title:a.title,type:t,author:a.author||void 0,dynasty:a.dynasty||void 0,role:a.role||void 0,path:b(o,a.path),additional_titles:a.additional_titles,attached_texts:a.attached_texts,edition:a.edition,juan_count:a.juan_count,has_text:a.has_text,has_image:a.has_image})}return n}async searchEntries(t,e,s){const n=await this.loadEntries(e,s);return F(n,t)}async searchAll(t,e=5,s){const n=["work","book","collection"],i=await Promise.all(n.map(o=>this.searchEntries(t,o,s)));return{works:i[0].slice(0,e),books:i[1].slice(0,e),collections:i[2].slice(0,e),totalWorks:i[0].length,totalBooks:i[1].length,totalCollections:i[2].length}}async rebuildIndex(t){var n,i;const e=this.getRootByStatus(t),s={books:Object.fromEntries(Array.from({length:B},(o,c)=>[c,{}])),collections:{0:{}},works:Object.fromEntries(Array.from({length:B},(o,c)=>[c,{}]))};for(const o of["Book","Collection","Work"]){const c=b(e,o);if(!await this.fs.exists(c))continue;const a=`${$t[o]}s`,h=await this.fs.glob(c,"**/*.json");for(const u of h)if(!u.includes("/index/"))try{const d=await this.loadMetadata(u);let f=d.id||d.ID||"";if(!f){const g=u.substring(u.lastIndexOf("/")+1);g.includes("-")&&(f=g.split("-")[0])}if(!f)continue;const p=u.substring(e.length+1);let I="";const v=d.authors;if(Array.isArray(v)&&v.length>0){const g=v[0];I=typeof g=="object"&&g!==null?g.name||"":String(g)}const S=Array.isArray(d.additional_titles)?d.additional_titles.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0,A=Array.isArray(d.attached_texts)?d.attached_texts.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0;let E;const x=d.juan_count;typeof x=="number"?E=x:typeof x=="object"&&x!==null&&(E=x.number||void 0);const j=typeof d.measure_info=="string"?d.measure_info:"";let m=!1,L=!1;const y=d.resources;if(Array.isArray(y))for(const g of y){if(typeof g!="object"||g===null)continue;const U=g.types;if(Array.isArray(U))U.includes("text")&&(m=!0),U.includes("image")&&(L=!0);else{const R=g.type;(R==="text"||R==="text+image")&&(m=!0),(R==="image"||R==="text+image")&&(L=!0)}}const w={id:f,title:d.title||"未命名",type:o,path:p,author:I,year:typeof d.publication_info=="object"&&((n=d.publication_info)==null?void 0:n.year)||"",holder:typeof d.current_location=="object"&&((i=d.current_location)==null?void 0:i.name)||""};S&&S.length>0&&(w.additional_titles=S),A&&A.length>0&&(w.attached_texts=A),E&&(w.juan_count=E),j&&(w.measure_info=j);const $=typeof d.edition=="string"?d.edition:"";$&&(w.edition=$),m&&(w.has_text=!0),L&&(w.has_image=!0);const ht=a==="collections"?0:J(f);s[a][ht][f]=w}catch{}}for(const[o,c]of Object.entries(s))for(const[l,a]of Object.entries(c)){const h=this.shardPath(e,o,Number(l)),u=h.substring(0,h.lastIndexOf("/"));await this.fs.mkdir(u),await this.fs.writeFile(h,JSON.stringify(a,null,2))}}getAssetDir(t){const e=this.getRootById(t),s=k(t),i=C(s).type,o=t.padEnd(3,"_").substring(0,3),[c,l,a]=[o[0],o[1],o[2]],h=N[i];return b(e,h,c,l,a,t)}async initAssetDir(t){const e=this.getAssetDir(t);return await this.fs.mkdir(e),e}async hasAssetDir(t){const e=this.getAssetDir(t);return this.fs.exists(e)}shardPath(t,e,s){return e==="collections"?b(t,"index","collections.json"):b(t,"index",e,`${s.toString(16)}.json`)}async loadShard(t,e,s){const n=J(s),i=this.shardPath(t,e,n);try{if(!await this.fs.exists(i))return{};const o=await this.fs.readFile(i);return JSON.parse(o)}catch{return{}}}async saveShard(t,e,s,n){const i=J(s),o=this.shardPath(t,e,i),c=o.substring(0,o.lastIndexOf("/"));await this.fs.mkdir(c),await this.fs.writeFile(o,JSON.stringify(n,null,2))}async loadAllShards(t,e){const s={};if(e==="collections"){const n=this.shardPath(t,e,0);try{if(await this.fs.exists(n)){const i=await this.fs.readFile(n);Object.assign(s,JSON.parse(i))}}catch{}return s}for(let n=0;n<B;n++){const i=this.shardPath(t,e,n);try{if(await this.fs.exists(i)){const o=await this.fs.readFile(i);Object.assign(s,JSON.parse(o))}}catch{}}return s}}function z(r,t){const e=t.toLowerCase();let s=0;const n=r.title.toLowerCase();n===e?s=200:n.startsWith(e)?s=150:n.includes(e)&&(s=100);const i=[...r.additional_titles||[],...r.attached_texts||[]];for(const a of i){const h=a.toLowerCase();h===e?s=Math.max(s,120):h.startsWith(e)?s=Math.max(s,90):h.includes(e)&&(s=Math.max(s,60))}let o=0;if(r.author){const a=r.author.toLowerCase();a===e?o=80:a.includes(e)&&(o=50)}let c=0;r.dynasty&&r.dynasty.toLowerCase().includes(e)&&(c=30);let l=s;return l===0&&(l=Math.max(o,c)),l===0?0:(l+=Math.max(0,20-n.length),r.type==="work"?l=Math.round(l*1.05):r.type==="collection"&&(l=Math.round(l*1.02)),r.has_text&&(l+=3),r.has_image&&(l+=2),l)}function Lt(r,t){return t===null?void 0:t}function F(r,t){const e=r.map(s=>({entry:s,score:z(s,t)})).filter(s=>s.score>0);return e.sort((s,n)=>n.score!==s.score?n.score-s.score:s.entry.title.length-n.entry.title.length),e.map(s=>s.entry)}function O(r,t,e,s){const n=r.map(i=>{const o=z(i,t);let c=0;const l=s[i.id];if(l&&e){const a={...i,title:l.t??i.title,author:l.a??i.author,additional_titles:l.at??i.additional_titles,attached_texts:l.axt??i.attached_texts};c=z(a,e)}return{entry:i,score:Math.max(o,c)}}).filter(i=>i.score>0);return n.sort((i,o)=>o.score!==i.score?o.score-i.score:i.entry.title.length-o.entry.title.length),n.map(i=>i.entry)}function Pt(r){const t=r.volumes??[];let e,s;if(t.length===0)e=[];else if(typeof t[0]=="number")e=t;else{s=[],e=[];for(const i of t){const o=i.volume;e.push(o);const c={};for(const[l,a]of Object.entries(i))l==="volume"||l==="status"||l==="file"||typeof a=="string"&&(l.includes("url")||l.includes("id"))&&(c[l]=a);s.push({volume:o,status:i.status,urls:Object.keys(c).length>0?c:void 0,file:i.file})}}const n={title:r.title??"",book_id:r.book_id??null,work_id:r.work_id??null,volumes:e,section:r.section,sub_items:r.sub_items,edition:r.edition,expected_volumes:r.expected_volumes,found_volumes:r.found_volumes,missing_volumes:r.missing_vols??r.missing_volumes};s&&(n.volume_details=s);for(const i of Object.keys(n))n[i]===void 0&&delete n[i];return n}function Tt(r){const t={total_books:r.total_books??0};return r.processed_volumes!=null&&(t.processed_volumes=r.processed_volumes),r.matched_works!=null&&(t.matched_works=r.matched_works),r.unmatched_works!=null&&(t.unmatched_works=r.unmatched_works),r.total_found_volumes!=null&&(t.total_found_volumes=r.total_found_volumes),t}function Y(r){var n;const t=r,e=(t.books??[]).map(Pt),s={collection_id:t.collection_id??"",title:t.title??"",total_volumes:t.total_volumes??0,stats:Tt(t.stats??{}),books:e};return t.source&&(s.source=t.source),t.resource_id&&(s.resource_id=t.resource_id),t.resource_name&&(s.resource_name=t.resource_name),(n=t.sections)!=null&&n.length&&(s.sections=t.sections),t.volume_index&&Object.keys(t.volume_index).length>0&&(s.volume_index=t.volume_index),s}const jt="https://raw.githubusercontent.com",Bt=["https://fastly.jsdelivr.net/gh","https://cdn.jsdelivr.net/gh"],Ft=5e3;class Mt{constructor(t){this.cache=null,this.cacheLoading=null,this.pathMap=new Map,this.searchSCache=null,this.t2sConverter=null,this.config={org:t.org,repos:t.repos,baseUrl:t.baseUrl??jt,cdnUrls:t.cdnUrls??Bt,timeout:t.timeout??Ft}}async ensureLoaded(){if(this.cache)return this.cache;if(this.cacheLoading)return this.cacheLoading;this.cacheLoading=(async()=>{const t=[];for(const s of[!0,!1])try{const n=s?this.config.repos.draft:this.config.repos.official,i=await this.fetchIndex(n),o=this.parseIndexResponse(i,s);t.push(...o)}catch(n){console.warn(`Failed to fetch ${s?"draft":"official"} index:`,n)}const e=new Map;for(const s of t)e.set(s.id,s);return this.cache=Array.from(e.values()),this.cache})();try{return await this.cacheLoading}finally{this.cache||(this.cacheLoading=null)}}async fetchFileWithFallback(t,e){const s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{return await this.fetchJson(s)}catch{}for(const n of this.config.cdnUrls){const i=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(i)}catch{continue}}throw new Error(`Failed to fetch ${e} for ${t} from all sources`)}async probeIndex(t){const e="index/collections.json",s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{if((await fetch(s,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{}for(const o of this.config.cdnUrls){const c=`${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{if((await fetch(c,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{continue}}const n="index/works/0.json",i=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(n)}`;try{if((await fetch(i,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{}for(const o of this.config.cdnUrls){const c=`${o}/${this.config.org}/${t}@main/${encodeURI(n)}`;try{if((await fetch(c,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{continue}}return!1}async fetchIndex(t){if(!await this.probeIndex(t))return{books:{},collections:{},works:{}};const s={books:{},collections:{},works:{}};try{const i=await this.fetchFileWithFallback(t,"index/collections.json");s.collections=i}catch{}const n=[];for(const i of["books","works"])for(let o=0;o<B;o++){const c=`index/${i}/${o.toString(16)}.json`;n.push(this.fetchFileWithFallback(t,c).then(l=>{Object.assign(s[i],l)}).catch(()=>{}))}return await Promise.all(n),s}async fetchJson(t){const e=await fetch(t,{cache:"no-store",signal:AbortSignal.timeout(this.config.timeout)});if(!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);return e.json()}parseIndexResponse(t,e){var i,o;const s=[],n=[["books","book"],["collections","collection"],["works","work"],["entities","entity"]];for(const[c,l]of n){const a=t[c];if(a)for(const h of Object.values(a)){const u=h,d=l==="entity"?u.primary_name||h.title||h.name||h.id:h.title||h.name||h.id;s.push({id:h.id,title:d,type:l,isDraft:e,author:h.author,dynasty:h.dynasty,role:h.role,path:h.path,additional_titles:(i=u.additional_titles)==null?void 0:i.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),attached_texts:(o=u.attached_texts)==null?void 0:o.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),edition:u.edition,juan_count:u.juan_count,has_text:u.has_text,has_image:u.has_image,has_collated:u.has_collated,subtype:u.subtype,primary_name:u.primary_name,birth_year:u.birth_year,death_year:u.death_year,cbdb_id:u.cbdb_id}),this.pathMap.set(h.id,{path:h.path,isDraft:e})}}return s}async ensureSearchSBuilt(){var n,i;if(this.searchSCache)return{searchS:this.searchSCache,converter:this.t2sConverter||null};if(this.t2sConverter===!1)return{searchS:{},converter:null};try{const o=await import("opencc-js");this.t2sConverter=o.Converter({from:"tw",to:"cn"})}catch{return this.t2sConverter=!1,this.searchSCache={},{searchS:{},converter:null}}const t=await this.ensureLoaded(),e=this.t2sConverter,s={};for(const o of t){const c={},l=e(o.title);if(l!==o.title&&(c.t=l),o.author){const a=e(o.author);a!==o.author&&(c.a=a)}if((n=o.additional_titles)!=null&&n.length){const a=o.additional_titles.map(e);a.some((h,u)=>h!==o.additional_titles[u])&&(c.at=a)}if((i=o.attached_texts)!=null&&i.length){const a=o.attached_texts.map(e);a.some((h,u)=>h!==o.attached_texts[u])&&(c.axt=a)}Object.keys(c).length>0&&(s[o.id]=c)}return this.searchSCache=s,{searchS:s,converter:e}}async loadEntries(t,e){let n=(await this.ensureLoaded()).filter(u=>u.type===t);const i=e.sortBy||"title",o=e.sortOrder||"asc";n.sort((u,d)=>{const f=String(u[i]??""),p=String(d[i]??""),I=f.localeCompare(p,"zh");return o==="asc"?I:-I});const c=e.page||1,l=e.pageSize||50,a=(c-1)*l;return{entries:n.slice(a,a+l),total:n.length,page:c,pageSize:l}}async search(t,e,s){const n=await this.ensureLoaded(),{searchS:i,converter:o}=await this.ensureSearchSBuilt(),c=n.filter(p=>p.type===e),l=o?o(t):void 0,h=Object.keys(i).length>0?O(c,t,l,i):F(c,t),u=s.page||1,d=s.pageSize||50,f=(u-1)*d;return{entries:h.slice(f,f+d),total:h.length,page:u,pageSize:d}}async searchAll(t,e=5){const s=await this.ensureLoaded(),{searchS:n,converter:i}=await this.ensureSearchSBuilt(),o=["work","book","collection"],c=i?i(t):void 0,l=Object.keys(n).length>0,a=o.map(h=>{const u=s.filter(d=>d.type===h);return l?O(u,t,c,n):F(u,t)});return{works:a[0].slice(0,e),books:a[1].slice(0,e),collections:a[2].slice(0,e),totalWorks:a[0].length,totalBooks:a[1].length,totalCollections:a[2].length}}async getItem(t){const e=await this.ensureLoaded(),s=this.pathMap.get(t);let n=null;if(s){const i=s.isDraft?this.config.repos.draft:this.config.repos.official;if(n=await this.fetchItemByPath(i,s.path),n){const o=e.find(c=>c.id===t);o!=null&&o.has_collated&&(n.has_collated=!0)}}else n=await this.findItemById(t);return n&&n.type==="entity"&&!n.title&&n.primary_name&&(n.title=n.primary_name),n}async getEntry(t){const s=(await this.ensureLoaded()).find(i=>i.id===t);if(s)return s;const n=await this.findItemById(t);return n?this.buildEntryFromItem(t,n):null}async getAllEntries(){return this.ensureLoaded()}async saveItem(){throw new Error("GithubStorage 为只读模式,不支持保存")}async deleteItem(){throw new Error("GithubStorage 为只读模式,不支持删除")}async generateId(){throw new Error("GithubStorage 为只读模式,不支持生成 ID")}async fetchItemByPath(t,e){let s=null;const n=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{s=await this.fetchJson(n)}catch{}if(!s)for(const i of this.config.cdnUrls){const o=`${i}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{s=await this.fetchJson(o);break}catch{continue}}return s}async findItemById(t){const e={book:"Book",collection:"Collection",work:"Work",entity:"Entity"};let s,n;try{const h=C(k(t));s=h.type,n=h.status}catch{return null}const i=n==="draft"?this.config.repos.draft:this.config.repos.official,o=e[s],c=t.padEnd(3,"_").substring(0,3),l=`${o}/${c[0]}/${c[1]}/${c[2]}`,a=`https://api.github.com/repos/${this.config.org}/${i}/contents/${l}`;try{const h=await fetch(a,{signal:AbortSignal.timeout(this.config.timeout)});if(!h.ok)return null;const d=(await h.json()).find(p=>p.name.startsWith(`${t}-`)&&p.name.endsWith(".json"));if(!d)return null;const f=await this.fetchItemByPath(i,d.path);return f&&this.pathMap.set(t,{path:d.path,isDraft:n==="draft"}),f}catch{return null}}buildEntryFromItem(t,e){const s=(e.type||"").toLowerCase(),n=s==="work"?"work":s==="collection"?"collection":"book";let i;const o=e.authors;if(Array.isArray(o)&&o.length>0){const a=o[0];i=typeof a=="object"&&a!==null?a.name||"":String(a)}let c=!0;try{c=C(k(t)).status==="draft"}catch{}const l=this.pathMap.get(t);return{id:t,title:e.title||e.书名||t,type:n,isDraft:c,author:i,dynasty:e.dynasty,role:e.role,path:(l==null?void 0:l.path)||"",juan_count:e.n_juan,has_collated:e.has_collated}}async fetchFile(t,e){const s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{return await this.fetchJson(s)}catch{}for(const n of this.config.cdnUrls){const i=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(i)}catch{continue}}return null}async resolveItemPath(t){await this.ensureLoaded();let e=this.pathMap.get(t);if(!e&&(await this.findItemById(t),e=this.pathMap.get(t),!e))return null;const s=e.isDraft?this.config.repos.draft:this.config.repos.official,n=e.path.substring(0,e.path.lastIndexOf("/"));return{repo:s,dir:n}}async getCollectionCatalogs(t){const e=await this.resolveItemPath(t);if(!e)return null;const s=await this.getItem(t);if(!s)return null;const n=s.resources||[];if(n.length===0)return null;const i=[];for(const o of n){const c=`${e.dir}/${t}/${o.id}/volume_book_mapping.json`,l=await this.fetchFile(e.repo,c);l&&i.push({resource_id:o.id,short_name:o.short_name,data:Y(l)})}return i.length>0?i:null}async getCollectionCatalog(t){var s;const e=await this.getCollectionCatalogs(t);return((s=e==null?void 0:e[0])==null?void 0:s.data)??null}async getCollatedEditionIndex(t){const e=await this.resolveItemPath(t);if(!e)return null;const s=`${e.dir}/${t}/collated_edition/collated_edition_index.json`;return this.fetchFile(e.repo,s)}async getCollatedJuan(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;const s=await this.resolveItemPath(t);if(!s)return null;const n=`${s.dir}/${t}/collated_edition/${e}`;return this.fetchFile(s.repo,n)}async getCatalogProgress(){return this.fetchFile(this.config.repos.draft,"resource-catalog.json")}async getCollectionProgress(){return this.fetchFile(this.config.repos.draft,"resource-collection.json")}async getResourceProgress(){return this.fetchFile(this.config.repos.draft,"resource.json")}async getSiteProgress(){return this.fetchFile(this.config.repos.draft,"resource-site.json")}async getRecommended(){return this.fetchFile(this.config.repos.draft,"recommended.json")}clearCache(){this.cache=null,this.pathMap.clear(),this.searchSCache=null,this.t2sConverter=null}}const Z=255;class K{constructor(t){if(this.lastTimestamp=-1,this.lastStatus=null,this.sequence=0,t<0||t>2047)throw new Error("Machine ID must be between 0 and 2047");this.machineId=t}nextId(t,e){let s=this._getCurrentTimestamp(t);if(s<this.lastTimestamp&&t===this.lastStatus)throw new Error("Clock moved backwards. Refusing to generate ID.");s===this.lastTimestamp&&t===this.lastStatus?(this.sequence=this.sequence+1&Z,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t;const n=W(t,e,BigInt(s),this.machineId,this.sequence);return M(n)}nextIdRaw(t,e){let s=this._getCurrentTimestamp(t);if(s<this.lastTimestamp&&t===this.lastStatus)throw new Error("Clock moved backwards. Refusing to generate ID.");return s===this.lastTimestamp&&t===this.lastStatus?(this.sequence=this.sequence+1&Z,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t,W(t,e,BigInt(s),this.machineId,this.sequence)}_getCurrentTimestamp(t){const e=Date.now();return t==="draft"?e:Math.floor(e/1e3)}_tilNextUnit(t,e){let s=this._getCurrentTimestamp(e);for(;s<=t;)s=this._getCurrentTimestamp(e);return s}}class Rt{constructor(t){this.recentEntities=[],this.storage=new q(t.fs,t.workspaceRoot),this.idGen=new K(t.machineId??0),this.fs=t.fs,this.workspaceRoot=t.workspaceRoot}async loadEntries(t,e){const s=await this.storage.loadEntries(t);return this.paginate(s,e)}async search(t,e,s){const n=await this.storage.searchEntries(t,e);return this.paginate(n,s)}async searchAll(t,e){return this.storage.searchAll(t,e)}async getItem(t){const e=await this.storage.getItem(t);return e&&e.type==="entity"&&!e.title&&e.primary_name&&(e.title=e.primary_name),e}async saveItem(t){const e=t.id;if(!e)throw new Error("metadata.id is required");const s=t.type||this.extractTypeFromId(e),n=await this.storage.saveItem(s,e,t);return{id:e,path:n}}async deleteItem(t){if(!await this.storage.deleteItem(t))throw new Error(`Item not found: ${t}`)}async generateId(t,e){return this.idGen.nextId(e,t)}async getEntry(t){const e=await this.storage.getItem(t);if(!e)return null;const s=e.type||this.extractTypeFromId(t);return{id:t,title:e.title||"未命名",type:s,author:this.extractAuthor(e),dynasty:this.extractYear(e)}}async getAllEntries(){const t=["book","collection","work"],e=[];for(const s of t){const n=await this.storage.loadEntries(s);e.push(...n)}return e}async getRelations(t){const e=await this.storage.getItem(t);if(!e)return null;const s={},n=e.type||this.extractTypeFromId(t);if(n==="book"){if(e.work_id){const i=await this.resolveEntity(e.work_id);i&&(s.belongsToWork={...i,type:"work"})}if(e.contained_in&&Array.isArray(e.contained_in)&&e.contained_in.length>0){const i=e.contained_in[0],o=typeof i=="string"?i:i.id;if(o){const c=await this.resolveEntity(o);c&&(s.belongsToCollection={...c,type:"collection"})}}}else if(n==="collection"){if(e.books&&Array.isArray(e.books)){const i=await Promise.all(e.books.map(o=>this.resolveEntity(o)));s.containedBooks=i.filter(o=>o!==null).map(o=>({...o,type:"book"}))}}else if(n==="work"){if(e.parent_work&&typeof e.parent_work=="object"){const i=e.parent_work;s.parentWork={id:i.id,title:i.title,type:"work"}}if(e.books&&Array.isArray(e.books)){const i=await Promise.all(e.books.map(o=>this.resolveEntity(o)));s.containedBooks=i.filter(o=>o!==null).map(o=>({...o,type:"book"}))}}return s}async linkEntity(t,e,s){const n=await this.storage.getItem(t);if(!n)throw new Error(`Source not found: ${t}`);const i=n.type||this.extractTypeFromId(t);switch(e){case"belongsToWork":case"work_id":n.work_id=s;break;case"belongsToCollection":case"contained_in":Array.isArray(n.contained_in)||(n.contained_in=[]);{const o=n.contained_in;o.some(l=>(typeof l=="string"?l:l.id)===s)||o.push({id:s})}break;case"parentWork":case"parent_work":{const o=await this.storage.getItem(s);n.parent_work={id:s,title:(o==null?void 0:o.title)||""};break}case"containedBooks":case"books":Array.isArray(n.books)||(n.books=[]),n.books.includes(s)||n.books.push(s);break;default:throw new Error(`Unknown relation field: ${e}`)}await this.storage.saveItem(i,t,n)}async unlinkEntity(t,e){const s=await this.storage.getItem(t);if(!s)throw new Error(`Source not found: ${t}`);const n=s.type||this.extractTypeFromId(t);switch(e){case"belongsToWork":case"work_id":delete s.work_id;break;case"belongsToCollection":case"contained_in":s.contained_in=[];break;case"parentWork":case"parent_work":delete s.parent_work;break;case"containedBooks":case"books":s.books=[];break;default:throw new Error(`Unknown relation field: ${e}`)}await this.storage.saveItem(n,t,s)}async createAndLink(t,e,s){const n=this.idGen.nextId("draft",s.type),i={id:n,type:s.type,title:s.title,...s.inheritData||{}};return await this.storage.saveItem(s.type,n,i),await this.linkEntity(t,e,n),{id:n}}async searchEntities(t,e){const s=e&&e!=="all"?[e]:["book","collection","work"],n=[];for(const i of s){const o=await this.storage.searchEntries(t,i);for(const c of o)n.push({id:c.id,title:c.title,type:c.type,author:c.author,dynasty:c.dynasty})}return n}async getRecentEntities(){return this.recentEntities}async addRecentEntity(t){this.recentEntities=[t,...this.recentEntities.filter(e=>e.id!==t.id)].slice(0,20)}async getCollectionCatalog(t){const e=await this.storage.findFileById(t);if(!e)return null;const n=e.substring(0,e.lastIndexOf("/"))+"/volume_book_mapping.json";try{const i=await this.storage.loadMetadata(n);return Object.keys(i).length===0?null:i}catch{return null}}async getRecommended(){const t=this.workspaceRoot+"/book-index-draft/recommended.json";try{const e=await this.fs.readFile(t);return JSON.parse(e)}catch{return null}}getAssetDir(t){return this.storage.getAssetDir(t)}async initAssetDir(t){return this.storage.initAssetDir(t)}async hasAssetDir(t){return this.storage.hasAssetDir(t)}getBookIndexStorage(){return this.storage}async rebuildIndex(t){await this.storage.rebuildIndex(t)}extractTypeFromId(t){try{const e=k(t);return C(e).type}catch{return"book"}}extractAuthor(t){const e=t.authors;if(Array.isArray(e)&&e.length>0){const s=e[0];return typeof s=="object"&&s!==null?s.name||"":String(s)}}extractYear(t){const e=t.publication_info;if(typeof e=="object"&&e!==null)return e.year||void 0}async resolveEntity(t){const e=await this.storage.getItem(t);return e?{id:t,title:e.title||"未命名"}:null}paginate(t,e){const s=e.page??1,n=e.pageSize??50;if(e.sortBy){const l=e.sortBy,a=e.sortOrder==="desc"?-1:1;t.sort((h,u)=>{const d=h[l]??"",f=u[l]??"";return d<f?-a:d>f?a:0})}const i=t.length,o=(s-1)*n;return{entries:t.slice(o,o+n),total:i,page:s,pageSize:n}}}const Dt="/data",Ot=1e4;class Ut{constructor(t={}){this.indexCache=null,this.indexLoading=null,this.pathMap=new Map,this.chunkCache=new Map,this.chunkLoading=new Map,this.manifest=null,this.manifestLoading=null,this.tiyaoCache=new Map,this.tiyaoLoading=new Map,this.searchSCache=null,this.searchSLoading=null,this.searchSLoaded=!1,this.metaCache=null,this.metaLoading=null,this.metaTried=!1,this.t2sConverter=null,this.t2sLoading=null,this.version=void 0,this.versionPromise=null,this.basePath=t.basePath??Dt,this.timeout=t.timeout??Ot}async ensureVersion(){return this.version!==void 0?this.version:this.versionPromise?this.versionPromise:(this.versionPromise=(async()=>{try{const t=await fetch(`${this.basePath}/version.json`,{cache:"no-cache",signal:AbortSignal.timeout(this.timeout)});if(!t.ok)return null;const e=await t.json(),s=e==null?void 0:e.commitId;return!s||s==="unknown"?null:s.slice(0,12)}catch{return null}})(),this.version=await this.versionPromise,this.version)}async fetchJson(t){const e=await this.ensureVersion(),s=e?`${t}${t.includes("?")?"&":"?"}v=${e}`:t,n=await fetch(s,{signal:AbortSignal.timeout(this.timeout)});if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);return n.json()}async ensureLoaded(){if(this.indexCache)return this.indexCache;if(this.indexLoading)return this.indexLoading;this.indexLoading=(async()=>{var n,i;const t=await this.fetchJson(`${this.basePath}/index.json`),e=[],s=[["books","book"],["collections","collection"],["works","work"],["entities","entity"]];for(const[o,c]of s){const l=t[o];if(l)for(const a of Object.values(l)){const h=c==="entity"?a.primary_name||a.title||a.name||a.id:a.title||a.name||a.id;e.push({id:a.id,title:h,type:c,isDraft:!0,author:a.author,dynasty:a.dynasty,role:a.role,path:a.path,additional_titles:(n=a.additional_titles)==null?void 0:n.map(u=>typeof u=="string"?u:u==null?void 0:u.book_title).filter(Boolean),attached_texts:(i=a.attached_texts)==null?void 0:i.map(u=>typeof u=="string"?u:u==null?void 0:u.book_title).filter(Boolean),edition:a.edition,juan_count:a.juan_count,has_text:a.has_text,has_image:a.has_image,has_collated:a.has_collated,subtype:a.subtype,primary_name:a.primary_name,birth_year:a.birth_year,death_year:a.death_year,cbdb_id:a.cbdb_id}),this.pathMap.set(a.id,{path:a.path,isDraft:!0})}}return this.indexCache=e,e})();try{return await this.indexLoading}finally{this.indexCache||(this.indexLoading=null)}}async ensureSearchSLoaded(){if(this.searchSLoaded)return this.searchSCache??{};if(this.searchSLoading)return this.searchSLoading;this.searchSLoading=(async()=>{try{const t=await this.fetchJson(`${this.basePath}/search_s.json`);this.searchSCache=t}catch{this.searchSCache={}}return this.searchSLoaded=!0,this.searchSCache})();try{return await this.searchSLoading}finally{this.searchSLoaded||(this.searchSLoading=null)}}async ensureT2S(){if(this.t2sConverter===!1)return null;if(this.t2sConverter)return this.t2sConverter;if(this.t2sLoading)return this.t2sLoading;this.t2sLoading=(async()=>{try{const t=await import("opencc-js");return this.t2sConverter=t.Converter({from:"tw",to:"cn"}),this.t2sConverter}catch{return this.t2sConverter=!1,null}})();try{return await this.t2sLoading}finally{this.t2sLoading=null}}async loadManifest(){if(this.manifest)return this.manifest;if(this.manifestLoading)return this.manifestLoading;this.manifestLoading=(async()=>{try{this.manifest=await this.fetchJson(`${this.basePath}/chunks/_manifest.json`)}catch{this.manifest=[]}return this.manifest})();try{return await this.manifestLoading}finally{this.manifest||(this.manifestLoading=null)}}async resolvePrefix(t){const e=await this.loadManifest();let s=0,n=e.length-1,i=null;for(;s<=n;){const o=s+n>>1;e[o]<=t?(i=e[o],s=o+1):n=o-1}if(i&&t.startsWith(i))return i;for(const o of e)if(t.startsWith(o))return o;return null}async loadChunk(t){if(this.chunkCache.has(t))return this.chunkCache.get(t);const e=this.chunkLoading.get(t);if(e)return e;const s=(async()=>{try{const n=await this.fetchJson(`${this.basePath}/chunks/${t}.json`);return this.chunkCache.set(t,n),n}catch{return this.chunkCache.set(t,{}),{}}})();this.chunkLoading.set(t,s);try{return await s}finally{this.chunkLoading.delete(t)}}async loadChunkForId(t){const e=await this.resolvePrefix(t);return e?this.loadChunk(e):{}}async loadTiyaoGroup(t,e){const s=`${t}-${e}`;if(this.tiyaoCache.has(s))return this.tiyaoCache.get(s);const n=this.tiyaoLoading.get(s);if(n)return n;const i=c=>String(c).padStart(3,"0"),o=(async()=>{const c=await this.fetchJson(`${this.basePath}/tiyao/juan-${i(t)}-${i(e)}.json`);return this.tiyaoCache.set(s,c),c})();this.tiyaoLoading.set(s,o);try{return await o}finally{this.tiyaoLoading.delete(s)}}async getCounts(){if(this.metaCache)return this.metaCache;if(this.metaLoading){const h=await this.metaLoading;if(h)return h}else{this.metaLoading=(async()=>{try{const h=await this.fetchJson(`${this.basePath}/meta.json`);if(h&&typeof h.works=="number")return this.metaCache=h,h}catch{}return this.metaTried=!0,null})();try{const h=await this.metaLoading;if(h)return h}finally{this.metaLoading=null}}const t=await this.ensureLoaded();let e=0,s=0,n=0,i=0,o=0,c=0;const l={};for(const h of t)h.type==="work"?(e++,h.has_text&&o++,h.has_image&&c++,h.subtype&&(l[h.subtype]=(l[h.subtype]??0)+1)):h.type==="book"?s++:h.type==="collection"?n++:h.type==="entity"&&i++;const a={works:e,books:s,collections:n,entities:i,resourceCounts:{hasText:o,hasImage:c},subtypeStats:l};return this.metaCache=a,a}async getResourceCounts(){return(await this.getCounts()).resourceCounts??{hasText:0,hasImage:0}}async getSubtypeStats(){return(await this.getCounts()).subtypeStats??{}}async loadEntries(t,e){let n=(await this.ensureLoaded()).filter(h=>h.type===t);const i=e.sortBy||"title",o=e.sortOrder||"asc";n.sort((h,u)=>{const d=String(h[i]??""),f=String(u[i]??""),p=d.localeCompare(f,"zh");return o==="asc"?p:-p});const c=e.page||1,l=e.pageSize||50,a=(c-1)*l;return{entries:n.slice(a,a+l),total:n.length,page:c,pageSize:l}}async search(t,e,s){const n=await this.ensureLoaded(),i=await this.ensureSearchSLoaded(),o=await this.ensureT2S(),c=n.filter(p=>p.type===e),l=o?o(t):void 0,h=Object.keys(i).length>0?O(c,t,l,i):F(c,t),u=s.page||1,d=s.pageSize||50,f=(u-1)*d;return{entries:h.slice(f,f+d),total:h.length,page:u,pageSize:d}}async searchAll(t,e=5){const s=await this.ensureLoaded(),n=await this.ensureSearchSLoaded(),i=await this.ensureT2S(),o=["work","book","collection","entity"],c=i?i(t):void 0,l=Object.keys(n).length>0,a=o.map(h=>{const u=s.filter(d=>d.type===h);return l?O(u,t,c,n):F(u,t)});return{works:a[0].slice(0,e),books:a[1].slice(0,e),collections:a[2].slice(0,e),entities:a[3].slice(0,e),totalWorks:a[0].length,totalBooks:a[1].length,totalCollections:a[2].length,totalEntities:a[3].length}}async getItem(t){try{const s=(await this.loadChunkForId(t))[t]||null;if(s){const n=(await this.ensureLoaded()).find(i=>i.id===t);n!=null&&n.has_collated&&(s.has_collated=!0),s.type==="entity"&&!s.title&&s.primary_name&&(s.title=s.primary_name)}return s}catch{return null}}async getEntry(t){return(await this.ensureLoaded()).find(s=>s.id===t)||null}async getAllEntries(){return this.ensureLoaded()}async saveItem(){throw new Error("BundleStorage 为只读模式,不支持保存")}async deleteItem(){throw new Error("BundleStorage 为只读模式,不支持删除")}async generateId(){throw new Error("BundleStorage 为只读模式,不支持生成 ID")}async getCollectionCatalogs(t){const e=await this.getItem(t);if(!e)return null;const s=e.resources||[];if(s.length===0)return null;const n=[];for(const i of s)try{const o=await this.fetchJson(`${this.basePath}/items/${t}/${i.id}/volume_book_mapping.json`);o&&n.push({resource_id:i.id,short_name:i.short_name,data:Y(o)})}catch{}return n.length>0?n:null}async getCollectionCatalog(t){var s;const e=await this.getCollectionCatalogs(t);return((s=e==null?void 0:e[0])==null?void 0:s.data)??null}async getCollatedEditionIndex(t){try{return await this.fetchJson(`${this.basePath}/items/${t}/collated_edition/collated_edition_index.json`)}catch{return null}}async getCollatedJuan(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;try{return await this.fetchJson(`${this.basePath}/items/${t}/collated_edition/${e}`)}catch{return null}}async getCollatedJuanText(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;const s=e.replace(/\.json$/,".md"),n=await this.ensureVersion(),i=`${this.basePath}/items/${t}/collated_edition/text/${s}`,o=n?`${i}?v=${n}`:i;try{const c=await fetch(o);return c.ok?await c.text():null}catch{return null}}async getCatalogProgress(){try{return await this.fetchJson(`${this.basePath}/resource-catalog.json`)}catch{return null}}async getCollectionProgress(){try{return await this.fetchJson(`${this.basePath}/resource-collection.json`)}catch{return null}}async getResourceProgress(){try{return await this.fetchJson(`${this.basePath}/resource.json`)}catch{return null}}async getSiteProgress(){try{return await this.fetchJson(`${this.basePath}/resource-site.json`)}catch{return null}}async getRecommended(){try{return await this.fetchJson(`${this.basePath}/recommended.json`)}catch{return null}}clearCache(){this.indexCache=null,this.indexLoading=null,this.pathMap.clear(),this.chunkCache.clear(),this.chunkLoading.clear(),this.manifest=null,this.manifestLoading=null,this.tiyaoCache.clear(),this.tiyaoLoading.clear(),this.searchSCache=null,this.searchSLoading=null,this.searchSLoaded=!1,this.metaCache=null,this.metaLoading=null,this.metaTried=!1,this.t2sConverter=null,this.t2sLoading=null,this.version=void 0,this.versionPromise=null}}class T extends Error{constructor(t){super(t),this.name="BookIndexError"}}class Nt extends T{constructor(t){super(t),this.name="StorageError"}}class Jt extends T{constructor(t){super(t),this.name="IdGenerationError"}}class Wt extends T{constructor(t){super(t),this.name="ConfigError"}}class zt extends T{constructor(t){super(t),this.name="MigrationError"}}class Ht{constructor(t,e,s=1){this.storage=new q(t,e),this.idGen=new K(s)}generateId(t="book",e="draft"){return this.idGen.nextIdRaw(e,t)}encodeId(t){return M(t)}decodeId(t){return k(t)}async saveItem(t,e,s="draft"){let n=t.id||t.ID;if(n)try{const o=P(n);e||(e=o.type)}catch{throw new T(`Invalid ID format: ${n}`)}else e||(e=t.type||"book"),n=this.idGen.nextId(s,e),t.id=n;return await this.storage.saveItem(e,n,t)}async getItem(t){return this.storage.getItem(t)}async findItemPath(t){return this.storage.findFileById(t)}async updateField(t,e,s){const n=await this.storage.findFileById(t);if(!n)return!1;try{const i=await this.storage.loadMetadata(n),o={基本信息:null,介绍:"description",资源:"resources",收藏历史:"history",其他版本:"related_books"},c=e in o?o[e]:e;if(c===null)return!1;if(c==="description"&&typeof s=="string"){const a=i[c]||{};i[c]={text:s,sources:a.sources||[]}}else i[c]=s;const l=P(t);return await this.storage.saveItem(l.type,t,i),!0}catch{return!1}}async deleteItem(t){return this.storage.deleteItem(t)}async rebuildIndices(){await this.storage.rebuildIndex("official"),await this.storage.rebuildIndex("draft")}getAssetDir(t){return this.storage.getAssetDir(t)}async initAssetDir(t){return this.storage.initAssetDir(t)}async hasAssetDir(t){return this.storage.hasAssetDir(t)}getStorage(){return this.storage}}const Gt={wikisource:"wikisource",shidianguji:"shidianguji",archive:"archive",ctext:"ctext",nlc:"nlc","read.nlc":"nlc","db.sido":"sido","guji.artx":"guji-artx","digital.library":"digital-library"},tt=new Set(["text","image","text+image","physical"]),et=new Set(["text","image","physical"]),qt=new Set(["catalog","search"]),Yt=new Set(["com","org","net","cn","edu","gov","io","jp","tw","hk"]);function Kt(r){if(!r)return"";try{const e=new URL(r).hostname;for(const[n,i]of Object.entries(Gt))if(e.includes(n))return i;const s=e.split(".");if(s.length>=2){const n=s.filter(i=>!Yt.has(i)&&i.length>2);return n.length>0?n[n.length-1]:s[s.length-2]}return e}catch{return""}}function Vt(r){const t=[];r.name||t.push("name is required");let e=!1;if(r.types!==void 0)if(!Array.isArray(r.types)||r.types.length===0)t.push("types must be a non-empty array when present");else{for(const s of r.types)et.has(s)||t.push(`invalid types atom '${s}', must be one of ${[...et].join(", ")}`);e=r.types.length===1&&r.types[0]==="physical"}else r.type!==void 0?(tt.has(r.type)||t.push(`invalid type '${r.type}', must be one of ${[...tt].join(", ")}`),e=r.type==="physical"):t.push("either type or types is required");return r.root_type&&!qt.has(r.root_type)&&t.push(`invalid root_type '${r.root_type}'`),!e&&!r.url&&t.push("url is required for non-physical resources"),t}const _=class _{constructor(t,e=""){if(this._type=null,this.title=e,typeof t=="string"){t.startsWith(_.PREFIX)&&(t=t.slice(_.PREFIX.length)),this.idStr=t;try{this.idInt=k(t)}catch{this.idInt=0n}}else this.idInt=t,this.idStr=M(t);if(this.idInt>0n)try{const s=P(this.idStr);this._type=s.type}catch{}}get type(){return this._type}getIcon(){return this._type===null?"":this._type==="book"?"📖 ":this._type==="collection"?"📚 ":this._type==="work"?"📜 ":""}render(t=!1){return`[${t?this.getIcon():""}${this.title}](${_.PREFIX}${this.idStr})`}static parseFromLink(t){const e=t.match(/\[(.*?)\]\((.*?)\)/);if(e){const s=e[1],n=e[2];if(n.startsWith(_.PREFIX)){const i=n.slice(_.PREFIX.length);return new _(i,s)}}return null}static isBidLink(t){return t.startsWith(_.PREFIX)}};_.PROTOCOL="bid:\\\\",_.PREFIX="bid:\\\\";let H=_;exports.BidLink=H;exports.BookIndexError=T;exports.BookIndexManager=Ht;exports.BookIndexStorage=q;exports.BundleStorage=Ut;exports.ConfigError=Wt;exports.GithubStorage=Mt;exports.IdGenerationError=Jt;exports.IdGenerator=K;exports.LocalStorage=Rt;exports.MigrationError=zt;exports.StorageError=Nt;exports.base36Decode=G;exports.base36Encode=M;exports.base58Decode=lt;exports.buildId=W;exports.decodeId=vt;exports.decodeIdString=P;exports.encodeId=xt;exports.extractIdFromUrl=Kt;exports.extractStatus=Ct;exports.extractType=Et;exports.normalizeCatalog=Y;exports.parseId=C;exports.smartDecode=k;exports.validateResource=Vt;
|
|
1
|
+
"use strict";var dt=Object.create;var V=Object.defineProperty;var ft=Object.getOwnPropertyDescriptor;var yt=Object.getOwnPropertyNames;var gt=Object.getPrototypeOf,pt=Object.prototype.hasOwnProperty;var mt=(a,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of yt(t))!pt.call(a,n)&&n!==e&&V(a,n,{get:()=>t[n],enumerable:!(s=ft(t,n))||s.enumerable});return a};var X=(a,t,e)=>(e=a!=null?dt(gt(a)):{},mt(t||!a||!a.__esModule?V(e,"default",{value:a,enumerable:!0}):e,a));const _t={official:0,draft:1},wt={0:"official",1:"draft"},bt={book:0,collection:2,work:3,entity:4},kt={0:"book",2:"collection",3:"work",4:"entity"},st=62n,nt=59n,it=19n,ot=8n,rt=(1n<<40n)-1n,It=(1n<<3n)-1n,St=(1n<<11n)-1n,xt=(1n<<8n)-1n,R="0123456789abcdefghijklmnopqrstuvwxyz",at=new Map;for(let a=0;a<R.length;a++)at.set(R[a],BigInt(a));function D(a){if(a===0n)return R[0];let t="";for(;a>0n;)t=R[Number(a%36n)]+t,a=a/36n;return t}function G(a){let t=0n;for(const e of a){const s=at.get(e);if(s===void 0)throw new Error(`Invalid Base36 character: ${e}`);t=t*36n+s}return t}const Q="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",ct=new Map;for(let a=0;a<Q.length;a++)ct.set(Q[a],BigInt(a));function lt(a){let t=0n;for(const e of a){const s=ct.get(e);if(s===void 0)throw new Error(`Invalid Base58 character: ${e}`);t=t*58n+s}return t}function k(a){return/[A-Z]/.test(a)?lt(a):G(a)}const vt=D,Et=G;function C(a){const t=Number(a>>st&1n),e=Number(a>>nt&It),s=a>>it&rt,n=Number(a>>ot&St),i=Number(a&xt);return{status:wt[t]??"draft",type:kt[e]??"book",timestamp:s,machineId:n,sequence:i}}function W(a,t,e,s,n){return BigInt(_t[a])<<st|BigInt(bt[t])<<nt|(e&rt)<<it|BigInt(s)<<ot|BigInt(n)}function j(a){return C(k(a))}function ht(a){return j(a).type}function Ct(a){return j(a).status}const N={book:"Book",collection:"Collection",work:"Work",entity:"Entity"},$t={Book:"book",Collection:"collection",Work:"work",Entity:"entity"},B=16;function J(a,t=B){let e=0;for(let s=0;s<a.length;s++)e=Math.imul(e,31)+a.charCodeAt(s)>>>0;return e%t}function b(...a){const t=a.join("/");return t.startsWith("//")?"//"+t.slice(2).replace(/\/+/g,"/"):t.replace(/\/+/g,"/")}function At(a){return a.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g,"")||"Undefined"}class q{constructor(t,e){this.fs=t,this.officialRoot=b(e,"book-index"),this.draftRoot=b(e,"book-index-draft")}getRootByStatus(t){return t==="draft"?this.draftRoot:this.officialRoot}getRootById(t){const e=k(t),s=C(e);return this.getRootByStatus(s.status)}getPath(t,e,s){const n=this.getRootById(e),i=e.padEnd(3,"_").substring(0,3),[o,c,l]=[i[0],i[1],i[2]],r=N[t];return b(n,r,o,c,l,`${e}-${At(s)}.json`)}async saveItem(t,e,s){const n=s.title||s.书名||"未命名",i=s.edition||"",o=i?`${n}${i}`:n,c=this.getPath(t,e,o),l=await this.findFileById(e);if(l&&l!==c)try{await this.fs.deleteFile(l)}catch{}const r=c.substring(0,c.lastIndexOf("/"));await this.fs.mkdir(r),s.id=e,s.type=t,await this.fs.writeFile(c,JSON.stringify(s,Tt,2));const h=this.getRootById(e),u=c.substring(h.length+1);return await this.updateIndexEntry(h,s,t,u),c}async updateIndexEntry(t,e,s,n){const i=e.id||"";if(!i)return;const o=`${s}s`,c=await this.loadShard(t,o,i);let l="";const r=e.authors;if(Array.isArray(r)&&r.length>0){const y=r[0];l=typeof y=="object"&&y!==null?y.name||"":String(y)}else typeof r=="string"&&(l=r);let h="";const u=e.publication_info;typeof u=="object"&&u!==null?h=u.year||"":typeof u=="string"&&(h=u);let d="";const f=e.current_location;typeof f=="object"&&f!==null?d=f.name||"":typeof f=="string"&&(d=f);const p=Array.isArray(e.additional_titles)?e.additional_titles.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0,I=Array.isArray(e.attached_texts)?e.attached_texts.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0;let v;const S=e.juan_count;typeof S=="number"?v=S:typeof S=="object"&&S!==null&&(v=S.number||void 0);const A=typeof e.measure_info=="string"?e.measure_info:"";let E=!1,x=!1;const P=e.resources;if(Array.isArray(P))for(const y of P){if(typeof y!="object"||y===null)continue;const _=y.types;if(Array.isArray(_))_.includes("text")&&(E=!0),_.includes("image")&&(x=!0);else{const $=y.type;($==="text"||$==="text+image")&&(E=!0),($==="image"||$==="text+image")&&(x=!0)}}const m={id:i,title:e.title||"未命名",type:N[s],path:n,author:l,year:h,holder:d};p&&p.length>0&&(m.additional_titles=p),I&&I.length>0&&(m.attached_texts=I),v&&(m.juan_count=v),A&&(m.measure_info=A);const T=typeof e.edition=="string"?e.edition:"";T&&(m.edition=T),E&&(m.has_text=!0),x&&(m.has_image=!0),c[i]=m,await this.saveShard(t,o,i,c)}async deleteItem(t){const e=await this.findFileById(t);if(!e)return!1;const s=k(t),n=C(s),i=this.getRootByStatus(n.status),o=`${n.type}s`,c=await this.loadShard(i,o,t);return c[t]&&(delete c[t],await this.saveShard(i,o,t,c)),await this.fs.deleteFile(e),!0}async findFileById(t){const e=t.padEnd(3,"_").substring(0,3),[s,n,i]=[e[0],e[1],e[2]];for(const o of[this.officialRoot,this.draftRoot])for(const c of["Book","Collection","Work"]){const l=b(o,c,s,n,i);if(await this.fs.exists(l))try{const h=(await this.fs.readdir(l)).find(u=>u.startsWith(`${t}-`)&&u.endsWith(".json"));if(h)return b(l,h)}catch{}}return null}async loadMetadata(t){try{const e=await this.fs.readFile(t);return JSON.parse(e)}catch{return{}}}async getItem(t){const e=await this.findFileById(t);if(!e)return null;const s=await this.loadMetadata(e);return Object.keys(s).length>0?s:null}async loadEntries(t,e){const s=e?[this.getRootByStatus(e)]:[this.officialRoot,this.draftRoot],n=[],i=`${t}s`;for(const o of s){const c=await this.loadAllShards(o,i);for(const[l,r]of Object.entries(c))n.push({id:l,title:r.title,type:t,author:r.author||void 0,dynasty:r.dynasty||void 0,role:r.role||void 0,path:b(o,r.path),additional_titles:r.additional_titles,attached_texts:r.attached_texts,edition:r.edition,juan_count:r.juan_count,has_text:r.has_text,has_image:r.has_image})}return n}async searchEntries(t,e,s){const n=await this.loadEntries(e,s);return F(n,t)}async searchAll(t,e=5,s){const n=["work","book","collection"],i=await Promise.all(n.map(o=>this.searchEntries(t,o,s)));return{works:i[0].slice(0,e),books:i[1].slice(0,e),collections:i[2].slice(0,e),totalWorks:i[0].length,totalBooks:i[1].length,totalCollections:i[2].length}}async rebuildIndex(t){var n,i;const e=this.getRootByStatus(t),s={books:Object.fromEntries(Array.from({length:B},(o,c)=>[c,{}])),collections:{0:{}},works:Object.fromEntries(Array.from({length:B},(o,c)=>[c,{}]))};for(const o of["Book","Collection","Work"]){const c=b(e,o);if(!await this.fs.exists(c))continue;const r=`${$t[o]}s`,h=await this.fs.glob(c,"**/*.json");for(const u of h)if(!u.includes("/index/"))try{const d=await this.loadMetadata(u);let f=d.id||d.ID||"";if(!f){const g=u.substring(u.lastIndexOf("/")+1);g.includes("-")&&(f=g.split("-")[0])}if(!f)continue;const p=u.substring(e.length+1);let I="";const v=d.authors;if(Array.isArray(v)&&v.length>0){const g=v[0];I=typeof g=="object"&&g!==null?g.name||"":String(g)}const S=Array.isArray(d.additional_titles)?d.additional_titles.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0,A=Array.isArray(d.attached_texts)?d.attached_texts.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0;let E;const x=d.juan_count;typeof x=="number"?E=x:typeof x=="object"&&x!==null&&(E=x.number||void 0);const P=typeof d.measure_info=="string"?d.measure_info:"";let m=!1,T=!1;const y=d.resources;if(Array.isArray(y))for(const g of y){if(typeof g!="object"||g===null)continue;const U=g.types;if(Array.isArray(U))U.includes("text")&&(m=!0),U.includes("image")&&(T=!0);else{const M=g.type;(M==="text"||M==="text+image")&&(m=!0),(M==="image"||M==="text+image")&&(T=!0)}}const _={id:f,title:d.title||"未命名",type:o,path:p,author:I,year:typeof d.publication_info=="object"&&((n=d.publication_info)==null?void 0:n.year)||"",holder:typeof d.current_location=="object"&&((i=d.current_location)==null?void 0:i.name)||""};S&&S.length>0&&(_.additional_titles=S),A&&A.length>0&&(_.attached_texts=A),E&&(_.juan_count=E),P&&(_.measure_info=P);const $=typeof d.edition=="string"?d.edition:"";$&&(_.edition=$),m&&(_.has_text=!0),T&&(_.has_image=!0);const ut=r==="collections"?0:J(f);s[r][ut][f]=_}catch{}}for(const[o,c]of Object.entries(s))for(const[l,r]of Object.entries(c)){const h=this.shardPath(e,o,Number(l)),u=h.substring(0,h.lastIndexOf("/"));await this.fs.mkdir(u),await this.fs.writeFile(h,JSON.stringify(r,null,2))}}getAssetDir(t){const e=this.getRootById(t),s=k(t),i=C(s).type,o=t.padEnd(3,"_").substring(0,3),[c,l,r]=[o[0],o[1],o[2]],h=N[i];return b(e,h,c,l,r,t)}async initAssetDir(t){const e=this.getAssetDir(t);return await this.fs.mkdir(e),e}async hasAssetDir(t){const e=this.getAssetDir(t);return this.fs.exists(e)}shardPath(t,e,s){return e==="collections"?b(t,"index","collections.json"):b(t,"index",e,`${s.toString(16)}.json`)}async loadShard(t,e,s){const n=J(s),i=this.shardPath(t,e,n);try{if(!await this.fs.exists(i))return{};const o=await this.fs.readFile(i);return JSON.parse(o)}catch{return{}}}async saveShard(t,e,s,n){const i=J(s),o=this.shardPath(t,e,i),c=o.substring(0,o.lastIndexOf("/"));await this.fs.mkdir(c),await this.fs.writeFile(o,JSON.stringify(n,null,2))}async loadAllShards(t,e){const s={};if(e==="collections"){const n=this.shardPath(t,e,0);try{if(await this.fs.exists(n)){const i=await this.fs.readFile(n);Object.assign(s,JSON.parse(i))}}catch{}return s}for(let n=0;n<B;n++){const i=this.shardPath(t,e,n);try{if(await this.fs.exists(i)){const o=await this.fs.readFile(i);Object.assign(s,JSON.parse(o))}}catch{}}return s}}function z(a,t){const e=t.toLowerCase();let s=0;const n=a.title.toLowerCase();n===e?s=200:n.startsWith(e)?s=150:n.includes(e)&&(s=100);const i=[...a.additional_titles||[],...a.attached_texts||[]];for(const r of i){const h=r.toLowerCase();h===e?s=Math.max(s,120):h.startsWith(e)?s=Math.max(s,90):h.includes(e)&&(s=Math.max(s,60))}let o=0;if(a.author){const r=a.author.toLowerCase();r===e?o=80:r.includes(e)&&(o=50)}let c=0;a.dynasty&&a.dynasty.toLowerCase().includes(e)&&(c=30);let l=s;return l===0&&(l=Math.max(o,c)),l===0?0:(l+=Math.max(0,20-n.length),a.type==="work"?l=Math.round(l*1.05):a.type==="collection"&&(l=Math.round(l*1.02)),a.has_text&&(l+=3),a.has_image&&(l+=2),l)}function Tt(a,t){return t===null?void 0:t}function F(a,t){const e=a.map(s=>({entry:s,score:z(s,t)})).filter(s=>s.score>0);return e.sort((s,n)=>n.score!==s.score?n.score-s.score:s.entry.title.length-n.entry.title.length),e.map(s=>s.entry)}function O(a,t,e,s){const n=a.map(i=>{const o=z(i,t);let c=0;const l=s[i.id];if(l&&e){const r={...i,title:l.t??i.title,author:l.a??i.author,additional_titles:l.at??i.additional_titles,attached_texts:l.axt??i.attached_texts};c=z(r,e)}return{entry:i,score:Math.max(o,c)}}).filter(i=>i.score>0);return n.sort((i,o)=>o.score!==i.score?o.score-i.score:i.entry.title.length-o.entry.title.length),n.map(i=>i.entry)}function jt(a){const t=a.volumes??[];let e,s;if(t.length===0)e=[];else if(typeof t[0]=="number")e=t;else{s=[],e=[];for(const i of t){const o=i.volume;e.push(o);const c={};for(const[l,r]of Object.entries(i))l==="volume"||l==="status"||l==="file"||typeof r=="string"&&(l.includes("url")||l.includes("id"))&&(c[l]=r);s.push({volume:o,status:i.status,urls:Object.keys(c).length>0?c:void 0,file:i.file})}}const n={title:a.title??"",book_id:a.book_id??null,work_id:a.work_id??null,volumes:e,section:a.section,sub_items:a.sub_items,edition:a.edition,expected_volumes:a.expected_volumes,found_volumes:a.found_volumes,missing_volumes:a.missing_vols??a.missing_volumes};s&&(n.volume_details=s);for(const i of Object.keys(n))n[i]===void 0&&delete n[i];return n}function Lt(a){const t={total_books:a.total_books??0};return a.processed_volumes!=null&&(t.processed_volumes=a.processed_volumes),a.matched_works!=null&&(t.matched_works=a.matched_works),a.unmatched_works!=null&&(t.unmatched_works=a.unmatched_works),a.total_found_volumes!=null&&(t.total_found_volumes=a.total_found_volumes),t}function Y(a){var n;const t=a,e=(t.books??[]).map(jt),s={collection_id:t.collection_id??"",title:t.title??"",total_volumes:t.total_volumes??0,stats:Lt(t.stats??{}),books:e};return t.source&&(s.source=t.source),t.resource_id&&(s.resource_id=t.resource_id),t.resource_name&&(s.resource_name=t.resource_name),(n=t.sections)!=null&&n.length&&(s.sections=t.sections),t.volume_index&&Object.keys(t.volume_index).length>0&&(s.volume_index=t.volume_index),s}const Pt="https://raw.githubusercontent.com",Bt=["https://fastly.jsdelivr.net/gh","https://cdn.jsdelivr.net/gh"],Ft=5e3;class Dt{constructor(t){this.cache=null,this.cacheLoading=null,this.pathMap=new Map,this.searchSCache=null,this.t2sConverter=null,this.config={org:t.org,repos:t.repos,baseUrl:t.baseUrl??Pt,cdnUrls:t.cdnUrls??Bt,timeout:t.timeout??Ft}}async ensureLoaded(){if(this.cache)return this.cache;if(this.cacheLoading)return this.cacheLoading;this.cacheLoading=(async()=>{const t=[];for(const s of[!0,!1])try{const n=s?this.config.repos.draft:this.config.repos.official,i=await this.fetchIndex(n),o=this.parseIndexResponse(i,s);t.push(...o)}catch(n){console.warn(`Failed to fetch ${s?"draft":"official"} index:`,n)}const e=new Map;for(const s of t)e.set(s.id,s);return this.cache=Array.from(e.values()),this.cache})();try{return await this.cacheLoading}finally{this.cache||(this.cacheLoading=null)}}async fetchFileWithFallback(t,e){const s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{return await this.fetchJson(s)}catch{}for(const n of this.config.cdnUrls){const i=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(i)}catch{continue}}throw new Error(`Failed to fetch ${e} for ${t} from all sources`)}async probeIndex(t){const e="index/collections.json",s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{if((await fetch(s,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{}for(const o of this.config.cdnUrls){const c=`${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{if((await fetch(c,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{continue}}const n="index/works/0.json",i=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(n)}`;try{if((await fetch(i,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{}for(const o of this.config.cdnUrls){const c=`${o}/${this.config.org}/${t}@main/${encodeURI(n)}`;try{if((await fetch(c,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{continue}}return!1}async fetchIndex(t){if(!await this.probeIndex(t))return{books:{},collections:{},works:{}};const s={books:{},collections:{},works:{}};try{const i=await this.fetchFileWithFallback(t,"index/collections.json");s.collections=i}catch{}const n=[];for(const i of["books","works"])for(let o=0;o<B;o++){const c=`index/${i}/${o.toString(16)}.json`;n.push(this.fetchFileWithFallback(t,c).then(l=>{Object.assign(s[i],l)}).catch(()=>{}))}return await Promise.all(n),s}async fetchJson(t){const e=await fetch(t,{cache:"no-store",signal:AbortSignal.timeout(this.config.timeout)});if(!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);return e.json()}parseIndexResponse(t,e){var i,o;const s=[],n=[["books","book"],["collections","collection"],["works","work"],["entities","entity"]];for(const[c,l]of n){const r=t[c];if(r)for(const h of Object.values(r)){const u=h,d=l==="entity"?u.primary_name||h.title||h.name||h.id:h.title||h.name||h.id;s.push({id:h.id,title:d,type:l,isDraft:e,author:h.author,dynasty:h.dynasty,role:h.role,path:h.path,additional_titles:(i=u.additional_titles)==null?void 0:i.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),attached_texts:(o=u.attached_texts)==null?void 0:o.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),edition:u.edition,juan_count:u.juan_count,has_text:u.has_text,has_image:u.has_image,has_collated:u.has_collated,subtype:u.subtype,primary_name:u.primary_name,birth_year:u.birth_year,death_year:u.death_year,cbdb_id:u.cbdb_id}),this.pathMap.set(h.id,{path:h.path,isDraft:e})}}return s}async ensureSearchSBuilt(){var n,i;if(this.searchSCache)return{searchS:this.searchSCache,converter:this.t2sConverter||null};if(this.t2sConverter===!1)return{searchS:{},converter:null};try{const o=await import("opencc-js");this.t2sConverter=o.Converter({from:"tw",to:"cn"})}catch{return this.t2sConverter=!1,this.searchSCache={},{searchS:{},converter:null}}const t=await this.ensureLoaded(),e=this.t2sConverter,s={};for(const o of t){const c={},l=e(o.title);if(l!==o.title&&(c.t=l),o.author){const r=e(o.author);r!==o.author&&(c.a=r)}if((n=o.additional_titles)!=null&&n.length){const r=o.additional_titles.map(e);r.some((h,u)=>h!==o.additional_titles[u])&&(c.at=r)}if((i=o.attached_texts)!=null&&i.length){const r=o.attached_texts.map(e);r.some((h,u)=>h!==o.attached_texts[u])&&(c.axt=r)}Object.keys(c).length>0&&(s[o.id]=c)}return this.searchSCache=s,{searchS:s,converter:e}}async loadEntries(t,e){let n=(await this.ensureLoaded()).filter(u=>u.type===t);const i=e.sortBy||"title",o=e.sortOrder||"asc";n.sort((u,d)=>{const f=String(u[i]??""),p=String(d[i]??""),I=f.localeCompare(p,"zh");return o==="asc"?I:-I});const c=e.page||1,l=e.pageSize||50,r=(c-1)*l;return{entries:n.slice(r,r+l),total:n.length,page:c,pageSize:l}}async search(t,e,s){const n=await this.ensureLoaded(),{searchS:i,converter:o}=await this.ensureSearchSBuilt(),c=n.filter(p=>p.type===e),l=o?o(t):void 0,h=Object.keys(i).length>0?O(c,t,l,i):F(c,t),u=s.page||1,d=s.pageSize||50,f=(u-1)*d;return{entries:h.slice(f,f+d),total:h.length,page:u,pageSize:d}}async searchAll(t,e=5){const s=await this.ensureLoaded(),{searchS:n,converter:i}=await this.ensureSearchSBuilt(),o=["work","book","collection"],c=i?i(t):void 0,l=Object.keys(n).length>0,r=o.map(h=>{const u=s.filter(d=>d.type===h);return l?O(u,t,c,n):F(u,t)});return{works:r[0].slice(0,e),books:r[1].slice(0,e),collections:r[2].slice(0,e),totalWorks:r[0].length,totalBooks:r[1].length,totalCollections:r[2].length}}async getItem(t){const e=await this.ensureLoaded(),s=this.pathMap.get(t);let n=null;if(s){const i=s.isDraft?this.config.repos.draft:this.config.repos.official;if(n=await this.fetchItemByPath(i,s.path),n){const o=e.find(c=>c.id===t);o!=null&&o.has_collated&&(n.has_collated=!0)}}else n=await this.findItemById(t);return n&&n.type==="entity"&&!n.title&&n.primary_name&&(n.title=n.primary_name),n}async getEntry(t){const s=(await this.ensureLoaded()).find(i=>i.id===t);if(s)return s;const n=await this.findItemById(t);return n?this.buildEntryFromItem(t,n):null}async getAllEntries(){return this.ensureLoaded()}async saveItem(){throw new Error("GithubStorage 为只读模式,不支持保存")}async deleteItem(){throw new Error("GithubStorage 为只读模式,不支持删除")}async generateId(){throw new Error("GithubStorage 为只读模式,不支持生成 ID")}async fetchItemByPath(t,e){let s=null;const n=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{s=await this.fetchJson(n)}catch{}if(!s)for(const i of this.config.cdnUrls){const o=`${i}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{s=await this.fetchJson(o);break}catch{continue}}return s}async findItemById(t){const e={book:"Book",collection:"Collection",work:"Work",entity:"Entity"};let s,n;try{const h=C(k(t));s=h.type,n=h.status}catch{return null}const i=n==="draft"?this.config.repos.draft:this.config.repos.official,o=e[s],c=t.padEnd(3,"_").substring(0,3),l=`${o}/${c[0]}/${c[1]}/${c[2]}`,r=`https://api.github.com/repos/${this.config.org}/${i}/contents/${l}`;try{const h=await fetch(r,{signal:AbortSignal.timeout(this.config.timeout)});if(!h.ok)return null;const d=(await h.json()).find(p=>p.name.startsWith(`${t}-`)&&p.name.endsWith(".json"));if(!d)return null;const f=await this.fetchItemByPath(i,d.path);return f&&this.pathMap.set(t,{path:d.path,isDraft:n==="draft"}),f}catch{return null}}buildEntryFromItem(t,e){const s=(e.type||"").toLowerCase(),n=s==="work"?"work":s==="collection"?"collection":"book";let i;const o=e.authors;if(Array.isArray(o)&&o.length>0){const r=o[0];i=typeof r=="object"&&r!==null?r.name||"":String(r)}let c=!0;try{c=C(k(t)).status==="draft"}catch{}const l=this.pathMap.get(t);return{id:t,title:e.title||e.书名||t,type:n,isDraft:c,author:i,dynasty:e.dynasty,role:e.role,path:(l==null?void 0:l.path)||"",juan_count:e.n_juan,has_collated:e.has_collated}}async fetchFile(t,e){const s=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(e)}`;try{return await this.fetchJson(s)}catch{}for(const n of this.config.cdnUrls){const i=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(i)}catch{continue}}return null}async resolveItemPath(t){await this.ensureLoaded();let e=this.pathMap.get(t);if(!e&&(await this.findItemById(t),e=this.pathMap.get(t),!e))return null;const s=e.isDraft?this.config.repos.draft:this.config.repos.official,n=e.path.substring(0,e.path.lastIndexOf("/"));return{repo:s,dir:n}}async getCollectionCatalogs(t){const e=await this.resolveItemPath(t);if(!e)return null;const s=await this.getItem(t);if(!s)return null;const n=s.resources||[];if(n.length===0)return null;const i=[];for(const o of n){const c=`${e.dir}/${t}/${o.id}/volume_book_mapping.json`,l=await this.fetchFile(e.repo,c);l&&i.push({resource_id:o.id,short_name:o.short_name,data:Y(l)})}return i.length>0?i:null}async getCollectionCatalog(t){var s;const e=await this.getCollectionCatalogs(t);return((s=e==null?void 0:e[0])==null?void 0:s.data)??null}async getCollatedEditionIndex(t){const e=await this.resolveItemPath(t);if(!e)return null;const s=`${e.dir}/${t}/collated_edition/collated_edition_index.json`;return this.fetchFile(e.repo,s)}async getCollatedJuan(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;const s=await this.resolveItemPath(t);if(!s)return null;const n=`${s.dir}/${t}/collated_edition/${e}`;return this.fetchFile(s.repo,n)}async getCatalogProgress(){return this.fetchFile(this.config.repos.draft,"resource-catalog.json")}async getCollectionProgress(){return this.fetchFile(this.config.repos.draft,"resource-collection.json")}async getResourceProgress(){return this.fetchFile(this.config.repos.draft,"resource.json")}async getSiteProgress(){return this.fetchFile(this.config.repos.draft,"resource-site.json")}async getRecommended(){return this.fetchFile(this.config.repos.draft,"recommended.json")}clearCache(){this.cache=null,this.pathMap.clear(),this.searchSCache=null,this.t2sConverter=null}}const Z=255;class K{constructor(t){if(this.lastTimestamp=-1,this.lastStatus=null,this.sequence=0,t<0||t>2047)throw new Error("Machine ID must be between 0 and 2047");this.machineId=t}nextId(t,e){let s=this._getCurrentTimestamp(t);if(s<this.lastTimestamp&&t===this.lastStatus)throw new Error("Clock moved backwards. Refusing to generate ID.");s===this.lastTimestamp&&t===this.lastStatus?(this.sequence=this.sequence+1&Z,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t;const n=W(t,e,BigInt(s),this.machineId,this.sequence);return D(n)}nextIdRaw(t,e){let s=this._getCurrentTimestamp(t);if(s<this.lastTimestamp&&t===this.lastStatus)throw new Error("Clock moved backwards. Refusing to generate ID.");return s===this.lastTimestamp&&t===this.lastStatus?(this.sequence=this.sequence+1&Z,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t,W(t,e,BigInt(s),this.machineId,this.sequence)}_getCurrentTimestamp(t){const e=Date.now();return t==="draft"?e:Math.floor(e/1e3)}_tilNextUnit(t,e){let s=this._getCurrentTimestamp(e);for(;s<=t;)s=this._getCurrentTimestamp(e);return s}}class Mt{constructor(t){this.recentEntities=[],this.storage=new q(t.fs,t.workspaceRoot),this.idGen=new K(t.machineId??0),this.fs=t.fs,this.workspaceRoot=t.workspaceRoot}async loadEntries(t,e){const s=await this.storage.loadEntries(t);return this.paginate(s,e)}async search(t,e,s){const n=await this.storage.searchEntries(t,e);return this.paginate(n,s)}async searchAll(t,e){return this.storage.searchAll(t,e)}async getItem(t){const e=await this.storage.getItem(t);return e&&e.type==="entity"&&!e.title&&e.primary_name&&(e.title=e.primary_name),e}async saveItem(t){const e=t.id;if(!e)throw new Error("metadata.id is required");const s=t.type||this.extractTypeFromId(e),n=await this.storage.saveItem(s,e,t);return{id:e,path:n}}async deleteItem(t){if(!await this.storage.deleteItem(t))throw new Error(`Item not found: ${t}`)}async generateId(t,e){return this.idGen.nextId(e,t)}async getEntry(t){const e=await this.storage.getItem(t);if(!e)return null;const s=e.type||this.extractTypeFromId(t);return{id:t,title:e.title||"未命名",type:s,author:this.extractAuthor(e),dynasty:this.extractYear(e)}}async getAllEntries(){const t=["book","collection","work"],e=[];for(const s of t){const n=await this.storage.loadEntries(s);e.push(...n)}return e}async getRelations(t){const e=await this.storage.getItem(t);if(!e)return null;const s={},n=e.type||this.extractTypeFromId(t);if(n==="book"){if(e.work_id){const i=await this.resolveEntity(e.work_id);i&&(s.belongsToWork={...i,type:"work"})}if(e.contained_in&&Array.isArray(e.contained_in)&&e.contained_in.length>0){const i=e.contained_in[0],o=typeof i=="string"?i:i.id;if(o){const c=await this.resolveEntity(o);c&&(s.belongsToCollection={...c,type:"collection"})}}}else if(n==="collection"){if(e.books&&Array.isArray(e.books)){const i=await Promise.all(e.books.map(o=>this.resolveEntity(o)));s.containedBooks=i.filter(o=>o!==null).map(o=>({...o,type:"book"}))}}else if(n==="work"){if(e.parent_work&&typeof e.parent_work=="object"){const i=e.parent_work;s.parentWork={id:i.id,title:i.title,type:"work"}}if(e.books&&Array.isArray(e.books)){const i=await Promise.all(e.books.map(o=>this.resolveEntity(o)));s.containedBooks=i.filter(o=>o!==null).map(o=>({...o,type:"book"}))}}return s}async linkEntity(t,e,s){const n=await this.storage.getItem(t);if(!n)throw new Error(`Source not found: ${t}`);const i=n.type||this.extractTypeFromId(t);switch(e){case"belongsToWork":case"work_id":n.work_id=s;break;case"belongsToCollection":case"contained_in":Array.isArray(n.contained_in)||(n.contained_in=[]);{const o=n.contained_in;o.some(l=>(typeof l=="string"?l:l.id)===s)||o.push({id:s})}break;case"parentWork":case"parent_work":{const o=await this.storage.getItem(s);n.parent_work={id:s,title:(o==null?void 0:o.title)||""};break}case"containedBooks":case"books":Array.isArray(n.books)||(n.books=[]),n.books.includes(s)||n.books.push(s);break;default:throw new Error(`Unknown relation field: ${e}`)}await this.storage.saveItem(i,t,n)}async unlinkEntity(t,e){const s=await this.storage.getItem(t);if(!s)throw new Error(`Source not found: ${t}`);const n=s.type||this.extractTypeFromId(t);switch(e){case"belongsToWork":case"work_id":delete s.work_id;break;case"belongsToCollection":case"contained_in":s.contained_in=[];break;case"parentWork":case"parent_work":delete s.parent_work;break;case"containedBooks":case"books":s.books=[];break;default:throw new Error(`Unknown relation field: ${e}`)}await this.storage.saveItem(n,t,s)}async createAndLink(t,e,s){const n=this.idGen.nextId("draft",s.type),i={id:n,type:s.type,title:s.title,...s.inheritData||{}};return await this.storage.saveItem(s.type,n,i),await this.linkEntity(t,e,n),{id:n}}async searchEntities(t,e){const s=e&&e!=="all"?[e]:["book","collection","work"],n=[];for(const i of s){const o=await this.storage.searchEntries(t,i);for(const c of o)n.push({id:c.id,title:c.title,type:c.type,author:c.author,dynasty:c.dynasty})}return n}async getRecentEntities(){return this.recentEntities}async addRecentEntity(t){this.recentEntities=[t,...this.recentEntities.filter(e=>e.id!==t.id)].slice(0,20)}async getCollectionCatalog(t){const e=await this.storage.findFileById(t);if(!e)return null;const n=e.substring(0,e.lastIndexOf("/"))+"/volume_book_mapping.json";try{const i=await this.storage.loadMetadata(n);return Object.keys(i).length===0?null:i}catch{return null}}async getRecommended(){const t=this.workspaceRoot+"/book-index-draft/recommended.json";try{const e=await this.fs.readFile(t);return JSON.parse(e)}catch{return null}}getAssetDir(t){return this.storage.getAssetDir(t)}async initAssetDir(t){return this.storage.initAssetDir(t)}async hasAssetDir(t){return this.storage.hasAssetDir(t)}getBookIndexStorage(){return this.storage}async rebuildIndex(t){await this.storage.rebuildIndex(t)}extractTypeFromId(t){try{const e=k(t);return C(e).type}catch{return"book"}}extractAuthor(t){const e=t.authors;if(Array.isArray(e)&&e.length>0){const s=e[0];return typeof s=="object"&&s!==null?s.name||"":String(s)}}extractYear(t){const e=t.publication_info;if(typeof e=="object"&&e!==null)return e.year||void 0}async resolveEntity(t){const e=await this.storage.getItem(t);return e?{id:t,title:e.title||"未命名"}:null}paginate(t,e){const s=e.page??1,n=e.pageSize??50;if(e.sortBy){const l=e.sortBy,r=e.sortOrder==="desc"?-1:1;t.sort((h,u)=>{const d=h[l]??"",f=u[l]??"";return d<f?-r:d>f?r:0})}const i=t.length,o=(s-1)*n;return{entries:t.slice(o,o+n),total:i,page:s,pageSize:n}}}const Rt="/data",Ot=1e4;class Ut{constructor(t={}){this.indexCache=null,this.indexLoading=null,this.pathMap=new Map,this.chunkCache=new Map,this.chunkLoading=new Map,this.manifest=null,this.manifestLoading=null,this.tiyaoCache=new Map,this.tiyaoLoading=new Map,this.searchSCache=null,this.searchSLoading=null,this.searchSLoaded=!1,this.metaCache=null,this.metaLoading=null,this.metaTried=!1,this.t2sConverter=null,this.t2sLoading=null,this.version=void 0,this.versionPromise=null,this.basePath=t.basePath??Rt,this.timeout=t.timeout??Ot}async ensureVersion(){return this.version!==void 0?this.version:this.versionPromise?this.versionPromise:(this.versionPromise=(async()=>{try{const t=await fetch(`${this.basePath}/version.json`,{cache:"no-cache",signal:AbortSignal.timeout(this.timeout)});if(!t.ok)return null;const e=await t.json(),s=e==null?void 0:e.commitId;return!s||s==="unknown"?null:s.slice(0,12)}catch{return null}})(),this.version=await this.versionPromise,this.version)}async fetchJson(t){const e=await this.ensureVersion(),s=e?`${t}${t.includes("?")?"&":"?"}v=${e}`:t,n=await fetch(s,{signal:AbortSignal.timeout(this.timeout)});if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);return n.json()}async ensureLoaded(){if(this.indexCache)return this.indexCache;if(this.indexLoading)return this.indexLoading;this.indexLoading=(async()=>{var n,i;const t=await this.fetchJson(`${this.basePath}/index.json`),e=[],s=[["books","book"],["collections","collection"],["works","work"],["entities","entity"]];for(const[o,c]of s){const l=t[o];if(l)for(const r of Object.values(l)){const h=c==="entity"?r.primary_name||r.title||r.name||r.id:r.title||r.name||r.id;e.push({id:r.id,title:h,type:c,isDraft:!0,author:r.author,dynasty:r.dynasty,role:r.role,path:r.path,additional_titles:(n=r.additional_titles)==null?void 0:n.map(u=>typeof u=="string"?u:u==null?void 0:u.book_title).filter(Boolean),attached_texts:(i=r.attached_texts)==null?void 0:i.map(u=>typeof u=="string"?u:u==null?void 0:u.book_title).filter(Boolean),edition:r.edition,juan_count:r.juan_count,has_text:r.has_text,has_image:r.has_image,has_collated:r.has_collated,subtype:r.subtype,primary_name:r.primary_name,birth_year:r.birth_year,death_year:r.death_year,cbdb_id:r.cbdb_id}),this.pathMap.set(r.id,{path:r.path,isDraft:!0})}}return this.indexCache=e,e})();try{return await this.indexLoading}finally{this.indexCache||(this.indexLoading=null)}}async ensureSearchSLoaded(){if(this.searchSLoaded)return this.searchSCache??{};if(this.searchSLoading)return this.searchSLoading;this.searchSLoading=(async()=>{try{const t=await this.fetchJson(`${this.basePath}/search_s.json`);this.searchSCache=t}catch{this.searchSCache={}}return this.searchSLoaded=!0,this.searchSCache})();try{return await this.searchSLoading}finally{this.searchSLoaded||(this.searchSLoading=null)}}async ensureT2S(){if(this.t2sConverter===!1)return null;if(this.t2sConverter)return this.t2sConverter;if(this.t2sLoading)return this.t2sLoading;this.t2sLoading=(async()=>{try{const t=await import("opencc-js");return this.t2sConverter=t.Converter({from:"tw",to:"cn"}),this.t2sConverter}catch{return this.t2sConverter=!1,null}})();try{return await this.t2sLoading}finally{this.t2sLoading=null}}async loadManifest(){if(this.manifest)return this.manifest;if(this.manifestLoading)return this.manifestLoading;this.manifestLoading=(async()=>{try{this.manifest=await this.fetchJson(`${this.basePath}/chunks/_manifest.json`)}catch{this.manifest=[]}return this.manifest})();try{return await this.manifestLoading}finally{this.manifest||(this.manifestLoading=null)}}async resolvePrefix(t){const e=await this.loadManifest();let s=0,n=e.length-1,i=null;for(;s<=n;){const o=s+n>>1;e[o]<=t?(i=e[o],s=o+1):n=o-1}if(i&&t.startsWith(i))return i;for(const o of e)if(t.startsWith(o))return o;return null}async loadChunk(t){if(this.chunkCache.has(t))return this.chunkCache.get(t);const e=this.chunkLoading.get(t);if(e)return e;const s=(async()=>{try{const n=await this.fetchJson(`${this.basePath}/chunks/${t}.json`);return this.chunkCache.set(t,n),n}catch{return this.chunkCache.set(t,{}),{}}})();this.chunkLoading.set(t,s);try{return await s}finally{this.chunkLoading.delete(t)}}async loadChunkForId(t){const e=await this.resolvePrefix(t);return e?this.loadChunk(e):{}}async loadTiyaoGroup(t,e){const s=`${t}-${e}`;if(this.tiyaoCache.has(s))return this.tiyaoCache.get(s);const n=this.tiyaoLoading.get(s);if(n)return n;const i=c=>String(c).padStart(3,"0"),o=(async()=>{const c=await this.fetchJson(`${this.basePath}/tiyao/juan-${i(t)}-${i(e)}.json`);return this.tiyaoCache.set(s,c),c})();this.tiyaoLoading.set(s,o);try{return await o}finally{this.tiyaoLoading.delete(s)}}async getCounts(){if(this.metaCache)return this.metaCache;if(this.metaLoading){const h=await this.metaLoading;if(h)return h}else{this.metaLoading=(async()=>{try{const h=await this.fetchJson(`${this.basePath}/meta.json`);if(h&&typeof h.works=="number")return this.metaCache=h,h}catch{}return this.metaTried=!0,null})();try{const h=await this.metaLoading;if(h)return h}finally{this.metaLoading=null}}const t=await this.ensureLoaded();let e=0,s=0,n=0,i=0,o=0,c=0;const l={};for(const h of t)h.type==="work"?(e++,h.has_text&&o++,h.has_image&&c++,h.subtype&&(l[h.subtype]=(l[h.subtype]??0)+1)):h.type==="book"?s++:h.type==="collection"?n++:h.type==="entity"&&i++;const r={works:e,books:s,collections:n,entities:i,resourceCounts:{hasText:o,hasImage:c},subtypeStats:l};return this.metaCache=r,r}async getResourceCounts(){return(await this.getCounts()).resourceCounts??{hasText:0,hasImage:0}}async getSubtypeStats(){return(await this.getCounts()).subtypeStats??{}}async loadEntries(t,e){let n=(await this.ensureLoaded()).filter(h=>h.type===t);const i=e.sortBy||"title",o=e.sortOrder||"asc";n.sort((h,u)=>{const d=String(h[i]??""),f=String(u[i]??""),p=d.localeCompare(f,"zh");return o==="asc"?p:-p});const c=e.page||1,l=e.pageSize||50,r=(c-1)*l;return{entries:n.slice(r,r+l),total:n.length,page:c,pageSize:l}}async search(t,e,s){const n=await this.ensureLoaded(),i=await this.ensureSearchSLoaded(),o=await this.ensureT2S(),c=n.filter(p=>p.type===e),l=o?o(t):void 0,h=Object.keys(i).length>0?O(c,t,l,i):F(c,t),u=s.page||1,d=s.pageSize||50,f=(u-1)*d;return{entries:h.slice(f,f+d),total:h.length,page:u,pageSize:d}}async searchAll(t,e=5){const s=await this.ensureLoaded(),n=await this.ensureSearchSLoaded(),i=await this.ensureT2S(),o=["work","book","collection","entity"],c=i?i(t):void 0,l=Object.keys(n).length>0,r=o.map(h=>{const u=s.filter(d=>d.type===h);return l?O(u,t,c,n):F(u,t)});return{works:r[0].slice(0,e),books:r[1].slice(0,e),collections:r[2].slice(0,e),entities:r[3].slice(0,e),totalWorks:r[0].length,totalBooks:r[1].length,totalCollections:r[2].length,totalEntities:r[3].length}}async getItem(t){try{const s=(await this.loadChunkForId(t))[t]||null;return s&&s.type==="entity"&&!s.title&&s.primary_name&&(s.title=s.primary_name),s}catch{return null}}async getEntry(t){var s,n;try{const o=(await this.loadChunkForId(t))[t];if(o){const c=ht(t),l=c==="entity"?o.primary_name||o.title||o.name||t:o.title||o.name||t;return{id:t,title:l,type:c,isDraft:!0,author:o.author,dynasty:o.dynasty,role:o.role,additional_titles:(s=o.additional_titles)==null?void 0:s.map(r=>typeof r=="string"?r:r==null?void 0:r.book_title).filter(Boolean),attached_texts:(n=o.attached_texts)==null?void 0:n.map(r=>typeof r=="string"?r:r==null?void 0:r.book_title).filter(Boolean),edition:o.edition,juan_count:o.juan_count,has_text:o.has_text,has_image:o.has_image,has_collated:o.has_collated,subtype:o.subtype,primary_name:o.primary_name,birth_year:o.birth_year,death_year:o.death_year,cbdb_id:o.cbdb_id}}}catch{}return(await this.ensureLoaded()).find(i=>i.id===t)||null}async getAllEntries(){return this.ensureLoaded()}async saveItem(){throw new Error("BundleStorage 为只读模式,不支持保存")}async deleteItem(){throw new Error("BundleStorage 为只读模式,不支持删除")}async generateId(){throw new Error("BundleStorage 为只读模式,不支持生成 ID")}async getCollectionCatalogs(t){const e=await this.getItem(t);if(!e)return null;const s=e.resources||[];if(s.length===0)return null;const n=[];for(const i of s)try{const o=await this.fetchJson(`${this.basePath}/items/${t}/${i.id}/volume_book_mapping.json`);o&&n.push({resource_id:i.id,short_name:i.short_name,data:Y(o)})}catch{}return n.length>0?n:null}async getCollectionCatalog(t){var s;const e=await this.getCollectionCatalogs(t);return((s=e==null?void 0:e[0])==null?void 0:s.data)??null}async getCollatedEditionIndex(t){try{return await this.fetchJson(`${this.basePath}/items/${t}/collated_edition/collated_edition_index.json`)}catch{return null}}async getCollatedJuan(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;try{return await this.fetchJson(`${this.basePath}/items/${t}/collated_edition/${e}`)}catch{return null}}async getCollatedJuanText(t,e){if(e.includes("..")||!e.endsWith(".json"))return null;const s=e.replace(/\.json$/,".md"),n=await this.ensureVersion(),i=`${this.basePath}/items/${t}/collated_edition/text/${s}`,o=n?`${i}?v=${n}`:i;try{const c=await fetch(o);return c.ok?await c.text():null}catch{return null}}async getCatalogProgress(){try{return await this.fetchJson(`${this.basePath}/resource-catalog.json`)}catch{return null}}async getCollectionProgress(){try{return await this.fetchJson(`${this.basePath}/resource-collection.json`)}catch{return null}}async getResourceProgress(){try{return await this.fetchJson(`${this.basePath}/resource.json`)}catch{return null}}async getSiteProgress(){try{return await this.fetchJson(`${this.basePath}/resource-site.json`)}catch{return null}}async getRecommended(){try{return await this.fetchJson(`${this.basePath}/recommended.json`)}catch{return null}}clearCache(){this.indexCache=null,this.indexLoading=null,this.pathMap.clear(),this.chunkCache.clear(),this.chunkLoading.clear(),this.manifest=null,this.manifestLoading=null,this.tiyaoCache.clear(),this.tiyaoLoading.clear(),this.searchSCache=null,this.searchSLoading=null,this.searchSLoaded=!1,this.metaCache=null,this.metaLoading=null,this.metaTried=!1,this.t2sConverter=null,this.t2sLoading=null,this.version=void 0,this.versionPromise=null}}class L extends Error{constructor(t){super(t),this.name="BookIndexError"}}class Nt extends L{constructor(t){super(t),this.name="StorageError"}}class Jt extends L{constructor(t){super(t),this.name="IdGenerationError"}}class Wt extends L{constructor(t){super(t),this.name="ConfigError"}}class zt extends L{constructor(t){super(t),this.name="MigrationError"}}class Ht{constructor(t,e,s=1){this.storage=new q(t,e),this.idGen=new K(s)}generateId(t="book",e="draft"){return this.idGen.nextIdRaw(e,t)}encodeId(t){return D(t)}decodeId(t){return k(t)}async saveItem(t,e,s="draft"){let n=t.id||t.ID;if(n)try{const o=j(n);e||(e=o.type)}catch{throw new L(`Invalid ID format: ${n}`)}else e||(e=t.type||"book"),n=this.idGen.nextId(s,e),t.id=n;return await this.storage.saveItem(e,n,t)}async getItem(t){return this.storage.getItem(t)}async findItemPath(t){return this.storage.findFileById(t)}async updateField(t,e,s){const n=await this.storage.findFileById(t);if(!n)return!1;try{const i=await this.storage.loadMetadata(n),o={基本信息:null,介绍:"description",资源:"resources",收藏历史:"history",其他版本:"related_books"},c=e in o?o[e]:e;if(c===null)return!1;if(c==="description"&&typeof s=="string"){const r=i[c]||{};i[c]={text:s,sources:r.sources||[]}}else i[c]=s;const l=j(t);return await this.storage.saveItem(l.type,t,i),!0}catch{return!1}}async deleteItem(t){return this.storage.deleteItem(t)}async rebuildIndices(){await this.storage.rebuildIndex("official"),await this.storage.rebuildIndex("draft")}getAssetDir(t){return this.storage.getAssetDir(t)}async initAssetDir(t){return this.storage.initAssetDir(t)}async hasAssetDir(t){return this.storage.hasAssetDir(t)}getStorage(){return this.storage}}const Gt={wikisource:"wikisource",shidianguji:"shidianguji",archive:"archive",ctext:"ctext",nlc:"nlc","read.nlc":"nlc","db.sido":"sido","guji.artx":"guji-artx","digital.library":"digital-library"},tt=new Set(["text","image","text+image","physical"]),et=new Set(["text","image","physical"]),qt=new Set(["catalog","search"]),Yt=new Set(["com","org","net","cn","edu","gov","io","jp","tw","hk"]);function Kt(a){if(!a)return"";try{const e=new URL(a).hostname;for(const[n,i]of Object.entries(Gt))if(e.includes(n))return i;const s=e.split(".");if(s.length>=2){const n=s.filter(i=>!Yt.has(i)&&i.length>2);return n.length>0?n[n.length-1]:s[s.length-2]}return e}catch{return""}}function Vt(a){const t=[];a.name||t.push("name is required");let e=!1;if(a.types!==void 0)if(!Array.isArray(a.types)||a.types.length===0)t.push("types must be a non-empty array when present");else{for(const s of a.types)et.has(s)||t.push(`invalid types atom '${s}', must be one of ${[...et].join(", ")}`);e=a.types.length===1&&a.types[0]==="physical"}else a.type!==void 0?(tt.has(a.type)||t.push(`invalid type '${a.type}', must be one of ${[...tt].join(", ")}`),e=a.type==="physical"):t.push("either type or types is required");return a.root_type&&!qt.has(a.root_type)&&t.push(`invalid root_type '${a.root_type}'`),!e&&!a.url&&t.push("url is required for non-physical resources"),t}const w=class w{constructor(t,e=""){if(this._type=null,this.title=e,typeof t=="string"){t.startsWith(w.PREFIX)&&(t=t.slice(w.PREFIX.length)),this.idStr=t;try{this.idInt=k(t)}catch{this.idInt=0n}}else this.idInt=t,this.idStr=D(t);if(this.idInt>0n)try{const s=j(this.idStr);this._type=s.type}catch{}}get type(){return this._type}getIcon(){return this._type===null?"":this._type==="book"?"📖 ":this._type==="collection"?"📚 ":this._type==="work"?"📜 ":""}render(t=!1){return`[${t?this.getIcon():""}${this.title}](${w.PREFIX}${this.idStr})`}static parseFromLink(t){const e=t.match(/\[(.*?)\]\((.*?)\)/);if(e){const s=e[1],n=e[2];if(n.startsWith(w.PREFIX)){const i=n.slice(w.PREFIX.length);return new w(i,s)}}return null}static isBidLink(t){return t.startsWith(w.PREFIX)}};w.PROTOCOL="bid:\\\\",w.PREFIX="bid:\\\\";let H=w;exports.BidLink=H;exports.BookIndexError=L;exports.BookIndexManager=Ht;exports.BookIndexStorage=q;exports.BundleStorage=Ut;exports.ConfigError=Wt;exports.GithubStorage=Dt;exports.IdGenerationError=Jt;exports.IdGenerator=K;exports.LocalStorage=Mt;exports.MigrationError=zt;exports.StorageError=Nt;exports.base36Decode=G;exports.base36Encode=D;exports.base58Decode=lt;exports.buildId=W;exports.decodeId=Et;exports.decodeIdString=j;exports.encodeId=vt;exports.extractIdFromUrl=Kt;exports.extractStatus=Ct;exports.extractType=ht;exports.normalizeCatalog=Y;exports.parseId=C;exports.smartDecode=k;exports.validateResource=Vt;
|