book-index-ui 0.6.0 → 0.6.2

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.d.ts CHANGED
@@ -337,6 +337,15 @@ export declare class BookIndexStorage {
337
337
  hasAssetDir(idStr: string): Promise<boolean>;
338
338
  private shardPath;
339
339
  private loadShard;
340
+ /**
341
+ * 探测既有 shard 的缩进宽度,新文件用 2。
342
+ *
343
+ * 仓库里各 shard 缩进并不统一(book-index-draft 的 index/works、index/entities
344
+ * 是 1,其余与 production 全仓是 2),历史上由不同脚本写成。一律按 2 重写会
345
+ * 把整个 shard 重排——七万余条的 works shard 会产生数十万行 diff,淹掉真正的改动。
346
+ * 与 Python 端 BookIndexStorage._detect_shard_indent 保持一致。
347
+ */
348
+ private detectShardIndent;
340
349
  private saveShard;
341
350
  private loadAllShards;
342
351
  }
@@ -413,10 +422,13 @@ export declare class BundleStorage implements IndexStorage {
413
422
  /** 数据版本(commitId 前 12 位)。null=已尝试加载但失败;undefined=未加载 */
414
423
  private version;
415
424
  private versionPromise;
425
+ /** true=版本号由外部注入(config.version),clearCache() 不应清掉它 */
426
+ private versionInjected;
416
427
  constructor(config?: BundleStorageConfig);
417
428
  /**
418
429
  * 强制 revalidate 拉取 /data/version.json,作为所有其他 fetch 的 cache key。
419
430
  * 失败/缺失时回退为不拼 version(退化为旧行为)。
431
+ * 若构造时已通过 config.version 注入版本号,直接用它,不再自己 fetch。
420
432
  */
421
433
  private ensureVersion;
422
434
  private fetchJson;
@@ -472,6 +484,18 @@ export declare interface BundleStorageConfig {
472
484
  basePath?: string;
473
485
  /** 请求超时(毫秒),默认 10000 */
474
486
  timeout?: number;
487
+ /**
488
+ * 外部已解析好的数据版本(commitId 前 12 位),传入后 ensureVersion() 不再
489
+ * 自己去 fetch `${basePath}/version.json`。
490
+ *
491
+ * cos 模式下 basePath 指向 COS 的 current/ 子目录,而 current/* 的所有文件
492
+ * 都被 CDN 打了 immutable/max-age=31536000 长缓存——包括 version.json 本身。
493
+ * 自己 fetch 只会长期卡在第一次被缓存住的旧版本(实测滞后 9+ 天),且
494
+ * `cache: 'no-cache'` 对 immutable 资源无效,浏览器根本不会发出请求。
495
+ * 版本号的权威来源是 COS 根目录的 latest.json(不缓存),调用方应该在那里
496
+ * 解析好版本号后通过这个字段注入,而不是让 BundleStorage 自己猜。
497
+ */
498
+ version?: string | null;
475
499
  }
476
500
 
477
501
  /** 四库总目等分类目录数据 */
@@ -1405,6 +1429,16 @@ export declare interface IndexFileEntry {
1405
1429
  measure_info?: string;
1406
1430
  has_text?: boolean;
1407
1431
  has_image?: boolean;
1432
+ subtype?: string;
1433
+ /** 粗粒度时代轴,选集合用(SCHEMA.md §period) */
1434
+ period?: string;
1435
+ /** 存佚 */
1436
+ loss_status?: string;
1437
+ original_title?: string;
1438
+ /** Book → Work 反向链 */
1439
+ work_id?: string;
1440
+ /** tombstone:已升级到的 production id */
1441
+ promoted_to?: string;
1408
1442
  }
1409
1443
 
1410
1444
  /** 索引数据源 */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { e as Mn, a as ho } from "./storage-entry-BrRCOVK7.js";
2
- import { B as xa, b as ya, c as va, d as ka, f as Sa, C as wa, G as _a, I as za, g as Ca, L as Ia, M as Ta, S as Ra, h as La, i as Ba, j as Ea, k as Wa, l as $a, m as Aa, n as Pa, o as Ma, p as Ha, q as Oa, r as ja, s as Fa, t as Da, u as Na, v as Ua } from "./storage-entry-BrRCOVK7.js";
1
+ import { e as Mn, a as ho } from "./storage-entry-DJXViIHU.js";
2
+ import { B as xa, b as ya, c as va, d as ka, f as Sa, C as wa, G as _a, I as za, g as Ca, L as Ia, M as Ta, S as Ra, h as La, i as Ba, j as Ea, k as Wa, l as $a, m as Aa, n as Pa, o as Ma, p as Ha, q as Oa, r as ja, s as Fa, t as Da, u as Na, v as Ua } from "./storage-entry-DJXViIHU.js";
3
3
  import { jsx as t, jsxs as i, Fragment as O } from "react/jsx-runtime";
4
4
  import pt, { createContext as Hn, useMemo as ue, useContext as ut, useState as z, useEffect as $, useCallback as F, useRef as ie } from "react";
5
5
  import bo from "react-markdown";
@@ -0,0 +1,2 @@
1
+ "use strict";var _t=Object.create;var et=Object.defineProperty;var wt=Object.getOwnPropertyDescriptor;var bt=Object.getOwnPropertyNames;var kt=Object.getPrototypeOf,It=Object.prototype.hasOwnProperty;var xt=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of bt(t))!It.call(r,n)&&n!==e&&et(r,n,{get:()=>t[n],enumerable:!(s=wt(t,n))||s.enumerable});return r};var vt=(r,t,e)=>(e=r!=null?_t(kt(r)):{},xt(t||!r||!r.__esModule?et(e,"default",{value:r,enumerable:!0}):e,r));const St={official:0,draft:1},Et={0:"official",1:"draft"},$t={book:0,collection:2,work:3,entity:4},At={0:"book",2:"collection",3:"work",4:"entity"},ct=62n,lt=59n,ht=19n,ut=8n,dt=(1n<<40n)-1n,Pt=(1n<<3n)-1n,jt=(1n<<11n)-1n,Ct=(1n<<8n)-1n,W="0123456789abcdefghijklmnopqrstuvwxyz",ft=new Map;for(let r=0;r<W.length;r++)ft.set(W[r],BigInt(r));function U(r){if(r===0n)return W[0];let t="";for(;r>0n;)t=W[Number(r%36n)]+t,r=r/36n;return t}function V(r){let t=0n;for(const e of r){const s=ft.get(e);if(s===void 0)throw new Error(`Invalid Base36 character: ${e}`);t=t*36n+s}return t}const st="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",yt=new Map;for(let r=0;r<st.length;r++)yt.set(st[r],BigInt(r));function gt(r){let t=0n;for(const e of r){const s=yt.get(e);if(s===void 0)throw new Error(`Invalid Base58 character: ${e}`);t=t*58n+s}return t}function I(r){return/[A-Z]/.test(r)?gt(r):V(r)}const Tt=U,Bt=V;function A(r){const t=Number(r>>ct&1n),e=Number(r>>lt&Pt),s=r>>ht&dt,n=Number(r>>ut&jt),o=Number(r&Ct);return{status:Et[t]??"draft",type:At[e]??"book",timestamp:s,machineId:n,sequence:o}}function q(r,t,e,s,n){return BigInt(St[r])<<ct|BigInt($t[t])<<lt|(e&dt)<<ht|BigInt(s)<<ut|BigInt(n)}function B(r){return A(I(r))}function pt(r){return B(r).type}function Ft(r){return B(r).status}const H={book:"Book",collection:"Collection",work:"Work",entity:"Entity"},Lt={Book:"book",Collection:"collection",Work:"work",Entity:"entity"},D=16;function J(r,t=D){let e=0;for(let s=0;s<r.length;s++)e=Math.imul(e,31)+r.charCodeAt(s)>>>0;return e%t}function k(...r){const t=r.join("/");return t.startsWith("//")?"//"+t.slice(2).replace(/\/+/g,"/"):t.replace(/\/+/g,"/")}function mt(r){return r.replace(/[^㐀-䶿一-鿿豈-﫿a-zA-Z0-9\u{20000}-\u{3134f}]/gu,"")||"Undefined"}class X{constructor(t,e){this.fs=t,this.officialRoot=k(e,"book-index"),this.draftRoot=k(e,"book-index-draft")}getRootByStatus(t){return t==="draft"?this.draftRoot:this.officialRoot}getRootById(t){const e=I(t),s=A(e);return this.getRootByStatus(s.status)}getPath(t,e,s){const n=this.getRootById(e),o=e.padEnd(3,"_").substring(0,3),[i,c,a]=[o[0],o[1],o[2]],l=H[t];return k(n,l,i,c,a,`${e}-${mt(s)}.json`)}async saveItem(t,e,s){const n=s.title||s.书名||"未命名",o=s.edition||"",i=o?`${n}${o}`:n,c=this.getPath(t,e,i),a=await this.findFileById(e);if(a&&a!==c)try{await this.fs.deleteFile(a)}catch{}const l=c.substring(0,c.lastIndexOf("/"));await this.fs.mkdir(l),s.id=e,s.type=t,await this.fs.writeFile(c,JSON.stringify(s,Mt,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 o=e.id||"";if(!o)return;const i=`${s}s`,c=await this.loadShard(t,i,o);let a="",l="",u="";const h=e.authors;if(Array.isArray(h)&&h.length>0){const g=h[0];typeof g=="object"&&g!==null?(a=g.name||"",l=g.dynasty||"",u=g.role||""):a=String(g)}else typeof h=="string"&&(a=h);!l&&typeof e.dynasty=="string"&&(l=e.dynasty);let d="";const f=e.publication_info;typeof f=="object"&&f!==null?d=f.year||"":typeof f=="string"&&(d=f);let _="";const w=e.current_location;typeof w=="object"&&w!==null?_=w.name||"":typeof w=="string"&&(_=w);const x=Array.isArray(e.additional_titles)?e.additional_titles.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0,P=Array.isArray(e.attached_texts)?e.attached_texts.map(g=>typeof g=="string"?g:g==null?void 0:g.book_title).filter(Boolean):void 0;let E;const v=e.juan_count;typeof v=="number"?E=v:typeof v=="object"&&v!==null&&(E=v.number||void 0);const j=typeof e.measure_info=="string"?e.measure_info:"";let $=!1,S=!1;const L=e.resources;if(Array.isArray(L))for(const g of L){if(typeof g!="object"||g===null)continue;const G=g.types;if(Array.isArray(G))G.includes("text")&&($=!0),G.includes("image")&&(S=!0);else{const N=g.type;(N==="text"||N==="text+image")&&($=!0),(N==="image"||N==="text+image")&&(S=!0)}}const p={id:o,title:e.title||"未命名",type:H[s],path:n,author:a,year:d,holder:_};x&&x.length>0&&(p.additional_titles=x),P&&P.length>0&&(p.attached_texts=P),E&&(p.juan_count=E),j&&(p.measure_info=j);const C=typeof e.edition=="string"?e.edition:"";C&&(p.edition=C),$&&(p.has_text=!0),S&&(p.has_image=!0),l&&(p.dynasty=l),u&&(p.role=u);const M=typeof e.subtype=="string"?e.subtype:"";M&&(p.subtype=M);const m=typeof e.period=="string"?e.period:"";m&&(p.period=m);const R=typeof e.loss_status=="string"?e.loss_status:"";R&&(p.loss_status=R);const O=typeof e.original_title=="string"?e.original_title:"";O&&(p.original_title=O);const y=typeof e.work_id=="string"?e.work_id:"";y&&(p.work_id=y);const T=typeof e._promoted_to=="string"?e._promoted_to:typeof e.promoted_to=="string"?e.promoted_to:"";T&&(p.promoted_to=T),c[o]=p,await this.saveShard(t,i,o,c)}async deleteItem(t){const e=await this.findFileById(t);if(!e)return!1;const s=I(t),n=A(s),o=this.getRootByStatus(n.status),i=`${n.type}s`,c=await this.loadShard(o,i,t);return c[t]&&(delete c[t],await this.saveShard(o,i,t,c)),await this.fs.deleteFile(e),!0}async findFileById(t){const e=t.padEnd(3,"_").substring(0,3),[s,n,o]=[e[0],e[1],e[2]];for(const i of[this.officialRoot,this.draftRoot])for(const c of["Book","Collection","Work"]){const a=k(i,c,s,n,o);if(await this.fs.exists(a))try{const u=(await this.fs.readdir(a)).find(h=>h.startsWith(`${t}-`)&&h.endsWith(".json"));if(u)return k(a,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=[],o=`${t}s`;for(const i of s){const c=await this.loadAllShards(i,o);for(const[a,l]of Object.entries(c))n.push({id:a,title:l.title,type:t,author:l.author||void 0,dynasty:l.dynasty||void 0,role:l.role||void 0,path:k(i,l.path),additional_titles:l.additional_titles,attached_texts:l.attached_texts,edition:l.edition,juan_count:l.juan_count,has_text:l.has_text,has_image:l.has_image})}return n}async searchEntries(t,e,s){const n=await this.loadEntries(e,s);return Y(n,t)}async searchAll(t,e=5,s){const n=["work","book","collection"],o=await Promise.all(n.map(i=>this.searchEntries(t,i,s)));return{works:o[0].slice(0,e),books:o[1].slice(0,e),collections:o[2].slice(0,e),totalWorks:o[0].length,totalBooks:o[1].length,totalCollections:o[2].length}}async rebuildIndex(t){var n,o;const e=this.getRootByStatus(t),s={books:Object.fromEntries(Array.from({length:D},(i,c)=>[c,{}])),collections:{0:{}},works:Object.fromEntries(Array.from({length:D},(i,c)=>[c,{}]))};for(const i of["Book","Collection","Work"]){const c=k(e,i);if(!await this.fs.exists(c))continue;const l=`${Lt[i]}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 y=h.substring(h.lastIndexOf("/")+1);y.includes("-")&&(f=y.split("-")[0])}if(!f)continue;const _=h.substring(e.length+1);let w="",x="",P="";const E=d.authors;if(Array.isArray(E)&&E.length>0){const y=E[0];typeof y=="object"&&y!==null?(w=y.name||"",x=y.dynasty||"",P=y.role||""):w=String(y)}!x&&typeof d.dynasty=="string"&&(x=d.dynasty);const v=Array.isArray(d.additional_titles)?d.additional_titles.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0,j=Array.isArray(d.attached_texts)?d.attached_texts.map(y=>typeof y=="string"?y:y==null?void 0:y.book_title).filter(Boolean):void 0;let $;const S=d.juan_count;typeof S=="number"?$=S:typeof S=="object"&&S!==null&&($=S.number||void 0);const L=typeof d.measure_info=="string"?d.measure_info:"";let p=!1,C=!1;const M=d.resources;if(Array.isArray(M))for(const y of M){if(typeof y!="object"||y===null)continue;const T=y.types;if(Array.isArray(T))T.includes("text")&&(p=!0),T.includes("image")&&(C=!0);else{const g=y.type;(g==="text"||g==="text+image")&&(p=!0),(g==="image"||g==="text+image")&&(C=!0)}}const m={id:f,title:d.title||"未命名",type:i,path:_,author:w,year:typeof d.publication_info=="object"&&((n=d.publication_info)==null?void 0:n.year)||"",holder:typeof d.current_location=="object"&&((o=d.current_location)==null?void 0:o.name)||""};v&&v.length>0&&(m.additional_titles=v),j&&j.length>0&&(m.attached_texts=j),$&&(m.juan_count=$),L&&(m.measure_info=L);const R=typeof d.edition=="string"?d.edition:"";R&&(m.edition=R),p&&(m.has_text=!0),C&&(m.has_image=!0),x&&(m.dynasty=x),P&&(m.role=P);const O=l==="collections"?0:J(f);s[l][O][f]=m}catch{}}for(const[i,c]of Object.entries(s))for(const[a,l]of Object.entries(c)){const u=this.shardPath(e,i,Number(a)),h=u.substring(0,u.lastIndexOf("/"));await this.fs.mkdir(h),await this.fs.writeFile(u,JSON.stringify(nt(l),null,await this.detectShardIndent(u)))}}getAssetDir(t){const e=this.getRootById(t),s=I(t),o=A(s).type,i=t.padEnd(3,"_").substring(0,3),[c,a,l]=[i[0],i[1],i[2]],u=H[o];return k(e,u,c,a,l,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"?k(t,"index","collections.json"):k(t,"index",e,`${s.toString(16)}.json`)}async loadShard(t,e,s){const n=J(s),o=this.shardPath(t,e,n);try{if(!await this.fs.exists(o))return{};const i=await this.fs.readFile(o);return JSON.parse(i)}catch{return{}}}async detectShardIndent(t,e=2){try{if(!await this.fs.exists(t))return e;const n=(await this.fs.readFile(t)).split(`
2
+ `)[1];if(n===void 0)return e;const o=n.replace(/^ +/,"");return!o||o.startsWith("}")?e:n.length-o.length||e}catch{return e}}async saveShard(t,e,s,n){const o=J(s),i=this.shardPath(t,e,o),c=i.substring(0,i.lastIndexOf("/"));await this.fs.mkdir(c);const a=await this.detectShardIndent(i);await this.fs.writeFile(i,JSON.stringify(nt(n),null,a))}async loadAllShards(t,e){const s={};if(e==="collections"){const n=this.shardPath(t,e,0);try{if(await this.fs.exists(n)){const o=await this.fs.readFile(n);Object.assign(s,JSON.parse(o))}}catch{}return s}for(let n=0;n<D;n++){const o=this.shardPath(t,e,n);try{if(await this.fs.exists(o)){const i=await this.fs.readFile(o);Object.assign(s,JSON.parse(i))}}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 o=[...r.additional_titles||[],...r.attached_texts||[]];for(const l of o){const u=l.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 i=0;if(r.author){const l=r.author.toLowerCase();l===e?i=80:l.includes(e)&&(i=50)}let c=0;r.dynasty&&r.dynasty.toLowerCase().includes(e)&&(c=30);let a=s;return a===0&&(a=Math.max(i,c)),a===0?0:(a+=Math.max(0,20-n.length),r.type==="work"?a=Math.round(a*1.05):r.type==="collection"&&(a=Math.round(a*1.02)),r.has_text&&(a+=3),r.has_image&&(a+=2),a)}function nt(r){const t={};for(const e of Object.keys(r).sort())t[e]=r[e];return t}function Mt(r,t){return t===null?void 0:t}function Y(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 ot(r,t,e,s){const n=r.map(o=>{const i=z(o,t);let c=0;const a=s[o.id];if(a&&e){const l={...o,title:a.t??o.title,author:a.a??o.author,additional_titles:a.at??o.additional_titles,attached_texts:a.axt??o.attached_texts};c=z(l,e)}return{entry:o,score:Math.max(i,c)}}).filter(o=>o.score>0);return n.sort((o,i)=>i.score!==o.score?i.score-o.score:o.entry.title.length-i.entry.title.length),n.map(o=>o.entry)}function Rt(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 o of t){const i=o.volume;e.push(i);const c={};for(const[a,l]of Object.entries(o))a==="volume"||a==="status"||a==="file"||typeof l=="string"&&(a.includes("url")||a.includes("id"))&&(c[a]=l);s.push({volume:i,status:o.status,urls:Object.keys(c).length>0?c:void 0,file:o.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 o of Object.keys(n))n[o]===void 0&&delete n[o];return n}function Dt(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 Q(r){var n;const t=r,e=(t.books??[]).map(Rt),s={collection_id:t.collection_id??"",title:t.title??"",total_volumes:t.total_volumes??0,stats:Dt(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}function Z(r){const t=new Map;if(!r||typeof r!="object")return t;const e=r;if(typeof e.version!="number")return console.warn("[promotions] missing version field; treating as empty"),t;if(e.version!==1)return console.warn(`[promotions] unknown version ${e.version}; treating as empty`),t;const s=e.promotions;if(!s||typeof s!="object")return t;for(const[n,o]of Object.entries(s))o&&typeof o=="object"&&typeof o.production_id=="string"&&t.set(n,o.production_id);return t}const Ut="https://raw.githubusercontent.com",Ot=["https://fastly.jsdelivr.net/gh","https://cdn.jsdelivr.net/gh"],Nt=5e3;class Jt{constructor(t){this.cache=null,this.cacheLoading=null,this.pathMap=new Map,this.promotions=new Map,this.searchSCache=null,this.t2sConverter=null,this.config={org:t.org,repos:t.repos,baseUrl:t.baseUrl??Ut,cdnUrls:t.cdnUrls??Ot,timeout:t.timeout??Nt}}async fetchPromotions(){try{const t=await this.fetchFileWithFallback(this.config.repos.draft,"promotions.json");return Z(t)}catch{return new Map}}async ensureLoaded(){if(this.cache)return this.cache;if(this.cacheLoading)return this.cacheLoading;this.cacheLoading=(async()=>{const[t,e,s]=await Promise.all([this.fetchPromotions(),this.fetchIndex(this.config.repos.draft).catch(i=>(console.warn("Failed to fetch draft index:",i),{books:{},collections:{},works:{}})),this.fetchIndex(this.config.repos.official).catch(i=>(console.warn("Failed to fetch official index:",i),{books:{},collections:{},works:{}}))]);this.promotions=t;const n=[...this.parseIndexResponse(e,!0),...this.parseIndexResponse(s,!1)],o=new Map;for(const i of n)i.isDraft&&i.promoted_to||o.set(i.id,i);return this.cache=Array.from(o.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 o=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(o)}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 i of this.config.cdnUrls){const c=`${i}/${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",o=`${this.config.baseUrl}/${this.config.org}/${t}/main/${encodeURI(n)}`;try{if((await fetch(o,{method:"HEAD",signal:AbortSignal.timeout(this.config.timeout)})).ok)return!0}catch{}for(const i of this.config.cdnUrls){const c=`${i}/${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 o=await this.fetchFileWithFallback(t,"index/collections.json");s.collections=o}catch{}const n=[];for(const o of["books","works"])for(let i=0;i<D;i++){const c=`index/${o}/${i.toString(16)}.json`;n.push(this.fetchFileWithFallback(t,c).then(a=>{Object.assign(s[o],a)}).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 o,i;const s=[],n=[["books","book"],["collections","collection"],["works","work"],["entities","entity"]];for(const[c,a]of n){const l=t[c];if(l)for(const u of Object.values(l)){const h=u,d=a==="entity"?h.primary_name||u.title||u.name||u.id:u.title||u.name||u.id;s.push({id:u.id,title:d,type:a,isDraft:e,author:u.author,dynasty:u.dynasty,role:u.role,path:u.path,additional_titles:(o=h.additional_titles)==null?void 0:o.map(f=>typeof f=="string"?f:f==null?void 0:f.book_title).filter(Boolean),attached_texts:(i=h.attached_texts)==null?void 0:i.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,promoted_to:h.promoted_to}),this.pathMap.set(u.id,{path:u.path,isDraft:e})}}return s}async ensureSearchSBuilt(){var n,o;if(this.searchSCache)return{searchS:this.searchSCache,converter:this.t2sConverter||null};if(this.t2sConverter===!1)return{searchS:{},converter:null};try{const i=await import("opencc-js");this.t2sConverter=i.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 i of t){const c={},a=e(i.title);if(a!==i.title&&(c.t=a),i.author){const l=e(i.author);l!==i.author&&(c.a=l)}if((n=i.additional_titles)!=null&&n.length){const l=i.additional_titles.map(e);l.some((u,h)=>u!==i.additional_titles[h])&&(c.at=l)}if((o=i.attached_texts)!=null&&o.length){const l=i.attached_texts.map(e);l.some((u,h)=>u!==i.attached_texts[h])&&(c.axt=l)}Object.keys(c).length>0&&(s[i.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 o=e.sortBy||"title",i=e.sortOrder||"asc";n.sort((h,d)=>{const f=String(h[o]??""),_=String(d[o]??""),w=f.localeCompare(_,"zh");return i==="asc"?w:-w});const c=e.page||1,a=e.pageSize||50,l=(c-1)*a;return{entries:n.slice(l,l+a),total:n.length,page:c,pageSize:a}}async search(t,e,s){const n=await this.ensureLoaded(),{searchS:o,converter:i}=await this.ensureSearchSBuilt(),c=n.filter(_=>_.type===e),a=i?i(t):void 0,u=Object.keys(o).length>0?ot(c,t,a,o):Y(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:o}=await this.ensureSearchSBuilt(),i=["work","book","collection"],c=o?o(t):void 0,a=Object.keys(n).length>0,l=i.map(u=>{const h=s.filter(d=>d.type===u);return a?ot(h,t,c,n):Y(h,t)});return{works:l[0].slice(0,e),books:l[1].slice(0,e),collections:l[2].slice(0,e),totalWorks:l[0].length,totalBooks:l[1].length,totalCollections:l[2].length}}async getItem(t){const e=await this.ensureLoaded(),s=this.promotions.get(t)??t,n=s!==t?t:void 0,o=this.pathMap.get(s);let i=null;if(o){const c=o.isDraft?this.config.repos.draft:this.config.repos.official;if(i=await this.fetchItemByPath(c,o.path),i){const a=e.find(l=>l.id===s);a!=null&&a.has_collated&&(i.has_collated=!0)}}else i=await this.findItemById(s);return i&&i.type==="entity"&&!i.title&&i.primary_name&&(i.title=i.primary_name),i&&n&&(i.redirected_from=n),i}async getEntry(t){const e=await this.ensureLoaded(),s=this.promotions.get(t)??t,n=s!==t?t:void 0,o=e.find(a=>a.id===s);if(o)return n?{...o,redirected_from:n}:o;const i=await this.findItemById(s);if(!i)return null;const c=this.buildEntryFromItem(s,i);return n?{...c,redirected_from:n}:c}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 o of this.config.cdnUrls){const i=`${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{s=await this.fetchJson(i);break}catch{continue}}return s}async findItemById(t){const e={book:"Book",collection:"Collection",work:"Work",entity:"Entity"};let s,n;try{const u=A(I(t));s=u.type,n=u.status}catch{return null}const o=n==="draft"?this.config.repos.draft:this.config.repos.official,i=e[s],c=t.padEnd(3,"_").substring(0,3),a=`${i}/${c[0]}/${c[1]}/${c[2]}`,l=`https://api.github.com/repos/${this.config.org}/${o}/contents/${a}`;try{const u=await fetch(l,{signal:AbortSignal.timeout(this.config.timeout)});if(!u.ok)return null;const d=(await u.json()).find(_=>_.name.startsWith(`${t}-`)&&_.name.endsWith(".json"));if(!d)return null;const f=await this.fetchItemByPath(o,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 o;const i=e.authors;if(Array.isArray(i)&&i.length>0){const l=i[0];o=typeof l=="object"&&l!==null?l.name||"":String(l)}let c=!0;try{c=A(I(t)).status==="draft"}catch{}const a=this.pathMap.get(t);return{id:t,title:e.title||e.书名||t,type:n,isDraft:c,author:o,dynasty:e.dynasty,role:e.role,path:(a==null?void 0:a.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 o=`${n}/${this.config.org}/${t}@main/${encodeURI(e)}`;try{return await this.fetchJson(o)}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 o=[];for(const i of n){const c=`${e.dir}/${t}/${i.id}/volume_book_mapping.json`,a=await this.fetchFile(e.repo,c);a&&o.push({resource_id:i.id,short_name:i.short_name,data:Q(a)})}return o.length>0?o: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`,n=await this.fetchFile(e.repo,`${s}/index.json`);return n||this.fetchFile(e.repo,`${s}/collated_edition_index.json`)}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 getLineageGraph(t){const e=await this.resolveItemPath(t);if(!e)return null;const s=`${e.dir}/${t}/lineage_graph.json`;return this.fetchFile(e.repo,s)}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 it=255;class tt{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&it,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t;const n=q(t,e,BigInt(s),this.machineId,this.sequence);return U(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&it,this.sequence===0&&(s=this._tilNextUnit(this.lastTimestamp,t))):this.sequence=0,this.lastTimestamp=s,this.lastStatus=t,q(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 Wt{constructor(t){this.recentEntities=[],this.storage=new X(t.fs,t.workspaceRoot),this.idGen=new tt(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 o=await this.resolveEntity(e.work_id);o&&(s.belongsToWork={...o,type:"work"})}if(e.contained_in&&Array.isArray(e.contained_in)&&e.contained_in.length>0){const o=e.contained_in[0],i=typeof o=="string"?o:o.id;if(i){const c=await this.resolveEntity(i);c&&(s.belongsToCollection={...c,type:"collection"})}}}else if(n==="collection"){if(e.books&&Array.isArray(e.books)){const o=await Promise.all(e.books.map(i=>this.resolveEntity(i)));s.containedBooks=o.filter(i=>i!==null).map(i=>({...i,type:"book"}))}}else if(n==="work"){if(e.parent_work&&typeof e.parent_work=="object"){const o=e.parent_work;s.parentWork={id:o.id,title:o.title,type:"work"}}if(e.books&&Array.isArray(e.books)){const o=await Promise.all(e.books.map(i=>this.resolveEntity(i)));s.containedBooks=o.filter(i=>i!==null).map(i=>({...i,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 o=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 i=n.contained_in;i.some(a=>(typeof a=="string"?a:a.id)===s)||i.push({id:s})}break;case"parentWork":case"parent_work":{const i=await this.storage.getItem(s);n.parent_work={id:s,title:(i==null?void 0:i.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(o,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),o={id:n,type:s.type,title:s.title,...s.inheritData||{}};return await this.storage.saveItem(s.type,n,o),await this.linkEntity(t,e,n),{id:n}}async searchEntities(t,e){const s=e&&e!=="all"?[e]:["book","collection","work"],n=[];for(const o of s){const i=await this.storage.searchEntries(t,o);for(const c of i)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 o=await this.storage.loadMetadata(n);return Object.keys(o).length===0?null:o}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=I(t);return A(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 a=e.sortBy,l=e.sortOrder==="desc"?-1:1;t.sort((u,h)=>{const d=u[a]??"",f=h[a]??"";return d<f?-l:d>f?l:0})}const o=t.length,i=(s-1)*n;return{entries:t.slice(i,i+n),total:o,page:s,pageSize:n}}}const Gt="/data",Ht=1e4;class qt{constructor(t={}){this.chunkCache=new Map,this.chunkLoading=new Map,this.manifest=null,this.manifestLoading=null,this.tiyaoCache=new Map,this.tiyaoLoading=new Map,this.metaCache=null,this.metaLoading=null,this.promotions=null,this.promotionsLoading=null,this.versionPromise=null,this.versionInjected=!1,this.basePath=t.basePath??Gt,this.timeout=t.timeout??Ht,t.version!==void 0&&(this.version=t.version??null,this.versionInjected=!0)}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,{cache:"no-cache",signal:AbortSignal.timeout(this.timeout)});if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);return n.json()}async ensurePromotions(){if(this.promotions)return this.promotions;if(this.promotionsLoading)return this.promotionsLoading;this.promotionsLoading=(async()=>{try{const t=await this.fetchJson(`${this.basePath}/promotions.json`);this.promotions=Z(t)}catch{this.promotions=new Map}return this.promotions})();try{return await this.promotionsLoading}finally{this.promotionsLoading=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,o=null;for(;s<=n;){const i=s+n>>1;e[i]<=t?(o=e[i],s=i+1):n=i-1}if(o&&t.startsWith(o))return o;for(const i of e)if(t.startsWith(i))return i;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 o=c=>String(c).padStart(3,"0"),i=(async()=>{const c=await this.fetchJson(`${this.basePath}/tiyao/juan-${o(t)}-${o(e)}.json`);return this.tiyaoCache.set(s,c),c})();this.tiyaoLoading.set(s,i);try{return await i}finally{this.tiyaoLoading.delete(s)}}async getCounts(){if(this.metaCache)return this.metaCache;if(this.metaLoading){const t=await this.metaLoading;if(t)return t;throw new Error("BundleStorage: meta.json 加载失败")}this.metaLoading=(async()=>{const t=await this.fetchJson(`${this.basePath}/meta.json`);if(!t||typeof t.works!="number")throw new Error("BundleStorage: meta.json 格式无效");return this.metaCache=t,t})();try{const t=await this.metaLoading;if(!t)throw new Error("BundleStorage: meta.json 加载失败");return t}finally{this.metaLoading=null}}async getResourceCounts(){return(await this.getCounts()).resourceCounts??{hasText:0,hasImage:0}}async getSubtypeStats(){return(await this.getCounts()).subtypeStats??{}}async loadEntries(t,e){throw new Error("BundleStorage.loadEntries 已废弃:请使用 worker 搜索")}async search(t,e,s){throw new Error("BundleStorage.search 已废弃:请使用 worker 搜索")}async searchAll(t,e=5){throw new Error("BundleStorage.searchAll 已废弃:请使用 worker 搜索")}async getItem(t){try{const s=(await this.ensurePromotions()).get(t)??t,n=s!==t?t:void 0,i=(await this.loadChunkForId(s))[s]||null;return i&&(i.type==="entity"&&!i.title&&i.primary_name&&(i.title=i.primary_name),n&&(i.redirected_from=n)),i}catch{return null}}async getEntry(t){var e,s;try{const o=(await this.ensurePromotions()).get(t)??t,i=o!==t?t:void 0,a=(await this.loadChunkForId(o))[o];if(!a)return null;const l=pt(o),u=l==="entity"?a.primary_name||a.title||a.name||o:a.title||a.name||o;return{id:o,title:u,type:l,isDraft:!0,author:a.author,dynasty:a.dynasty,role:a.role,additional_titles:(e=a.additional_titles)==null?void 0:e.map(h=>typeof h=="string"?h:h==null?void 0:h.book_title).filter(Boolean),attached_texts:(s=a.attached_texts)==null?void 0:s.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,...i?{redirected_from:i}:{}}}catch{return null}}async getAllEntries(){throw new Error("BundleStorage.getAllEntries 已废弃:请使用 getEntry / worker 搜索")}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 o of s)try{const i=await this.fetchJson(`${this.basePath}/items/${t}/${o.id}/volume_book_mapping.json`);i&&n.push({resource_id:o.id,short_name:o.short_name,data:Q(i)})}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/index.json`)}catch{}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$/,".txt"),n=await this.ensureVersion(),o=`${this.basePath}/items/${t}/collated_edition/text/${s}`,i=n?`${o}?v=${n}`:o;try{const c=await fetch(i,{cache:"no-cache"});return c.ok?await c.text():null}catch{return null}}async getBookFullTextIndex(t){try{return await this.fetchJson(`${this.basePath}/items/${t}/full_text/index.json`)}catch{return null}}async getBookFullTextChapter(t,e){if(e.includes(".."))return null;const s=e.endsWith(".md")?e.replace(/\.md$/,".txt"):e,n=await this.ensureVersion(),o=`${this.basePath}/items/${t}/full_text/${s}`,i=n?`${o}?v=${n}`:o;try{const c=await fetch(i,{cache:"no-cache"});return c.ok?await c.text():null}catch{return null}}async getLineageGraph(t){try{return await this.fetchJson(`${this.basePath}/items/${t}/lineage_graph.json`)}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.chunkCache.clear(),this.chunkLoading.clear(),this.manifest=null,this.manifestLoading=null,this.tiyaoCache.clear(),this.tiyaoLoading.clear(),this.metaCache=null,this.metaLoading=null,this.versionInjected||(this.version=void 0,this.versionPromise=null)}}class F extends Error{constructor(t){super(t),this.name="BookIndexError"}}class zt extends F{constructor(t){super(t),this.name="StorageError"}}class Yt extends F{constructor(t){super(t),this.name="IdGenerationError"}}class Kt extends F{constructor(t){super(t),this.name="ConfigError"}}class Vt extends F{constructor(t){super(t),this.name="MigrationError"}}class Xt{constructor(t,e,s=1){this.storage=new X(t,e),this.idGen=new tt(s)}generateId(t="book",e="draft"){return this.idGen.nextIdRaw(e,t)}encodeId(t){return U(t)}decodeId(t){return I(t)}async saveItem(t,e,s="draft"){let n=t.id||t.ID;if(n)try{const i=B(n);e||(e=i.type)}catch{throw new F(`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 o=await this.storage.loadMetadata(n),i={基本信息:null,介绍:"description",资源:"resources",收藏历史:"history",其他版本:"related_books"},c=e in i?i[e]:e;if(c===null)return!1;if(c==="description"&&typeof s=="string"){const l=o[c]||{};o[c]={text:s,sources:l.sources||[]}}else o[c]=s;const a=B(t);return await this.storage.saveItem(a.type,t,o),!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 Qt={wikisource:"wikisource",shidianguji:"shidianguji",archive:"archive",ctext:"ctext",nlc:"nlc","read.nlc":"nlc","db.sido":"sido","guji.artx":"guji-artx","digital.library":"digital-library"},rt=new Set(["text","image","text+image","physical"]),at=new Set(["text","image","physical"]),Zt=new Set(["catalog","search"]),te=new Set(["com","org","net","cn","edu","gov","io","jp","tw","hk"]);function ee(r){if(!r)return"";try{const e=new URL(r).hostname;for(const[n,o]of Object.entries(Qt))if(e.includes(n))return o;const s=e.split(".");if(s.length>=2){const n=s.filter(o=>!te.has(o)&&o.length>2);return n.length>0?n[n.length-1]:s[s.length-2]}return e}catch{return""}}function se(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)at.has(s)||t.push(`invalid types atom '${s}', must be one of ${[...at].join(", ")}`);e=r.types.length===1&&r.types[0]==="physical"}else r.type!==void 0?(rt.has(r.type)||t.push(`invalid type '${r.type}', must be one of ${[...rt].join(", ")}`),e=r.type==="physical"):t.push("either type or types is required");return r.root_type&&!Zt.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 b=class b{constructor(t,e=""){if(this._type=null,this.title=e,typeof t=="string"){t.startsWith(b.PREFIX)&&(t=t.slice(b.PREFIX.length)),this.idStr=t;try{this.idInt=I(t)}catch{this.idInt=0n}}else this.idInt=t,this.idStr=U(t);if(this.idInt>0n)try{const s=B(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}](${b.PREFIX}${this.idStr})`}static parseFromLink(t){const e=t.match(/\[(.*?)\]\((.*?)\)/);if(e){const s=e[1],n=e[2];if(n.startsWith(b.PREFIX)){const o=n.slice(b.PREFIX.length);return new b(o,s)}}return null}static isBidLink(t){return t.startsWith(b.PREFIX)}};b.PROTOCOL="bid:\\\\",b.PREFIX="bid:\\\\";let K=b;exports.BidLink=K;exports.BookIndexError=F;exports.BookIndexManager=Xt;exports.BookIndexStorage=X;exports.BundleStorage=qt;exports.ConfigError=Kt;exports.GithubStorage=Jt;exports.IdGenerationError=Yt;exports.IdGenerator=tt;exports.LocalStorage=Wt;exports.MigrationError=Vt;exports.StorageError=zt;exports.base36Decode=V;exports.base36Encode=U;exports.base58Decode=gt;exports.buildId=q;exports.buildPromotionMap=Z;exports.cleanName=mt;exports.decodeId=Bt;exports.decodeIdString=B;exports.encodeId=Tt;exports.extractIdFromUrl=ee;exports.extractStatus=Ft;exports.extractType=pt;exports.normalizeCatalog=Q;exports.parseId=A;exports.shardOf=J;exports.smartDecode=I;exports.validateResource=se;