book-index-ui 0.2.11 → 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 +34 -0
- package/dist/index.js +1466 -1448
- package/dist/storage-entry-QB1IoDUU.cjs +1 -0
- package/dist/{storage-entry-Bfhi3hs7.js → storage-entry-UQLfmeLb.js} +350 -281
- package/dist/storage.cjs +1 -1
- package/dist/storage.d.ts +34 -0
- package/dist/storage.js +1 -1
- package/package.json +1 -1
- package/dist/storage-entry-DEouFxE1.cjs +0 -1
package/dist/storage.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./storage-entry-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./storage-entry-QB1IoDUU.cjs");exports.BidLink=r.BidLink;exports.BookIndexError=r.BookIndexError;exports.BookIndexManager=r.BookIndexManager;exports.BookIndexStorage=r.BookIndexStorage;exports.BundleStorage=r.BundleStorage;exports.ConfigError=r.ConfigError;exports.GithubStorage=r.GithubStorage;exports.IdGenerationError=r.IdGenerationError;exports.IdGenerator=r.IdGenerator;exports.LocalStorage=r.LocalStorage;exports.MigrationError=r.MigrationError;exports.StorageError=r.StorageError;exports.extractIdFromUrl=r.extractIdFromUrl;exports.validateResource=r.validateResource;
|
package/dist/storage.d.ts
CHANGED
|
@@ -221,6 +221,10 @@ export declare class BundleStorage implements IndexStorage {
|
|
|
221
221
|
private searchSCache;
|
|
222
222
|
private searchSLoading;
|
|
223
223
|
private searchSLoaded;
|
|
224
|
+
private metaCache;
|
|
225
|
+
private metaLoading;
|
|
226
|
+
/** null = 已尝试加载 meta.json 但失败/缺失(fallback 到 ensureLoaded) */
|
|
227
|
+
private metaTried;
|
|
224
228
|
private t2sConverter;
|
|
225
229
|
private t2sLoading;
|
|
226
230
|
/** 数据版本(commitId 前 12 位)。null=已尝试加载但失败;undefined=未加载 */
|
|
@@ -246,14 +250,24 @@ export declare class BundleStorage implements IndexStorage {
|
|
|
246
250
|
/** Load chunk for a specific ID using manifest-based prefix resolution */
|
|
247
251
|
private loadChunkForId;
|
|
248
252
|
private loadTiyaoGroup;
|
|
253
|
+
/**
|
|
254
|
+
* 获取轻量元数据(< 1 KB)。优先读 /data/meta.json;
|
|
255
|
+
* 若该文件不存在(旧 bundle),回退到 ensureLoaded 计算。
|
|
256
|
+
*/
|
|
257
|
+
getCounts(): Promise<IndexCounts>;
|
|
249
258
|
getResourceCounts(): Promise<{
|
|
250
259
|
hasText: number;
|
|
251
260
|
hasImage: number;
|
|
252
261
|
}>;
|
|
262
|
+
getSubtypeStats(): Promise<Record<string, number>>;
|
|
253
263
|
loadEntries(type: IndexType, options: LoadOptions): Promise<PageResult<IndexEntry>>;
|
|
254
264
|
search(query: string, type: IndexType, options: LoadOptions): Promise<PageResult<IndexEntry>>;
|
|
255
265
|
searchAll(query: string, limit?: number): Promise<GroupedSearchResult>;
|
|
256
266
|
getItem(id: string): Promise<Record<string, unknown> | null>;
|
|
267
|
+
/**
|
|
268
|
+
* 优先用 chunk 构造 IndexEntry,避免触发 ensureLoaded() 拉全量 index.json。
|
|
269
|
+
* 旧 bundle 没有把 has_collated 等字段注入 chunk 时回退到 ensureLoaded。
|
|
270
|
+
*/
|
|
257
271
|
getEntry(id: string): Promise<IndexEntry | null>;
|
|
258
272
|
getAllEntries(): Promise<IndexEntry[]>;
|
|
259
273
|
saveItem(): Promise<{
|
|
@@ -627,6 +641,18 @@ export declare class IdGenerator {
|
|
|
627
641
|
private _tilNextUnit;
|
|
628
642
|
}
|
|
629
643
|
|
|
644
|
+
declare interface IndexCounts {
|
|
645
|
+
works: number;
|
|
646
|
+
books: number;
|
|
647
|
+
collections: number;
|
|
648
|
+
entities: number;
|
|
649
|
+
resourceCounts?: {
|
|
650
|
+
hasText: number;
|
|
651
|
+
hasImage: number;
|
|
652
|
+
};
|
|
653
|
+
subtypeStats?: Record<string, number>;
|
|
654
|
+
}
|
|
655
|
+
|
|
630
656
|
/** 统一详情数据类型 */
|
|
631
657
|
export declare type IndexDetailData = BookDetailData | CollectionDetailData | WorkDetailData | EntityDetailData;
|
|
632
658
|
|
|
@@ -803,6 +829,14 @@ export declare interface IndexStorage {
|
|
|
803
829
|
}>;
|
|
804
830
|
/** 获取 Work subtype 细分统计 */
|
|
805
831
|
getSubtypeStats?(): Promise<Record<string, number>>;
|
|
832
|
+
/**
|
|
833
|
+
* 一次性获取索引规模 + 资源 + subtype 统计的轻量元数据。
|
|
834
|
+
*
|
|
835
|
+
* 用于代替 getAllEntries() / loadEntries(t,{page:1,pageSize:1}) ×4 等
|
|
836
|
+
* "为了几个数字下载整个 index" 的场景。BundleStorage 实现读取
|
|
837
|
+
* /data/meta.json(< 1 KB),其它实现可选。
|
|
838
|
+
*/
|
|
839
|
+
getCounts?(): Promise<IndexCounts>;
|
|
806
840
|
}
|
|
807
841
|
|
|
808
842
|
/** 索引类型 */
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as o, b as e, c as s, d as t, f as n, C as d, G as g, I as i, g as I, L as B, M as S, S as x, o as E, v as c } from "./storage-entry-
|
|
1
|
+
import { B as o, b as e, c as s, d as t, f as n, C as d, G as g, I as i, g as I, L as B, M as S, S as x, o as E, v as c } from "./storage-entry-UQLfmeLb.js";
|
|
2
2
|
export {
|
|
3
3
|
o as BidLink,
|
|
4
4
|
e as BookIndexError,
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
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},_t={0:"official",1:"draft"},wt={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 $(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:_t[t]??"draft",type:bt[e]??"book",timestamp:s,machineId:n,sequence:i}}function J(r,t,e,s,n){return BigInt(mt[r])<<st|BigInt(wt[t])<<nt|(e&rt)<<it|BigInt(s)<<ot|BigInt(n)}function j(r){return $(k(r))}function Et(r){return j(r).type}function $t(r){return j(r).status}const N={book:"Book",collection:"Collection",work:"Work",entity:"Entity"},At={Book:"book",Collection:"collection",Work:"work",Entity:"entity"},B=16;function W(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 Ct(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=$(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}-${Ct(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,Pt,2));const u=this.getRootById(e),h=c.substring(u.length+1);return await this.updateIndexEntry(u,s,t,h),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 u="";const h=e.publication_info;typeof h=="object"&&h!==null?u=h.year||"":typeof h=="string"&&(u=h);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 C=typeof e.measure_info=="string"?e.measure_info:"";let E=!1,x=!1;const L=e.resources;if(Array.isArray(L))for(const y of L){if(typeof y!="object"||y===null)continue;const _=y.types;if(Array.isArray(_))_.includes("text")&&(E=!0),_.includes("image")&&(x=!0);else{const A=y.type;(A==="text"||A==="text+image")&&(E=!0),(A==="image"||A==="text+image")&&(x=!0)}}const m={id:i,title:e.title||"未命名",type:N[s],path:n,author:l,year:u,holder:d};p&&p.length>0&&(m.additional_titles=p),I&&I.length>0&&(m.attached_texts=I),v&&(m.juan_count=v),C&&(m.measure_info=C);const P=typeof e.edition=="string"?e.edition:"";P&&(m.edition=P),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=$(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 u=(await this.fs.readdir(l)).find(h=>h.startsWith(`${t}-`)&&h.endsWith(".json"));if(u)return b(l,u)}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=`${At[o]}s`,u=await this.fs.glob(c,"**/*.json");for(const h of u)if(!h.includes("/index/"))try{const d=await this.loadMetadata(h);let f=d.id||d.ID||"";if(!f){const g=h.substring(h.lastIndexOf("/")+1);g.includes("-")&&(f=g.split("-")[0])}if(!f)continue;const p=h.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,C=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 L=typeof d.measure_info=="string"?d.measure_info:"";let m=!1,P=!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")&&(P=!0);else{const R=g.type;(R==="text"||R==="text+image")&&(m=!0),(R==="image"||R==="text+image")&&(P=!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),C&&C.length>0&&(_.attached_texts=C),E&&(_.juan_count=E),L&&(_.measure_info=L);const A=typeof d.edition=="string"?d.edition:"";A&&(_.edition=A),m&&(_.has_text=!0),P&&(_.has_image=!0);const ht=a==="collections"?0:W(f);s[a][ht][f]=_}catch{}}for(const[o,c]of Object.entries(s))for(const[l,a]of Object.entries(c)){const u=this.shardPath(e,o,Number(l)),h=u.substring(0,u.lastIndexOf("/"));await this.fs.mkdir(h),await this.fs.writeFile(u,JSON.stringify(a,null,2))}}getAssetDir(t){const e=this.getRootById(t),s=k(t),i=$(s).type,o=t.padEnd(3,"_").substring(0,3),[c,l,a]=[o[0],o[1],o[2]],u=N[i];return b(e,u,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=W(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=W(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 u=a.toLowerCase();u===e?s=Math.max(s,120):u.startsWith(e)?s=Math.max(s,90):u.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 Pt(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 jt(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(jt),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 Lt="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??Lt,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 u of Object.values(a)){const h=u,d=l==="entity"?h.primary_name||u.title||u.name||u.id:u.title||u.name||u.id;s.push({id:u.id,title:d,type:l,isDraft:e,author:u.author,dynasty:u.dynasty,role:u.role,path:u.path,additional_titles:(i=h.additional_titles)==null?void 0:i.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),attached_texts:(o=h.attached_texts)==null?void 0:o.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),edition:h.edition,juan_count:h.juan_count,has_text:h.has_text,has_image:h.has_image,has_collated:h.has_collated,subtype:h.subtype,primary_name:h.primary_name,birth_year:h.birth_year,death_year:h.death_year,cbdb_id:h.cbdb_id}),this.pathMap.set(u.id,{path:u.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((u,h)=>u!==o.additional_titles[h])&&(c.at=a)}if((i=o.attached_texts)!=null&&i.length){const a=o.attached_texts.map(e);a.some((u,h)=>u!==o.attached_texts[h])&&(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(h=>h.type===t);const i=e.sortBy||"title",o=e.sortOrder||"asc";n.sort((h,d)=>{const f=String(h[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,u=Object.keys(i).length>0?O(c,t,l,i):F(c,t),h=s.page||1,d=s.pageSize||50,f=(h-1)*d;return{entries:u.slice(f,f+d),total:u.length,page:h,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(u=>{const h=s.filter(d=>d.type===u);return l?O(h,t,c,n):F(h,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 u=$(k(t));s=u.type,n=u.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 u=await fetch(a,{signal:AbortSignal.timeout(this.config.timeout)});if(!u.ok)return null;const d=(await u.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=$(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=J(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,J(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 $(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((u,h)=>{const d=u[l]??"",f=h[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.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 u=c==="entity"?a.primary_name||a.title||a.name||a.id:a.title||a.name||a.id;e.push({id:a.id,title:u,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(h=>typeof h=="string"?h:h==null?void 0:h.book_title).filter(Boolean),attached_texts:(i=a.attached_texts)==null?void 0:i.map(h=>typeof h=="string"?h:h==null?void 0:h.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 getResourceCounts(){const t=await this.ensureLoaded();let e=0,s=0;for(const n of t)n.type==="work"&&(n.has_text&&e++,n.has_image&&s++);return{hasText:e,hasImage:s}}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,h)=>{const d=String(u[i]??""),f=String(h[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,u=Object.keys(i).length>0?O(c,t,l,i):F(c,t),h=s.page||1,d=s.pageSize||50,f=(h-1)*d;return{entries:u.slice(f,f+d),total:u.length,page:h,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(u=>{const h=s.filter(d=>d.type===u);return l?O(h,t,c,n):F(h,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.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 Wt extends T{constructor(t){super(t),this.name="IdGenerationError"}}class Jt 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=j(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=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(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 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=M(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=T;exports.BookIndexManager=Ht;exports.BookIndexStorage=q;exports.BundleStorage=Ut;exports.ConfigError=Jt;exports.GithubStorage=Mt;exports.IdGenerationError=Wt;exports.IdGenerator=K;exports.LocalStorage=Rt;exports.MigrationError=zt;exports.StorageError=Nt;exports.base36Decode=G;exports.base36Encode=M;exports.base58Decode=lt;exports.buildId=J;exports.decodeId=vt;exports.decodeIdString=j;exports.encodeId=xt;exports.extractIdFromUrl=Kt;exports.extractStatus=$t;exports.extractType=Et;exports.normalizeCatalog=Y;exports.parseId=$;exports.smartDecode=k;exports.validateResource=Vt;
|