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.
@@ -1,16 +1,16 @@
1
1
  const ct = { official: 0, draft: 1 }, lt = { 0: "official", 1: "draft" }, ht = { book: 0, collection: 2, work: 3, entity: 4 }, ut = { 0: "book", 2: "collection", 3: "work", 4: "entity" }, V = 62n, X = 59n, Q = 19n, Z = 8n, tt = (1n << 40n) - 1n, dt = (1n << 3n) - 1n, ft = (1n << 11n) - 1n, yt = (1n << 8n) - 1n, R = "0123456789abcdefghijklmnopqrstuvwxyz", et = /* @__PURE__ */ new Map();
2
- for (let r = 0; r < R.length; r++)
3
- et.set(R[r], BigInt(r));
4
- function U(r) {
5
- if (r === 0n) return R[0];
2
+ for (let c = 0; c < R.length; c++)
3
+ et.set(R[c], BigInt(c));
4
+ function D(c) {
5
+ if (c === 0n) return R[0];
6
6
  let t = "";
7
- for (; r > 0n; )
8
- t = R[Number(r % 36n)] + t, r = r / 36n;
7
+ for (; c > 0n; )
8
+ t = R[Number(c % 36n)] + t, c = c / 36n;
9
9
  return t;
10
10
  }
11
- function st(r) {
11
+ function st(c) {
12
12
  let t = 0n;
13
- for (const e of r) {
13
+ for (const e of c) {
14
14
  const s = et.get(e);
15
15
  if (s === void 0)
16
16
  throw new Error(`Invalid Base36 character: ${e}`);
@@ -19,11 +19,11 @@ function st(r) {
19
19
  return t;
20
20
  }
21
21
  const H = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", nt = /* @__PURE__ */ new Map();
22
- for (let r = 0; r < H.length; r++)
23
- nt.set(H[r], BigInt(r));
24
- function gt(r) {
22
+ for (let c = 0; c < H.length; c++)
23
+ nt.set(H[c], BigInt(c));
24
+ function gt(c) {
25
25
  let t = 0n;
26
- for (const e of r) {
26
+ for (const e of c) {
27
27
  const s = nt.get(e);
28
28
  if (s === void 0)
29
29
  throw new Error(`Invalid Base58 character: ${e}`);
@@ -31,12 +31,12 @@ function gt(r) {
31
31
  }
32
32
  return t;
33
33
  }
34
- function x(r) {
35
- return /[A-Z]/.test(r) ? gt(r) : st(r);
34
+ function x(c) {
35
+ return /[A-Z]/.test(c) ? gt(c) : st(c);
36
36
  }
37
- const Ct = U, Pt = st;
38
- function A(r) {
39
- const t = Number(r >> V & 1n), e = Number(r >> X & dt), s = r >> Q & tt, n = Number(r >> Z & ft), i = Number(r & yt);
37
+ const jt = D, Pt = st;
38
+ function $(c) {
39
+ const t = Number(c >> V & 1n), e = Number(c >> X & dt), s = c >> Q & tt, n = Number(c >> Z & ft), i = Number(c & yt);
40
40
  return {
41
41
  status: lt[t] ?? "draft",
42
42
  type: ut[e] ?? "book",
@@ -45,31 +45,31 @@ function A(r) {
45
45
  sequence: i
46
46
  };
47
47
  }
48
- function z(r, t, e, s, n) {
49
- return BigInt(ct[r]) << V | BigInt(ht[t]) << X | (e & tt) << Q | BigInt(s) << Z | BigInt(n);
48
+ function z(c, t, e, s, n) {
49
+ return BigInt(ct[c]) << V | BigInt(ht[t]) << X | (e & tt) << Q | BigInt(s) << Z | BigInt(n);
50
50
  }
51
- function L(r) {
52
- return A(x(r));
51
+ function L(c) {
52
+ return $(x(c));
53
53
  }
54
- function jt(r) {
55
- return L(r).type;
54
+ function pt(c) {
55
+ return L(c).type;
56
56
  }
57
- function Tt(r) {
58
- return L(r).status;
57
+ function Tt(c) {
58
+ return L(c).status;
59
59
  }
60
- const N = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" }, pt = { Book: "book", Collection: "collection", Work: "work", Entity: "entity" }, T = 16;
61
- function W(r, t = T) {
60
+ const N = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" }, mt = { Book: "book", Collection: "collection", Work: "work", Entity: "entity" }, T = 16;
61
+ function J(c, t = T) {
62
62
  let e = 0;
63
- for (let s = 0; s < r.length; s++)
64
- e = Math.imul(e, 31) + r.charCodeAt(s) >>> 0;
63
+ for (let s = 0; s < c.length; s++)
64
+ e = Math.imul(e, 31) + c.charCodeAt(s) >>> 0;
65
65
  return e % t;
66
66
  }
67
- function b(...r) {
68
- const t = r.join("/");
67
+ function b(...c) {
68
+ const t = c.join("/");
69
69
  return t.startsWith("//") ? "//" + t.slice(2).replace(/\/+/g, "/") : t.replace(/\/+/g, "/");
70
70
  }
71
- function mt(r) {
72
- return r.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "") || "Undefined";
71
+ function _t(c) {
72
+ return c.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "") || "Undefined";
73
73
  }
74
74
  class it {
75
75
  constructor(t, e) {
@@ -79,30 +79,30 @@ class it {
79
79
  return t === "draft" ? this.draftRoot : this.officialRoot;
80
80
  }
81
81
  getRootById(t) {
82
- const e = x(t), s = A(e);
82
+ const e = x(t), s = $(e);
83
83
  return this.getRootByStatus(s.status);
84
84
  }
85
85
  /**
86
86
  * 计算文件路径: {root}/{Type}/{c1}/{c2}/{c3}/{ID}-{name}.json
87
87
  */
88
88
  getPath(t, e, s) {
89
- const n = this.getRootById(e), i = e.padEnd(3, "_").substring(0, 3), [o, c, l] = [i[0], i[1], i[2]], a = N[t];
90
- return b(n, a, o, c, l, `${e}-${mt(s)}.json`);
89
+ const n = this.getRootById(e), i = e.padEnd(3, "_").substring(0, 3), [o, r, l] = [i[0], i[1], i[2]], a = N[t];
90
+ return b(n, a, o, r, l, `${e}-${_t(s)}.json`);
91
91
  }
92
92
  /**
93
93
  * 保存条目并更新索引
94
94
  */
95
95
  async saveItem(t, e, s) {
96
- const n = s.title || s.书名 || "未命名", i = s.edition || "", o = i ? `${n}${i}` : n, c = this.getPath(t, e, o), l = await this.findFileById(e);
97
- if (l && l !== c)
96
+ const n = s.title || s.书名 || "未命名", i = s.edition || "", o = i ? `${n}${i}` : n, r = this.getPath(t, e, o), l = await this.findFileById(e);
97
+ if (l && l !== r)
98
98
  try {
99
99
  await this.fs.deleteFile(l);
100
100
  } catch {
101
101
  }
102
- const a = c.substring(0, c.lastIndexOf("/"));
103
- await this.fs.mkdir(a), s.id = e, s.type = t, await this.fs.writeFile(c, JSON.stringify(s, _t, 2));
104
- const u = this.getRootById(e), h = c.substring(u.length + 1);
105
- return await this.updateIndexEntry(u, s, t, h), c;
102
+ const a = r.substring(0, r.lastIndexOf("/"));
103
+ await this.fs.mkdir(a), s.id = e, s.type = t, await this.fs.writeFile(r, JSON.stringify(s, wt, 2));
104
+ const h = this.getRootById(e), u = r.substring(h.length + 1);
105
+ return await this.updateIndexEntry(h, s, t, u), r;
106
106
  }
107
107
  /**
108
108
  * 更新索引分片中的条目
@@ -110,16 +110,16 @@ class it {
110
110
  async updateIndexEntry(t, e, s, n) {
111
111
  const i = e.id || "";
112
112
  if (!i) return;
113
- const o = `${s}s`, c = await this.loadShard(t, o, i);
113
+ const o = `${s}s`, r = await this.loadShard(t, o, i);
114
114
  let l = "";
115
115
  const a = e.authors;
116
116
  if (Array.isArray(a) && a.length > 0) {
117
117
  const y = a[0];
118
118
  l = typeof y == "object" && y !== null ? y.name || "" : String(y);
119
119
  } else typeof a == "string" && (l = a);
120
- let u = "";
121
- const h = e.publication_info;
122
- typeof h == "object" && h !== null ? u = h.year || "" : typeof h == "string" && (u = h);
120
+ let h = "";
121
+ const u = e.publication_info;
122
+ typeof u == "object" && u !== null ? h = u.year || "" : typeof u == "string" && (h = u);
123
123
  let d = "";
124
124
  const f = e.current_location;
125
125
  typeof f == "object" && f !== null ? d = f.name || "" : typeof f == "string" && (d = f);
@@ -127,18 +127,18 @@ class it {
127
127
  let v;
128
128
  const I = e.juan_count;
129
129
  typeof I == "number" ? v = I : typeof I == "object" && I !== null && (v = I.number || void 0);
130
- const C = typeof e.measure_info == "string" ? e.measure_info : "";
131
- let E = !1, S = !1;
132
- const j = e.resources;
133
- if (Array.isArray(j))
134
- for (const y of j) {
130
+ const A = typeof e.measure_info == "string" ? e.measure_info : "";
131
+ let C = !1, S = !1;
132
+ const P = e.resources;
133
+ if (Array.isArray(P))
134
+ for (const y of P) {
135
135
  if (typeof y != "object" || y === null) continue;
136
136
  const _ = y.types;
137
137
  if (Array.isArray(_))
138
- _.includes("text") && (E = !0), _.includes("image") && (S = !0);
138
+ _.includes("text") && (C = !0), _.includes("image") && (S = !0);
139
139
  else {
140
- const $ = y.type;
141
- ($ === "text" || $ === "text+image") && (E = !0), ($ === "image" || $ === "text+image") && (S = !0);
140
+ const E = y.type;
141
+ (E === "text" || E === "text+image") && (C = !0), (E === "image" || E === "text+image") && (S = !0);
142
142
  }
143
143
  }
144
144
  const m = {
@@ -147,12 +147,12 @@ class it {
147
147
  type: N[s],
148
148
  path: n,
149
149
  author: l,
150
- year: u,
150
+ year: h,
151
151
  holder: d
152
152
  };
153
- p && p.length > 0 && (m.additional_titles = p), k && k.length > 0 && (m.attached_texts = k), v && (m.juan_count = v), C && (m.measure_info = C);
154
- const P = typeof e.edition == "string" ? e.edition : "";
155
- P && (m.edition = P), E && (m.has_text = !0), S && (m.has_image = !0), c[i] = m, await this.saveShard(t, o, i, c);
153
+ p && p.length > 0 && (m.additional_titles = p), k && k.length > 0 && (m.attached_texts = k), v && (m.juan_count = v), A && (m.measure_info = A);
154
+ const j = typeof e.edition == "string" ? e.edition : "";
155
+ j && (m.edition = j), C && (m.has_text = !0), S && (m.has_image = !0), r[i] = m, await this.saveShard(t, o, i, r);
156
156
  }
157
157
  /**
158
158
  * 删除条目和索引记录
@@ -160,8 +160,8 @@ class it {
160
160
  async deleteItem(t) {
161
161
  const e = await this.findFileById(t);
162
162
  if (!e) return !1;
163
- const s = x(t), n = A(s), i = this.getRootByStatus(n.status), o = `${n.type}s`, c = await this.loadShard(i, o, t);
164
- return c[t] && (delete c[t], await this.saveShard(i, o, t, c)), await this.fs.deleteFile(e), !0;
163
+ const s = x(t), n = $(s), i = this.getRootByStatus(n.status), o = `${n.type}s`, r = await this.loadShard(i, o, t);
164
+ return r[t] && (delete r[t], await this.saveShard(i, o, t, r)), await this.fs.deleteFile(e), !0;
165
165
  }
166
166
  /**
167
167
  * 通过 ID 查找文件
@@ -169,12 +169,12 @@ class it {
169
169
  async findFileById(t) {
170
170
  const e = t.padEnd(3, "_").substring(0, 3), [s, n, i] = [e[0], e[1], e[2]];
171
171
  for (const o of [this.officialRoot, this.draftRoot])
172
- for (const c of ["Book", "Collection", "Work"]) {
173
- const l = b(o, c, s, n, i);
172
+ for (const r of ["Book", "Collection", "Work"]) {
173
+ const l = b(o, r, s, n, i);
174
174
  if (await this.fs.exists(l))
175
175
  try {
176
- const u = (await this.fs.readdir(l)).find((h) => h.startsWith(`${t}-`) && h.endsWith(".json"));
177
- if (u) return b(l, u);
176
+ const h = (await this.fs.readdir(l)).find((u) => u.startsWith(`${t}-`) && u.endsWith(".json"));
177
+ if (h) return b(l, h);
178
178
  } catch {
179
179
  }
180
180
  }
@@ -206,8 +206,8 @@ class it {
206
206
  async loadEntries(t, e) {
207
207
  const s = e ? [this.getRootByStatus(e)] : [this.officialRoot, this.draftRoot], n = [], i = `${t}s`;
208
208
  for (const o of s) {
209
- const c = await this.loadAllShards(o, i);
210
- for (const [l, a] of Object.entries(c))
209
+ const r = await this.loadAllShards(o, i);
210
+ for (const [l, a] of Object.entries(r))
211
211
  n.push({
212
212
  id: l,
213
213
  title: a.title,
@@ -262,47 +262,47 @@ class it {
262
262
  async rebuildIndex(t) {
263
263
  var n, i;
264
264
  const e = this.getRootByStatus(t), s = {
265
- books: Object.fromEntries(Array.from({ length: T }, (o, c) => [c, {}])),
265
+ books: Object.fromEntries(Array.from({ length: T }, (o, r) => [r, {}])),
266
266
  collections: { 0: {} },
267
- works: Object.fromEntries(Array.from({ length: T }, (o, c) => [c, {}]))
267
+ works: Object.fromEntries(Array.from({ length: T }, (o, r) => [r, {}]))
268
268
  };
269
269
  for (const o of ["Book", "Collection", "Work"]) {
270
- const c = b(e, o);
271
- if (!await this.fs.exists(c)) continue;
272
- const a = `${pt[o]}s`, u = await this.fs.glob(c, "**/*.json");
273
- for (const h of u)
274
- if (!h.includes("/index/"))
270
+ const r = b(e, o);
271
+ if (!await this.fs.exists(r)) continue;
272
+ const a = `${mt[o]}s`, h = await this.fs.glob(r, "**/*.json");
273
+ for (const u of h)
274
+ if (!u.includes("/index/"))
275
275
  try {
276
- const d = await this.loadMetadata(h);
276
+ const d = await this.loadMetadata(u);
277
277
  let f = d.id || d.ID || "";
278
278
  if (!f) {
279
- const g = h.substring(h.lastIndexOf("/") + 1);
279
+ const g = u.substring(u.lastIndexOf("/") + 1);
280
280
  g.includes("-") && (f = g.split("-")[0]);
281
281
  }
282
282
  if (!f) continue;
283
- const p = h.substring(e.length + 1);
283
+ const p = u.substring(e.length + 1);
284
284
  let k = "";
285
285
  const v = d.authors;
286
286
  if (Array.isArray(v) && v.length > 0) {
287
287
  const g = v[0];
288
288
  k = typeof g == "object" && g !== null ? g.name || "" : String(g);
289
289
  }
290
- const I = 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;
291
- let E;
290
+ const I = Array.isArray(d.additional_titles) ? d.additional_titles.map((g) => typeof g == "string" ? g : g == null ? void 0 : g.book_title).filter(Boolean) : void 0, A = Array.isArray(d.attached_texts) ? d.attached_texts.map((g) => typeof g == "string" ? g : g == null ? void 0 : g.book_title).filter(Boolean) : void 0;
291
+ let C;
292
292
  const S = d.juan_count;
293
- typeof S == "number" ? E = S : typeof S == "object" && S !== null && (E = S.number || void 0);
294
- const j = typeof d.measure_info == "string" ? d.measure_info : "";
295
- let m = !1, P = !1;
293
+ typeof S == "number" ? C = S : typeof S == "object" && S !== null && (C = S.number || void 0);
294
+ const P = typeof d.measure_info == "string" ? d.measure_info : "";
295
+ let m = !1, j = !1;
296
296
  const y = d.resources;
297
297
  if (Array.isArray(y))
298
298
  for (const g of y) {
299
299
  if (typeof g != "object" || g === null) continue;
300
- const D = g.types;
301
- if (Array.isArray(D))
302
- D.includes("text") && (m = !0), D.includes("image") && (P = !0);
300
+ const U = g.types;
301
+ if (Array.isArray(U))
302
+ U.includes("text") && (m = !0), U.includes("image") && (j = !0);
303
303
  else {
304
304
  const M = g.type;
305
- (M === "text" || M === "text+image") && (m = !0), (M === "image" || M === "text+image") && (P = !0);
305
+ (M === "text" || M === "text+image") && (m = !0), (M === "image" || M === "text+image") && (j = !0);
306
306
  }
307
307
  }
308
308
  const _ = {
@@ -314,18 +314,18 @@ class it {
314
314
  year: typeof d.publication_info == "object" && ((n = d.publication_info) == null ? void 0 : n.year) || "",
315
315
  holder: typeof d.current_location == "object" && ((i = d.current_location) == null ? void 0 : i.name) || ""
316
316
  };
317
- I && I.length > 0 && (_.additional_titles = I), C && C.length > 0 && (_.attached_texts = C), E && (_.juan_count = E), j && (_.measure_info = j);
318
- const $ = typeof d.edition == "string" ? d.edition : "";
319
- $ && (_.edition = $), m && (_.has_text = !0), P && (_.has_image = !0);
320
- const at = a === "collections" ? 0 : W(f);
321
- s[a][at][f] = _;
317
+ I && I.length > 0 && (_.additional_titles = I), A && A.length > 0 && (_.attached_texts = A), C && (_.juan_count = C), P && (_.measure_info = P);
318
+ const E = typeof d.edition == "string" ? d.edition : "";
319
+ E && (_.edition = E), m && (_.has_text = !0), j && (_.has_image = !0);
320
+ const rt = a === "collections" ? 0 : J(f);
321
+ s[a][rt][f] = _;
322
322
  } catch {
323
323
  }
324
324
  }
325
- for (const [o, c] of Object.entries(s))
326
- for (const [l, a] of Object.entries(c)) {
327
- const u = this.shardPath(e, o, Number(l)), h = u.substring(0, u.lastIndexOf("/"));
328
- await this.fs.mkdir(h), await this.fs.writeFile(u, JSON.stringify(a, null, 2));
325
+ for (const [o, r] of Object.entries(s))
326
+ for (const [l, a] of Object.entries(r)) {
327
+ const h = this.shardPath(e, o, Number(l)), u = h.substring(0, h.lastIndexOf("/"));
328
+ await this.fs.mkdir(u), await this.fs.writeFile(h, JSON.stringify(a, null, 2));
329
329
  }
330
330
  }
331
331
  // ── Asset Directory ──
@@ -334,8 +334,8 @@ class it {
334
334
  * 与 JSON 文件同级,以 ID 命名
335
335
  */
336
336
  getAssetDir(t) {
337
- const e = this.getRootById(t), s = x(t), i = A(s).type, o = t.padEnd(3, "_").substring(0, 3), [c, l, a] = [o[0], o[1], o[2]], u = N[i];
338
- return b(e, u, c, l, a, t);
337
+ const e = this.getRootById(t), s = x(t), i = $(s).type, o = t.padEnd(3, "_").substring(0, 3), [r, l, a] = [o[0], o[1], o[2]], h = N[i];
338
+ return b(e, h, r, l, a, t);
339
339
  }
340
340
  /**
341
341
  * 初始化资源目录:创建 {ID}/ 文件夹
@@ -357,7 +357,7 @@ class it {
357
357
  return e === "collections" ? b(t, "index", "collections.json") : b(t, "index", e, `${s.toString(16)}.json`);
358
358
  }
359
359
  async loadShard(t, e, s) {
360
- const n = W(s), i = this.shardPath(t, e, n);
360
+ const n = J(s), i = this.shardPath(t, e, n);
361
361
  try {
362
362
  if (!await this.fs.exists(i)) return {};
363
363
  const o = await this.fs.readFile(i);
@@ -367,8 +367,8 @@ class it {
367
367
  }
368
368
  }
369
369
  async saveShard(t, e, s, n) {
370
- const i = W(s), o = this.shardPath(t, e, i), c = o.substring(0, o.lastIndexOf("/"));
371
- await this.fs.mkdir(c), await this.fs.writeFile(o, JSON.stringify(n, null, 2));
370
+ const i = J(s), o = this.shardPath(t, e, i), r = o.substring(0, o.lastIndexOf("/"));
371
+ await this.fs.mkdir(r), await this.fs.writeFile(o, JSON.stringify(n, null, 2));
372
372
  }
373
373
  async loadAllShards(t, e) {
374
374
  const s = {};
@@ -396,37 +396,37 @@ class it {
396
396
  return s;
397
397
  }
398
398
  }
399
- function J(r, t) {
399
+ function W(c, t) {
400
400
  const e = t.toLowerCase();
401
401
  let s = 0;
402
- const n = r.title.toLowerCase();
402
+ const n = c.title.toLowerCase();
403
403
  n === e ? s = 200 : n.startsWith(e) ? s = 150 : n.includes(e) && (s = 100);
404
- const i = [...r.additional_titles || [], ...r.attached_texts || []];
404
+ const i = [...c.additional_titles || [], ...c.attached_texts || []];
405
405
  for (const a of i) {
406
- const u = a.toLowerCase();
407
- u === e ? s = Math.max(s, 120) : u.startsWith(e) ? s = Math.max(s, 90) : u.includes(e) && (s = Math.max(s, 60));
406
+ const h = a.toLowerCase();
407
+ h === e ? s = Math.max(s, 120) : h.startsWith(e) ? s = Math.max(s, 90) : h.includes(e) && (s = Math.max(s, 60));
408
408
  }
409
409
  let o = 0;
410
- if (r.author) {
411
- const a = r.author.toLowerCase();
410
+ if (c.author) {
411
+ const a = c.author.toLowerCase();
412
412
  a === e ? o = 80 : a.includes(e) && (o = 50);
413
413
  }
414
- let c = 0;
415
- r.dynasty && r.dynasty.toLowerCase().includes(e) && (c = 30);
414
+ let r = 0;
415
+ c.dynasty && c.dynasty.toLowerCase().includes(e) && (r = 30);
416
416
  let l = s;
417
- 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);
417
+ return l === 0 && (l = Math.max(o, r)), l === 0 ? 0 : (l += Math.max(0, 20 - n.length), c.type === "work" ? l = Math.round(l * 1.05) : c.type === "collection" && (l = Math.round(l * 1.02)), c.has_text && (l += 3), c.has_image && (l += 2), l);
418
418
  }
419
- function _t(r, t) {
419
+ function wt(c, t) {
420
420
  return t === null ? void 0 : t;
421
421
  }
422
- function B(r, t) {
423
- const e = r.map((s) => ({ entry: s, score: J(s, t) })).filter((s) => s.score > 0);
422
+ function B(c, t) {
423
+ const e = c.map((s) => ({ entry: s, score: W(s, t) })).filter((s) => s.score > 0);
424
424
  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);
425
425
  }
426
- function O(r, t, e, s) {
427
- const n = r.map((i) => {
428
- const o = J(i, t);
429
- let c = 0;
426
+ function O(c, t, e, s) {
427
+ const n = c.map((i) => {
428
+ const o = W(i, t);
429
+ let r = 0;
430
430
  const l = s[i.id];
431
431
  if (l && e) {
432
432
  const a = {
@@ -436,14 +436,14 @@ function O(r, t, e, s) {
436
436
  additional_titles: l.at ?? i.additional_titles,
437
437
  attached_texts: l.axt ?? i.attached_texts
438
438
  };
439
- c = J(a, e);
439
+ r = W(a, e);
440
440
  }
441
- return { entry: i, score: Math.max(o, c) };
441
+ return { entry: i, score: Math.max(o, r) };
442
442
  }).filter((i) => i.score > 0);
443
443
  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);
444
444
  }
445
- function wt(r) {
446
- const t = r.volumes ?? [];
445
+ function bt(c) {
446
+ const t = c.volumes ?? [];
447
447
  let e, s;
448
448
  if (t.length === 0)
449
449
  e = [];
@@ -454,64 +454,64 @@ function wt(r) {
454
454
  for (const i of t) {
455
455
  const o = i.volume;
456
456
  e.push(o);
457
- const c = {};
457
+ const r = {};
458
458
  for (const [l, a] of Object.entries(i))
459
- l === "volume" || l === "status" || l === "file" || typeof a == "string" && (l.includes("url") || l.includes("id")) && (c[l] = a);
459
+ l === "volume" || l === "status" || l === "file" || typeof a == "string" && (l.includes("url") || l.includes("id")) && (r[l] = a);
460
460
  s.push({
461
461
  volume: o,
462
462
  status: i.status,
463
- urls: Object.keys(c).length > 0 ? c : void 0,
463
+ urls: Object.keys(r).length > 0 ? r : void 0,
464
464
  file: i.file
465
465
  });
466
466
  }
467
467
  }
468
468
  const n = {
469
- title: r.title ?? "",
470
- book_id: r.book_id ?? null,
471
- work_id: r.work_id ?? null,
469
+ title: c.title ?? "",
470
+ book_id: c.book_id ?? null,
471
+ work_id: c.work_id ?? null,
472
472
  volumes: e,
473
- section: r.section,
474
- sub_items: r.sub_items,
475
- edition: r.edition,
476
- expected_volumes: r.expected_volumes,
477
- found_volumes: r.found_volumes,
478
- missing_volumes: r.missing_vols ?? r.missing_volumes
473
+ section: c.section,
474
+ sub_items: c.sub_items,
475
+ edition: c.edition,
476
+ expected_volumes: c.expected_volumes,
477
+ found_volumes: c.found_volumes,
478
+ missing_volumes: c.missing_vols ?? c.missing_volumes
479
479
  };
480
480
  s && (n.volume_details = s);
481
481
  for (const i of Object.keys(n))
482
482
  n[i] === void 0 && delete n[i];
483
483
  return n;
484
484
  }
485
- function bt(r) {
485
+ function kt(c) {
486
486
  const t = {
487
- total_books: r.total_books ?? 0
487
+ total_books: c.total_books ?? 0
488
488
  };
489
- 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;
489
+ return c.processed_volumes != null && (t.processed_volumes = c.processed_volumes), c.matched_works != null && (t.matched_works = c.matched_works), c.unmatched_works != null && (t.unmatched_works = c.unmatched_works), c.total_found_volumes != null && (t.total_found_volumes = c.total_found_volumes), t;
490
490
  }
491
- function ot(r) {
491
+ function ot(c) {
492
492
  var n;
493
- const t = r, e = (t.books ?? []).map(wt), s = {
493
+ const t = c, e = (t.books ?? []).map(bt), s = {
494
494
  collection_id: t.collection_id ?? "",
495
495
  title: t.title ?? "",
496
496
  total_volumes: t.total_volumes ?? 0,
497
- stats: bt(t.stats ?? {}),
497
+ stats: kt(t.stats ?? {}),
498
498
  books: e
499
499
  };
500
500
  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;
501
501
  }
502
- const kt = "https://raw.githubusercontent.com", It = [
502
+ const It = "https://raw.githubusercontent.com", St = [
503
503
  "https://fastly.jsdelivr.net/gh",
504
504
  "https://cdn.jsdelivr.net/gh"
505
- ], St = 5e3;
505
+ ], xt = 5e3;
506
506
  class Lt {
507
507
  // null=未加载, false=不可用
508
508
  constructor(t) {
509
509
  this.cache = null, this.cacheLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.searchSCache = null, this.t2sConverter = null, this.config = {
510
510
  org: t.org,
511
511
  repos: t.repos,
512
- baseUrl: t.baseUrl ?? kt,
513
- cdnUrls: t.cdnUrls ?? It,
514
- timeout: t.timeout ?? St
512
+ baseUrl: t.baseUrl ?? It,
513
+ cdnUrls: t.cdnUrls ?? St,
514
+ timeout: t.timeout ?? xt
515
515
  };
516
516
  }
517
517
  /** 确保 index 数据已加载到缓存 */
@@ -566,9 +566,9 @@ class Lt {
566
566
  } catch {
567
567
  }
568
568
  for (const o of this.config.cdnUrls) {
569
- const c = `${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;
569
+ const r = `${o}/${this.config.org}/${t}@main/${encodeURI(e)}`;
570
570
  try {
571
- if ((await fetch(c, {
571
+ if ((await fetch(r, {
572
572
  method: "HEAD",
573
573
  signal: AbortSignal.timeout(this.config.timeout)
574
574
  })).ok) return !0;
@@ -585,9 +585,9 @@ class Lt {
585
585
  } catch {
586
586
  }
587
587
  for (const o of this.config.cdnUrls) {
588
- const c = `${o}/${this.config.org}/${t}@main/${encodeURI(n)}`;
588
+ const r = `${o}/${this.config.org}/${t}@main/${encodeURI(n)}`;
589
589
  try {
590
- if ((await fetch(c, {
590
+ if ((await fetch(r, {
591
591
  method: "HEAD",
592
592
  signal: AbortSignal.timeout(this.config.timeout)
593
593
  })).ok) return !0;
@@ -610,9 +610,9 @@ class Lt {
610
610
  const n = [];
611
611
  for (const i of ["books", "works"])
612
612
  for (let o = 0; o < T; o++) {
613
- const c = `index/${i}/${o.toString(16)}.json`;
613
+ const r = `index/${i}/${o.toString(16)}.json`;
614
614
  n.push(
615
- this.fetchFileWithFallback(t, c).then((l) => {
615
+ this.fetchFileWithFallback(t, r).then((l) => {
616
616
  Object.assign(s[i], l);
617
617
  }).catch(() => {
618
618
  })
@@ -639,33 +639,33 @@ class Lt {
639
639
  ["works", "work"],
640
640
  ["entities", "entity"]
641
641
  ];
642
- for (const [c, l] of n) {
643
- const a = t[c];
642
+ for (const [r, l] of n) {
643
+ const a = t[r];
644
644
  if (a)
645
- for (const u of Object.values(a)) {
646
- const h = u, d = l === "entity" ? h.primary_name || u.title || u.name || u.id : u.title || u.name || u.id;
645
+ for (const h of Object.values(a)) {
646
+ const u = h, d = l === "entity" ? u.primary_name || h.title || h.name || h.id : h.title || h.name || h.id;
647
647
  s.push({
648
- id: u.id,
648
+ id: h.id,
649
649
  title: d,
650
650
  type: l,
651
651
  isDraft: e,
652
- author: u.author,
653
- dynasty: u.dynasty,
654
- role: u.role,
655
- path: u.path,
656
- 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),
657
- 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),
658
- edition: h.edition,
659
- juan_count: h.juan_count,
660
- has_text: h.has_text,
661
- has_image: h.has_image,
662
- has_collated: h.has_collated,
663
- subtype: h.subtype,
664
- primary_name: h.primary_name,
665
- birth_year: h.birth_year,
666
- death_year: h.death_year,
667
- cbdb_id: h.cbdb_id
668
- }), this.pathMap.set(u.id, { path: u.path, isDraft: e });
652
+ author: h.author,
653
+ dynasty: h.dynasty,
654
+ role: h.role,
655
+ path: h.path,
656
+ additional_titles: (i = u.additional_titles) == null ? void 0 : i.map((f) => typeof f == "string" ? f : f == null ? void 0 : f.book_title).filter(Boolean),
657
+ attached_texts: (o = u.attached_texts) == null ? void 0 : o.map((f) => typeof f == "string" ? f : f == null ? void 0 : f.book_title).filter(Boolean),
658
+ edition: u.edition,
659
+ juan_count: u.juan_count,
660
+ has_text: u.has_text,
661
+ has_image: u.has_image,
662
+ has_collated: u.has_collated,
663
+ subtype: u.subtype,
664
+ primary_name: u.primary_name,
665
+ birth_year: u.birth_year,
666
+ death_year: u.death_year,
667
+ cbdb_id: u.cbdb_id
668
+ }), this.pathMap.set(h.id, { path: h.path, isDraft: e });
669
669
  }
670
670
  }
671
671
  return s;
@@ -689,52 +689,52 @@ class Lt {
689
689
  }
690
690
  const t = await this.ensureLoaded(), e = this.t2sConverter, s = {};
691
691
  for (const o of t) {
692
- const c = {}, l = e(o.title);
693
- if (l !== o.title && (c.t = l), o.author) {
692
+ const r = {}, l = e(o.title);
693
+ if (l !== o.title && (r.t = l), o.author) {
694
694
  const a = e(o.author);
695
- a !== o.author && (c.a = a);
695
+ a !== o.author && (r.a = a);
696
696
  }
697
697
  if ((n = o.additional_titles) != null && n.length) {
698
698
  const a = o.additional_titles.map(e);
699
- a.some((u, h) => u !== o.additional_titles[h]) && (c.at = a);
699
+ a.some((h, u) => h !== o.additional_titles[u]) && (r.at = a);
700
700
  }
701
701
  if ((i = o.attached_texts) != null && i.length) {
702
702
  const a = o.attached_texts.map(e);
703
- a.some((u, h) => u !== o.attached_texts[h]) && (c.axt = a);
703
+ a.some((h, u) => h !== o.attached_texts[u]) && (r.axt = a);
704
704
  }
705
- Object.keys(c).length > 0 && (s[o.id] = c);
705
+ Object.keys(r).length > 0 && (s[o.id] = r);
706
706
  }
707
707
  return this.searchSCache = s, { searchS: s, converter: e };
708
708
  }
709
709
  // --- IndexStorage 实现 ---
710
710
  async loadEntries(t, e) {
711
- let n = (await this.ensureLoaded()).filter((h) => h.type === t);
711
+ let n = (await this.ensureLoaded()).filter((u) => u.type === t);
712
712
  const i = e.sortBy || "title", o = e.sortOrder || "asc";
713
- n.sort((h, d) => {
714
- const f = String(h[i] ?? ""), p = String(d[i] ?? ""), k = f.localeCompare(p, "zh");
713
+ n.sort((u, d) => {
714
+ const f = String(u[i] ?? ""), p = String(d[i] ?? ""), k = f.localeCompare(p, "zh");
715
715
  return o === "asc" ? k : -k;
716
716
  });
717
- const c = e.page || 1, l = e.pageSize || 50, a = (c - 1) * l;
717
+ const r = e.page || 1, l = e.pageSize || 50, a = (r - 1) * l;
718
718
  return {
719
719
  entries: n.slice(a, a + l),
720
720
  total: n.length,
721
- page: c,
721
+ page: r,
722
722
  pageSize: l
723
723
  };
724
724
  }
725
725
  async search(t, e, s) {
726
- 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) : B(c, t), h = s.page || 1, d = s.pageSize || 50, f = (h - 1) * d;
726
+ const n = await this.ensureLoaded(), { searchS: i, converter: o } = await this.ensureSearchSBuilt(), r = n.filter((p) => p.type === e), l = o ? o(t) : void 0, h = Object.keys(i).length > 0 ? O(r, t, l, i) : B(r, t), u = s.page || 1, d = s.pageSize || 50, f = (u - 1) * d;
727
727
  return {
728
- entries: u.slice(f, f + d),
729
- total: u.length,
730
- page: h,
728
+ entries: h.slice(f, f + d),
729
+ total: h.length,
730
+ page: u,
731
731
  pageSize: d
732
732
  };
733
733
  }
734
734
  async searchAll(t, e = 5) {
735
- 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) => {
736
- const h = s.filter((d) => d.type === u);
737
- return l ? O(h, t, c, n) : B(h, t);
735
+ const s = await this.ensureLoaded(), { searchS: n, converter: i } = await this.ensureSearchSBuilt(), o = ["work", "book", "collection"], r = i ? i(t) : void 0, l = Object.keys(n).length > 0, a = o.map((h) => {
736
+ const u = s.filter((d) => d.type === h);
737
+ return l ? O(u, t, r, n) : B(u, t);
738
738
  });
739
739
  return {
740
740
  works: a[0].slice(0, e),
@@ -751,7 +751,7 @@ class Lt {
751
751
  if (s) {
752
752
  const i = s.isDraft ? this.config.repos.draft : this.config.repos.official;
753
753
  if (n = await this.fetchItemByPath(i, s.path), n) {
754
- const o = e.find((c) => c.id === t);
754
+ const o = e.find((r) => r.id === t);
755
755
  o != null && o.has_collated && (n.has_collated = !0);
756
756
  }
757
757
  } else
@@ -805,18 +805,18 @@ class Lt {
805
805
  const e = { book: "Book", collection: "Collection", work: "Work", entity: "Entity" };
806
806
  let s, n;
807
807
  try {
808
- const u = A(x(t));
809
- s = u.type, n = u.status;
808
+ const h = $(x(t));
809
+ s = h.type, n = h.status;
810
810
  } catch {
811
811
  return null;
812
812
  }
813
- 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}`;
813
+ const i = n === "draft" ? this.config.repos.draft : this.config.repos.official, o = e[s], r = t.padEnd(3, "_").substring(0, 3), l = `${o}/${r[0]}/${r[1]}/${r[2]}`, a = `https://api.github.com/repos/${this.config.org}/${i}/contents/${l}`;
814
814
  try {
815
- const u = await fetch(a, {
815
+ const h = await fetch(a, {
816
816
  signal: AbortSignal.timeout(this.config.timeout)
817
817
  });
818
- if (!u.ok) return null;
819
- const d = (await u.json()).find((p) => p.name.startsWith(`${t}-`) && p.name.endsWith(".json"));
818
+ if (!h.ok) return null;
819
+ const d = (await h.json()).find((p) => p.name.startsWith(`${t}-`) && p.name.endsWith(".json"));
820
820
  if (!d) return null;
821
821
  const f = await this.fetchItemByPath(i, d.path);
822
822
  return f && this.pathMap.set(t, { path: d.path, isDraft: n === "draft" }), f;
@@ -833,9 +833,9 @@ class Lt {
833
833
  const a = o[0];
834
834
  i = typeof a == "object" && a !== null ? a.name || "" : String(a);
835
835
  }
836
- let c = !0;
836
+ let r = !0;
837
837
  try {
838
- c = A(x(t)).status === "draft";
838
+ r = $(x(t)).status === "draft";
839
839
  } catch {
840
840
  }
841
841
  const l = this.pathMap.get(t);
@@ -843,7 +843,7 @@ class Lt {
843
843
  id: t,
844
844
  title: e.title || e.书名 || t,
845
845
  type: n,
846
- isDraft: c,
846
+ isDraft: r,
847
847
  author: i,
848
848
  dynasty: e.dynasty,
849
849
  role: e.role,
@@ -887,7 +887,7 @@ class Lt {
887
887
  if (n.length === 0) return null;
888
888
  const i = [];
889
889
  for (const o of n) {
890
- const c = `${e.dir}/${t}/${o.id}/volume_book_mapping.json`, l = await this.fetchFile(e.repo, c);
890
+ const r = `${e.dir}/${t}/${o.id}/volume_book_mapping.json`, l = await this.fetchFile(e.repo, r);
891
891
  l && i.push({
892
892
  resource_id: o.id,
893
893
  short_name: o.short_name,
@@ -935,7 +935,7 @@ class Lt {
935
935
  }
936
936
  }
937
937
  const G = 255;
938
- class rt {
938
+ class at {
939
939
  constructor(t) {
940
940
  if (this.lastTimestamp = -1, this.lastStatus = null, this.sequence = 0, t < 0 || t > 2047)
941
941
  throw new Error("Machine ID must be between 0 and 2047");
@@ -950,7 +950,7 @@ class rt {
950
950
  throw new Error("Clock moved backwards. Refusing to generate ID.");
951
951
  s === this.lastTimestamp && t === this.lastStatus ? (this.sequence = this.sequence + 1 & G, this.sequence === 0 && (s = this._tilNextUnit(this.lastTimestamp, t))) : this.sequence = 0, this.lastTimestamp = s, this.lastStatus = t;
952
952
  const n = z(t, e, BigInt(s), this.machineId, this.sequence);
953
- return U(n);
953
+ return D(n);
954
954
  }
955
955
  /**
956
956
  * 生成下一个 ID(返回 bigint 原始值)
@@ -974,7 +974,7 @@ class rt {
974
974
  }
975
975
  class Bt {
976
976
  constructor(t) {
977
- this.recentEntities = [], this.storage = new it(t.fs, t.workspaceRoot), this.idGen = new rt(t.machineId ?? 0), this.fs = t.fs, this.workspaceRoot = t.workspaceRoot;
977
+ this.recentEntities = [], this.storage = new it(t.fs, t.workspaceRoot), this.idGen = new at(t.machineId ?? 0), this.fs = t.fs, this.workspaceRoot = t.workspaceRoot;
978
978
  }
979
979
  async loadEntries(t, e) {
980
980
  const s = await this.storage.loadEntries(t);
@@ -1036,8 +1036,8 @@ class Bt {
1036
1036
  if (e.contained_in && Array.isArray(e.contained_in) && e.contained_in.length > 0) {
1037
1037
  const i = e.contained_in[0], o = typeof i == "string" ? i : i.id;
1038
1038
  if (o) {
1039
- const c = await this.resolveEntity(o);
1040
- c && (s.belongsToCollection = { ...c, type: "collection" });
1039
+ const r = await this.resolveEntity(o);
1040
+ r && (s.belongsToCollection = { ...r, type: "collection" });
1041
1041
  }
1042
1042
  }
1043
1043
  } else if (n === "collection") {
@@ -1133,13 +1133,13 @@ class Bt {
1133
1133
  const s = e && e !== "all" ? [e] : ["book", "collection", "work"], n = [];
1134
1134
  for (const i of s) {
1135
1135
  const o = await this.storage.searchEntries(t, i);
1136
- for (const c of o)
1136
+ for (const r of o)
1137
1137
  n.push({
1138
- id: c.id,
1139
- title: c.title,
1140
- type: c.type,
1141
- author: c.author,
1142
- dynasty: c.dynasty
1138
+ id: r.id,
1139
+ title: r.title,
1140
+ type: r.type,
1141
+ author: r.author,
1142
+ dynasty: r.dynasty
1143
1143
  });
1144
1144
  }
1145
1145
  return n;
@@ -1201,7 +1201,7 @@ class Bt {
1201
1201
  extractTypeFromId(t) {
1202
1202
  try {
1203
1203
  const e = x(t);
1204
- return A(e).type;
1204
+ return $(e).type;
1205
1205
  } catch {
1206
1206
  return "book";
1207
1207
  }
@@ -1226,8 +1226,8 @@ class Bt {
1226
1226
  const s = e.page ?? 1, n = e.pageSize ?? 50;
1227
1227
  if (e.sortBy) {
1228
1228
  const l = e.sortBy, a = e.sortOrder === "desc" ? -1 : 1;
1229
- t.sort((u, h) => {
1230
- const d = u[l] ?? "", f = h[l] ?? "";
1229
+ t.sort((h, u) => {
1230
+ const d = h[l] ?? "", f = u[l] ?? "";
1231
1231
  return d < f ? -a : d > f ? a : 0;
1232
1232
  });
1233
1233
  }
@@ -1235,10 +1235,10 @@ class Bt {
1235
1235
  return { entries: t.slice(o, o + n), total: i, page: s, pageSize: n };
1236
1236
  }
1237
1237
  }
1238
- const xt = "/data", vt = 1e4;
1238
+ const vt = "/data", Ct = 1e4;
1239
1239
  class Ft {
1240
1240
  constructor(t = {}) {
1241
- this.indexCache = null, this.indexLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.chunkCache = /* @__PURE__ */ new Map(), this.chunkLoading = /* @__PURE__ */ new Map(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache = /* @__PURE__ */ new Map(), this.tiyaoLoading = /* @__PURE__ */ 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 ?? xt, this.timeout = t.timeout ?? vt;
1241
+ this.indexCache = null, this.indexLoading = null, this.pathMap = /* @__PURE__ */ new Map(), this.chunkCache = /* @__PURE__ */ new Map(), this.chunkLoading = /* @__PURE__ */ new Map(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache = /* @__PURE__ */ new Map(), this.tiyaoLoading = /* @__PURE__ */ new Map(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.metaCache = null, this.metaLoading = null, this.metaTried = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null, this.basePath = t.basePath ?? vt, this.timeout = t.timeout ?? Ct;
1242
1242
  }
1243
1243
  // ─── 内部工具 ───
1244
1244
  /**
@@ -1282,23 +1282,23 @@ class Ft {
1282
1282
  ["works", "work"],
1283
1283
  ["entities", "entity"]
1284
1284
  ];
1285
- for (const [o, c] of s) {
1285
+ for (const [o, r] of s) {
1286
1286
  const l = t[o];
1287
1287
  if (l)
1288
1288
  for (const a of Object.values(l)) {
1289
- const u = c === "entity" ? a.primary_name || a.title || a.name || a.id : a.title || a.name || a.id;
1289
+ const h = r === "entity" ? a.primary_name || a.title || a.name || a.id : a.title || a.name || a.id;
1290
1290
  e.push({
1291
1291
  id: a.id,
1292
- title: u,
1293
- type: c,
1292
+ title: h,
1293
+ type: r,
1294
1294
  isDraft: !0,
1295
1295
  // bundle 目前只打包 draft 数据
1296
1296
  author: a.author,
1297
1297
  dynasty: a.dynasty,
1298
1298
  role: a.role,
1299
1299
  path: a.path,
1300
- 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),
1301
- 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),
1300
+ additional_titles: (n = a.additional_titles) == null ? void 0 : n.map((u) => typeof u == "string" ? u : u == null ? void 0 : u.book_title).filter(Boolean),
1301
+ attached_texts: (i = a.attached_texts) == null ? void 0 : i.map((u) => typeof u == "string" ? u : u == null ? void 0 : u.book_title).filter(Boolean),
1302
1302
  edition: a.edition,
1303
1303
  juan_count: a.juan_count,
1304
1304
  has_text: a.has_text,
@@ -1426,11 +1426,11 @@ class Ft {
1426
1426
  if (this.tiyaoCache.has(s)) return this.tiyaoCache.get(s);
1427
1427
  const n = this.tiyaoLoading.get(s);
1428
1428
  if (n) return n;
1429
- const i = (c) => String(c).padStart(3, "0"), o = (async () => {
1430
- const c = await this.fetchJson(
1429
+ const i = (r) => String(r).padStart(3, "0"), o = (async () => {
1430
+ const r = await this.fetchJson(
1431
1431
  `${this.basePath}/tiyao/juan-${i(t)}-${i(e)}.json`
1432
1432
  );
1433
- return this.tiyaoCache.set(s, c), c;
1433
+ return this.tiyaoCache.set(s, r), r;
1434
1434
  })();
1435
1435
  this.tiyaoLoading.set(s, o);
1436
1436
  try {
@@ -1440,41 +1440,81 @@ class Ft {
1440
1440
  }
1441
1441
  }
1442
1442
  // ─── IndexStorage 实现 ───
1443
- async getResourceCounts() {
1443
+ /**
1444
+ * 获取轻量元数据(< 1 KB)。优先读 /data/meta.json;
1445
+ * 若该文件不存在(旧 bundle),回退到 ensureLoaded 计算。
1446
+ */
1447
+ async getCounts() {
1448
+ if (this.metaCache) return this.metaCache;
1449
+ if (this.metaLoading) {
1450
+ const h = await this.metaLoading;
1451
+ if (h) return h;
1452
+ } else {
1453
+ this.metaLoading = (async () => {
1454
+ try {
1455
+ const h = await this.fetchJson(`${this.basePath}/meta.json`);
1456
+ if (h && typeof h.works == "number")
1457
+ return this.metaCache = h, h;
1458
+ } catch {
1459
+ }
1460
+ return this.metaTried = !0, null;
1461
+ })();
1462
+ try {
1463
+ const h = await this.metaLoading;
1464
+ if (h) return h;
1465
+ } finally {
1466
+ this.metaLoading = null;
1467
+ }
1468
+ }
1444
1469
  const t = await this.ensureLoaded();
1445
- let e = 0, s = 0;
1446
- for (const n of t)
1447
- n.type === "work" && (n.has_text && e++, n.has_image && s++);
1448
- return { hasText: e, hasImage: s };
1470
+ let e = 0, s = 0, n = 0, i = 0, o = 0, r = 0;
1471
+ const l = {};
1472
+ for (const h of t)
1473
+ h.type === "work" ? (e++, h.has_text && o++, h.has_image && r++, h.subtype && (l[h.subtype] = (l[h.subtype] ?? 0) + 1)) : h.type === "book" ? s++ : h.type === "collection" ? n++ : h.type === "entity" && i++;
1474
+ const a = {
1475
+ works: e,
1476
+ books: s,
1477
+ collections: n,
1478
+ entities: i,
1479
+ resourceCounts: { hasText: o, hasImage: r },
1480
+ subtypeStats: l
1481
+ };
1482
+ return this.metaCache = a, a;
1483
+ }
1484
+ async getResourceCounts() {
1485
+ return (await this.getCounts()).resourceCounts ?? { hasText: 0, hasImage: 0 };
1486
+ }
1487
+ async getSubtypeStats() {
1488
+ return (await this.getCounts()).subtypeStats ?? {};
1449
1489
  }
1450
1490
  async loadEntries(t, e) {
1451
- let n = (await this.ensureLoaded()).filter((u) => u.type === t);
1491
+ let n = (await this.ensureLoaded()).filter((h) => h.type === t);
1452
1492
  const i = e.sortBy || "title", o = e.sortOrder || "asc";
1453
- n.sort((u, h) => {
1454
- const d = String(u[i] ?? ""), f = String(h[i] ?? ""), p = d.localeCompare(f, "zh");
1493
+ n.sort((h, u) => {
1494
+ const d = String(h[i] ?? ""), f = String(u[i] ?? ""), p = d.localeCompare(f, "zh");
1455
1495
  return o === "asc" ? p : -p;
1456
1496
  });
1457
- const c = e.page || 1, l = e.pageSize || 50, a = (c - 1) * l;
1497
+ const r = e.page || 1, l = e.pageSize || 50, a = (r - 1) * l;
1458
1498
  return {
1459
1499
  entries: n.slice(a, a + l),
1460
1500
  total: n.length,
1461
- page: c,
1501
+ page: r,
1462
1502
  pageSize: l
1463
1503
  };
1464
1504
  }
1465
1505
  async search(t, e, s) {
1466
- 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) : B(c, t), h = s.page || 1, d = s.pageSize || 50, f = (h - 1) * d;
1506
+ const n = await this.ensureLoaded(), i = await this.ensureSearchSLoaded(), o = await this.ensureT2S(), r = n.filter((p) => p.type === e), l = o ? o(t) : void 0, h = Object.keys(i).length > 0 ? O(r, t, l, i) : B(r, t), u = s.page || 1, d = s.pageSize || 50, f = (u - 1) * d;
1467
1507
  return {
1468
- entries: u.slice(f, f + d),
1469
- total: u.length,
1470
- page: h,
1508
+ entries: h.slice(f, f + d),
1509
+ total: h.length,
1510
+ page: u,
1471
1511
  pageSize: d
1472
1512
  };
1473
1513
  }
1474
1514
  async searchAll(t, e = 5) {
1475
- 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) => {
1476
- const h = s.filter((d) => d.type === u);
1477
- return l ? O(h, t, c, n) : B(h, t);
1515
+ const s = await this.ensureLoaded(), n = await this.ensureSearchSLoaded(), i = await this.ensureT2S(), o = ["work", "book", "collection", "entity"], r = i ? i(t) : void 0, l = Object.keys(n).length > 0, a = o.map((h) => {
1516
+ const u = s.filter((d) => d.type === h);
1517
+ return l ? O(u, t, r, n) : B(u, t);
1478
1518
  });
1479
1519
  return {
1480
1520
  works: a[0].slice(0, e),
@@ -1490,17 +1530,46 @@ class Ft {
1490
1530
  async getItem(t) {
1491
1531
  try {
1492
1532
  const s = (await this.loadChunkForId(t))[t] || null;
1493
- if (s) {
1494
- const n = (await this.ensureLoaded()).find((i) => i.id === t);
1495
- n != null && n.has_collated && (s.has_collated = !0), s.type === "entity" && !s.title && s.primary_name && (s.title = s.primary_name);
1496
- }
1497
- return s;
1533
+ return s && s.type === "entity" && !s.title && s.primary_name && (s.title = s.primary_name), s;
1498
1534
  } catch {
1499
1535
  return null;
1500
1536
  }
1501
1537
  }
1538
+ /**
1539
+ * 优先用 chunk 构造 IndexEntry,避免触发 ensureLoaded() 拉全量 index.json。
1540
+ * 旧 bundle 没有把 has_collated 等字段注入 chunk 时回退到 ensureLoaded。
1541
+ */
1502
1542
  async getEntry(t) {
1503
- return (await this.ensureLoaded()).find((s) => s.id === t) || null;
1543
+ var s, n;
1544
+ try {
1545
+ const o = (await this.loadChunkForId(t))[t];
1546
+ if (o) {
1547
+ const r = pt(t), l = r === "entity" ? o.primary_name || o.title || o.name || t : o.title || o.name || t;
1548
+ return {
1549
+ id: t,
1550
+ title: l,
1551
+ type: r,
1552
+ isDraft: !0,
1553
+ author: o.author,
1554
+ dynasty: o.dynasty,
1555
+ role: o.role,
1556
+ additional_titles: (s = o.additional_titles) == null ? void 0 : s.map((a) => typeof a == "string" ? a : a == null ? void 0 : a.book_title).filter(Boolean),
1557
+ attached_texts: (n = o.attached_texts) == null ? void 0 : n.map((a) => typeof a == "string" ? a : a == null ? void 0 : a.book_title).filter(Boolean),
1558
+ edition: o.edition,
1559
+ juan_count: o.juan_count,
1560
+ has_text: o.has_text,
1561
+ has_image: o.has_image,
1562
+ has_collated: o.has_collated,
1563
+ subtype: o.subtype,
1564
+ primary_name: o.primary_name,
1565
+ birth_year: o.birth_year,
1566
+ death_year: o.death_year,
1567
+ cbdb_id: o.cbdb_id
1568
+ };
1569
+ }
1570
+ } catch {
1571
+ }
1572
+ return (await this.ensureLoaded()).find((i) => i.id === t) || null;
1504
1573
  }
1505
1574
  async getAllEntries() {
1506
1575
  return this.ensureLoaded();
@@ -1565,8 +1634,8 @@ class Ft {
1565
1634
  if (e.includes("..") || !e.endsWith(".json")) return null;
1566
1635
  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;
1567
1636
  try {
1568
- const c = await fetch(o);
1569
- return c.ok ? await c.text() : null;
1637
+ const r = await fetch(o);
1638
+ return r.ok ? await r.text() : null;
1570
1639
  } catch {
1571
1640
  return null;
1572
1641
  }
@@ -1609,7 +1678,7 @@ class Ft {
1609
1678
  }
1610
1679
  // ─── 工具 ───
1611
1680
  clearCache() {
1612
- 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;
1681
+ this.indexCache = null, this.indexLoading = null, this.pathMap.clear(), this.chunkCache.clear(), this.chunkLoading.clear(), this.manifest = null, this.manifestLoading = null, this.tiyaoCache.clear(), this.tiyaoLoading.clear(), this.searchSCache = null, this.searchSLoading = null, this.searchSLoaded = !1, this.metaCache = null, this.metaLoading = null, this.metaTried = !1, this.t2sConverter = null, this.t2sLoading = null, this.version = void 0, this.versionPromise = null;
1613
1682
  }
1614
1683
  }
1615
1684
  class F extends Error {
@@ -1632,14 +1701,14 @@ class Ot extends F {
1632
1701
  super(t), this.name = "ConfigError";
1633
1702
  }
1634
1703
  }
1635
- class Ut extends F {
1704
+ class Dt extends F {
1636
1705
  constructor(t) {
1637
1706
  super(t), this.name = "MigrationError";
1638
1707
  }
1639
1708
  }
1640
- class Dt {
1709
+ class Ut {
1641
1710
  constructor(t, e, s = 1) {
1642
- this.storage = new it(t, e), this.idGen = new rt(s);
1711
+ this.storage = new it(t, e), this.idGen = new at(s);
1643
1712
  }
1644
1713
  /** Generate a new unique ID (returns raw bigint). */
1645
1714
  generateId(t = "book", e = "draft") {
@@ -1647,7 +1716,7 @@ class Dt {
1647
1716
  }
1648
1717
  /** Encode a bigint ID to Base36 string. */
1649
1718
  encodeId(t) {
1650
- return U(t);
1719
+ return D(t);
1651
1720
  }
1652
1721
  /** Decode an ID string to bigint (supports base36 and legacy base58). */
1653
1722
  decodeId(t) {
@@ -1686,13 +1755,13 @@ class Dt {
1686
1755
  资源: "resources",
1687
1756
  收藏历史: "history",
1688
1757
  其他版本: "related_books"
1689
- }, c = e in o ? o[e] : e;
1690
- if (c === null) return !1;
1691
- if (c === "description" && typeof s == "string") {
1692
- const a = i[c] || {};
1693
- i[c] = { text: s, sources: a.sources || [] };
1758
+ }, r = e in o ? o[e] : e;
1759
+ if (r === null) return !1;
1760
+ if (r === "description" && typeof s == "string") {
1761
+ const a = i[r] || {};
1762
+ i[r] = { text: s, sources: a.sources || [] };
1694
1763
  } else
1695
- i[c] = s;
1764
+ i[r] = s;
1696
1765
  const l = L(t);
1697
1766
  return await this.storage.saveItem(l.type, t, i), !0;
1698
1767
  } catch {
@@ -1736,10 +1805,10 @@ const Et = {
1736
1805
  "guji.artx": "guji-artx",
1737
1806
  "digital.library": "digital-library"
1738
1807
  }, q = /* @__PURE__ */ new Set(["text", "image", "text+image", "physical"]), Y = /* @__PURE__ */ new Set(["text", "image", "physical"]), $t = /* @__PURE__ */ new Set(["catalog", "search"]), At = /* @__PURE__ */ new Set(["com", "org", "net", "cn", "edu", "gov", "io", "jp", "tw", "hk"]);
1739
- function Nt(r) {
1740
- if (!r) return "";
1808
+ function Nt(c) {
1809
+ if (!c) return "";
1741
1810
  try {
1742
- const e = new URL(r).hostname;
1811
+ const e = new URL(c).hostname;
1743
1812
  for (const [n, i] of Object.entries(Et))
1744
1813
  if (e.includes(n)) return i;
1745
1814
  const s = e.split(".");
@@ -1752,20 +1821,20 @@ function Nt(r) {
1752
1821
  return "";
1753
1822
  }
1754
1823
  }
1755
- function Wt(r) {
1824
+ function Jt(c) {
1756
1825
  const t = [];
1757
- r.name || t.push("name is required");
1826
+ c.name || t.push("name is required");
1758
1827
  let e = !1;
1759
- if (r.types !== void 0)
1760
- if (!Array.isArray(r.types) || r.types.length === 0)
1828
+ if (c.types !== void 0)
1829
+ if (!Array.isArray(c.types) || c.types.length === 0)
1761
1830
  t.push("types must be a non-empty array when present");
1762
1831
  else {
1763
- for (const s of r.types)
1832
+ for (const s of c.types)
1764
1833
  Y.has(s) || t.push(`invalid types atom '${s}', must be one of ${[...Y].join(", ")}`);
1765
- e = r.types.length === 1 && r.types[0] === "physical";
1834
+ e = c.types.length === 1 && c.types[0] === "physical";
1766
1835
  }
1767
- else r.type !== void 0 ? (q.has(r.type) || t.push(`invalid type '${r.type}', must be one of ${[...q].join(", ")}`), e = r.type === "physical") : t.push("either type or types is required");
1768
- return r.root_type && !$t.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;
1836
+ else c.type !== void 0 ? (q.has(c.type) || t.push(`invalid type '${c.type}', must be one of ${[...q].join(", ")}`), e = c.type === "physical") : t.push("either type or types is required");
1837
+ return c.root_type && !$t.has(c.root_type) && t.push(`invalid root_type '${c.root_type}'`), !e && !c.url && t.push("url is required for non-physical resources"), t;
1769
1838
  }
1770
1839
  const w = class w {
1771
1840
  constructor(t, e = "") {
@@ -1777,7 +1846,7 @@ const w = class w {
1777
1846
  this.idInt = 0n;
1778
1847
  }
1779
1848
  } else
1780
- this.idInt = t, this.idStr = U(t);
1849
+ this.idInt = t, this.idStr = D(t);
1781
1850
  if (this.idInt > 0n)
1782
1851
  try {
1783
1852
  const s = L(this.idStr);
@@ -1817,25 +1886,25 @@ export {
1817
1886
  Lt as G,
1818
1887
  Rt as I,
1819
1888
  Bt as L,
1820
- Ut as M,
1889
+ Dt as M,
1821
1890
  Mt as S,
1822
- jt as a,
1891
+ pt as a,
1823
1892
  F as b,
1824
- Dt as c,
1893
+ Ut as c,
1825
1894
  it as d,
1826
1895
  Tt as e,
1827
1896
  Ft as f,
1828
- rt as g,
1897
+ at as g,
1829
1898
  st as h,
1830
- U as i,
1899
+ D as i,
1831
1900
  gt as j,
1832
1901
  z as k,
1833
1902
  Pt as l,
1834
1903
  L as m,
1835
- Ct as n,
1904
+ jt as n,
1836
1905
  Nt as o,
1837
1906
  ot as p,
1838
- A as q,
1907
+ $ as q,
1839
1908
  x as s,
1840
- Wt as v
1909
+ Jt as v
1841
1910
  };