@mastra/libsql 1.29.0-alpha.1 → 1.29.0

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.js CHANGED
@@ -6649,7 +6649,8 @@ const KNOWLEDGE_PAGES_CORE_FUNCTIONS = [
6649
6649
  const KNOWLEDGE_PAGES_CORE_NUMBERS = [
6650
6650
  "MAX_KNOWLEDGE_MOVE_PAGES",
6651
6651
  "MAX_KNOWLEDGE_PAGE_DEPTH",
6652
- "MAX_KNOWLEDGE_PAGE_LIST_LIMIT"
6652
+ "MAX_KNOWLEDGE_PAGE_LIST_LIMIT",
6653
+ "MAX_KNOWLEDGE_PAGE_LINKS"
6653
6654
  ];
6654
6655
  function resolveKnowledgePagesCore(storageModule) {
6655
6656
  const module = typeof storageModule === "object" && storageModule !== null ? storageModule : {};
@@ -6670,16 +6671,18 @@ function createKnowledgePagesCoreLoader(features, loadStorageModule) {
6670
6671
  };
6671
6672
  }
6672
6673
  /**
6673
- * Keyword-search words: the query split on whitespace, lowercased, deduplicated. A hit needs at
6674
- * least one of them (as a case-insensitive substring); an empty list means the search returns nothing.
6674
+ * Keyword-search words: the query split on whitespace, lowercased, deduplicated, keeping the first
6675
+ * {@link KNOWLEDGE_SEARCH_MAX_WORDS}. A hit needs at least one of them (as a case-insensitive
6676
+ * substring); an empty list means the search returns nothing.
6675
6677
  */
6676
6678
  function knowledgeSearchWords(query) {
6677
- return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
6679
+ return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))].slice(0, 16);
6678
6680
  }
6679
6681
  /**
6680
6682
  * Points one matched search word earns on a page, by the best field it appears in: name, then
6681
- * description, then body. Pages rank by how many query words they match first; these points only
6682
- * break ties between pages that match the same number of words.
6683
+ * description, then body. A page whose name contains the whole query ranks first; below that, pages
6684
+ * rank by how many query words they match, and these points only break ties between pages that
6685
+ * match the same number of words.
6683
6686
  */
6684
6687
  const KNOWLEDGE_SEARCH_WEIGHTS = {
6685
6688
  name: 3,
@@ -6705,9 +6708,37 @@ const KNOWLEDGE_PAGE_TABLES = {
6705
6708
  mentions: "mastra_knowledge_mentions",
6706
6709
  pins: "mastra_knowledge_pins",
6707
6710
  pinAudiences: "mastra_knowledge_pin_audiences",
6708
- activity: "mastra_knowledge_activity"
6711
+ activity: "mastra_knowledge_activity",
6712
+ links: "mastra_knowledge_page_links"
6709
6713
  };
6710
6714
  const T = KNOWLEDGE_PAGE_TABLES;
6715
+ function pinsTableDDL(name) {
6716
+ return `CREATE TABLE IF NOT EXISTS "${name}" (
6717
+ id TEXT PRIMARY KEY,
6718
+ pageId TEXT NOT NULL,
6719
+ kind TEXT NOT NULL DEFAULT 'page',
6720
+ depth INTEGER,
6721
+ audience TEXT NOT NULL,
6722
+ createdBy TEXT NOT NULL,
6723
+ createdAt TEXT NOT NULL,
6724
+ updatedAt TEXT NOT NULL,
6725
+ UNIQUE (pageId, kind)
6726
+ )`;
6727
+ }
6728
+ /**
6729
+ * Pins tables from before pin kinds kept one pin per page (`pageId UNIQUE`). SQLite can't drop that
6730
+ * constraint in place, so the table is rebuilt with every existing pin as a `page` pin. Run after
6731
+ * {@link KNOWLEDGE_PAGE_DDL}, in the same transaction; a no-op once `kind` exists.
6732
+ */
6733
+ async function upgradeKnowledgePinKinds(tx) {
6734
+ if ((await tx.execute(`SELECT name FROM pragma_table_info('${T.pins}')`)).rows.some((row) => String(row.name) === "kind")) return;
6735
+ const next = `${T.pins}_kinds`;
6736
+ await tx.execute(`DROP TABLE IF EXISTS "${next}"`);
6737
+ await tx.execute(pinsTableDDL(next));
6738
+ await tx.execute(`INSERT INTO "${next}" (id, pageId, kind, audience, createdBy, createdAt, updatedAt) SELECT id, pageId, 'page', audience, createdBy, createdAt, updatedAt FROM "${T.pins}"`);
6739
+ await tx.execute(`DROP TABLE "${T.pins}"`);
6740
+ await tx.execute(`ALTER TABLE "${next}" RENAME TO "${T.pins}"`);
6741
+ }
6711
6742
  /** DDL for the schema-4 page tables, in creation order. Every statement is idempotent. */
6712
6743
  const KNOWLEDGE_PAGE_DDL = [
6713
6744
  `CREATE TABLE IF NOT EXISTS "mastra_knowledge_access_state" (
@@ -6771,14 +6802,7 @@ const KNOWLEDGE_PAGE_DDL = [
6771
6802
  PRIMARY KEY (noteId, pageId)
6772
6803
  )`,
6773
6804
  `CREATE INDEX IF NOT EXISTS idx_kmentions_page ON "${T.mentions}" (pageId)`,
6774
- `CREATE TABLE IF NOT EXISTS "${T.pins}" (
6775
- id TEXT PRIMARY KEY,
6776
- pageId TEXT NOT NULL UNIQUE,
6777
- audience TEXT NOT NULL,
6778
- createdBy TEXT NOT NULL,
6779
- createdAt TEXT NOT NULL,
6780
- updatedAt TEXT NOT NULL
6781
- )`,
6805
+ pinsTableDDL(T.pins),
6782
6806
  `CREATE TABLE IF NOT EXISTS "${T.pinAudiences}" (
6783
6807
  pinId TEXT NOT NULL,
6784
6808
  audience TEXT NOT NULL,
@@ -6795,7 +6819,16 @@ const KNOWLEDGE_PAGE_DDL = [
6795
6819
  provenance TEXT NOT NULL,
6796
6820
  createdAt TEXT NOT NULL
6797
6821
  )`,
6798
- `CREATE INDEX IF NOT EXISTS idx_kactivity_page ON "${T.activity}" (pageId, id DESC)`
6822
+ `CREATE INDEX IF NOT EXISTS idx_kactivity_page ON "${T.activity}" (pageId, id DESC)`,
6823
+ `CREATE TABLE IF NOT EXISTS "${T.links}" (
6824
+ fromPageId TEXT NOT NULL,
6825
+ ref TEXT NOT NULL,
6826
+ toPageId TEXT,
6827
+ count INTEGER NOT NULL,
6828
+ PRIMARY KEY (fromPageId, ref)
6829
+ ) WITHOUT ROWID`,
6830
+ `CREATE INDEX IF NOT EXISTS idx_klinks_to ON "${T.links}" (toPageId) WHERE toPageId IS NOT NULL`,
6831
+ `CREATE INDEX IF NOT EXISTS idx_klinks_ref ON "${T.links}" (ref) WHERE toPageId IS NULL`
6799
6832
  ];
6800
6833
  function str(value) {
6801
6834
  return value === null || value === void 0 ? void 0 : String(value);
@@ -6850,6 +6883,8 @@ function toPin(row) {
6850
6883
  return {
6851
6884
  id: String(row.id),
6852
6885
  pageId: String(row.pageId),
6886
+ kind: String(row.kind),
6887
+ ...row.depth !== null && row.depth !== void 0 ? { depth: Number(row.depth) } : {},
6853
6888
  audience: JSON.parse(String(row.audience)),
6854
6889
  createdBy: String(row.createdBy),
6855
6890
  createdAt: new Date(String(row.createdAt)),
@@ -6978,10 +7013,11 @@ var LibSQLKnowledgePages = class {
6978
7013
  this.#read = config.read;
6979
7014
  this.#transaction = config.transaction;
6980
7015
  }
6981
- /** Deletes every row from the page tables (scopes, pages, notes, pins, activity). */
7016
+ /** Deletes every row from the page tables (scopes, pages, notes, pins, activity, links). */
6982
7017
  async clearAll() {
6983
7018
  await this.#transaction(async (tx) => {
6984
7019
  for (const table of [
7020
+ T.links,
6985
7021
  T.activity,
6986
7022
  T.pinAudiences,
6987
7023
  T.pins,
@@ -7163,13 +7199,19 @@ var LibSQLKnowledgePages = class {
7163
7199
  const limit = limitOf(input.limit, core.MAX_KNOWLEDGE_PAGE_LIST_LIMIT);
7164
7200
  const cursor = decodeCursor(input.cursor, 2);
7165
7201
  const args = [input.parentId];
7202
+ let filter = "";
7203
+ if (input.read) {
7204
+ const readable = readableScopes(input.read);
7205
+ filter = ` AND id IN (${readable.sql})`;
7206
+ args.push(...readable.args);
7207
+ }
7166
7208
  let after = "";
7167
7209
  if (cursor) {
7168
7210
  after = ` AND (position > ? OR (position = ? AND id > ?))`;
7169
7211
  args.push(cursor[0], cursor[0], cursor[1]);
7170
7212
  }
7171
7213
  args.push(limit + 1);
7172
- const rows = await this.#query(this.#read, `SELECT * FROM "${T.pages}" WHERE isScope = 1 AND parentId IS ?${after} ORDER BY position, id LIMIT ?`, args);
7214
+ const rows = await this.#query(this.#read, `SELECT * FROM "${T.pages}" WHERE isScope = 1 AND parentId IS ?${filter}${after} ORDER BY position, id LIMIT ?`, args);
7173
7215
  return this.#pageOutput(rows, limit, (row) => [String(row.position), String(row.id)]);
7174
7216
  }
7175
7217
  #pageOutput(rows, limit, cursorOf) {
@@ -7454,9 +7496,8 @@ var LibSQLKnowledgePages = class {
7454
7496
  args: [input.sourceId]
7455
7497
  });
7456
7498
  const pins = await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId IN (?, ?)`, [input.sourceId, input.targetId]);
7457
- const sourcePin = pins.find((pin) => String(pin.pageId) === input.sourceId);
7458
- if (sourcePin) {
7459
- const targetPin = pins.find((pin) => String(pin.pageId) === input.targetId);
7499
+ for (const sourcePin of pins.filter((pin) => String(pin.pageId) === input.sourceId)) {
7500
+ const targetPin = pins.find((pin) => String(pin.pageId) === input.targetId && pin.kind === sourcePin.kind);
7460
7501
  const audience = JSON.parse(String(sourcePin.audience));
7461
7502
  if (targetPin) {
7462
7503
  const merged = [.../* @__PURE__ */ new Set([...JSON.parse(String(targetPin.audience)), ...audience])];
@@ -7556,6 +7597,15 @@ var LibSQLKnowledgePages = class {
7556
7597
  const rows = await this.#query(this.#read, `SELECT n.* FROM "${T.notes}" n WHERE n.pageId = ?${input.includeDeleted ? "" : " AND n.deletedAt IS NULL"} AND ${readable.sql}${after} ORDER BY n.createdAt, n.id LIMIT ?`, args);
7557
7598
  return this.#noteOutput(rows, limit);
7558
7599
  }
7600
+ async countChildScopes(input) {
7601
+ const ids = [...new Set(input.parentIds)];
7602
+ const counts = Object.fromEntries(ids.map((id) => [id, 0]));
7603
+ if (ids.length === 0) return counts;
7604
+ const readable = readableScopes(input.read);
7605
+ const rows = await this.#query(this.#read, `SELECT parentId, COUNT(*) AS total FROM "${T.pages}" WHERE parentId IN (SELECT value FROM json_each(?)) AND isScope = 1 AND id IN (${readable.sql}) GROUP BY parentId`, [jsonList(ids), ...readable.args]);
7606
+ for (const row of rows) counts[String(row.parentId)] = Number(row.total);
7607
+ return counts;
7608
+ }
7559
7609
  async countChildPages(input) {
7560
7610
  const ids = [...new Set(input.parentIds)];
7561
7611
  const counts = Object.fromEntries(ids.map((id) => [id, 0]));
@@ -7565,6 +7615,111 @@ var LibSQLKnowledgePages = class {
7565
7615
  for (const row of rows) counts[String(row.parentId)] = Number(row.total);
7566
7616
  return counts;
7567
7617
  }
7618
+ async replacePageBodyLinks(input) {
7619
+ await this.#transaction(async (tx) => {
7620
+ await tx.execute({
7621
+ sql: `DELETE FROM "${T.links}" WHERE fromPageId = ?`,
7622
+ args: [input.pageId]
7623
+ });
7624
+ if (input.links.length === 0) return;
7625
+ await tx.execute({
7626
+ sql: `INSERT INTO "${T.links}" (fromPageId, ref, toPageId, count) SELECT ?, json_extract(value, '$.ref'), json_extract(value, '$.toPageId'), json_extract(value, '$.count') FROM json_each(?)`,
7627
+ args: [input.pageId, JSON.stringify(input.links.map(({ ref, toPageId, count }) => ({
7628
+ ref,
7629
+ toPageId,
7630
+ count
7631
+ })))]
7632
+ });
7633
+ });
7634
+ }
7635
+ async listPageBodyLinkSources(input) {
7636
+ const refs = input.refs ?? [];
7637
+ const targets = input.toPageIds ?? [];
7638
+ if (refs.length === 0 && targets.length === 0) return [];
7639
+ return (await this.#query(this.#read, `SELECT DISTINCT fromPageId FROM "${T.links}" WHERE (toPageId IS NULL AND ref IN (SELECT value FROM json_each(?))) OR toPageId IN (SELECT value FROM json_each(?)) ORDER BY fromPageId`, [jsonList(refs), jsonList(targets)])).map((row) => String(row.fromPageId));
7640
+ }
7641
+ /**
7642
+ * Visible links touching `ids` (from them for `out`, to them for `in`): resolved, both ends live
7643
+ * and readable, not self-links; a note link also needs a visible live note. One row per
7644
+ * (from, to, kind), counts summed.
7645
+ */
7646
+ async #links(read, kinds, ids, direction) {
7647
+ const wanted = new Set(kinds ?? ["body", "note"]);
7648
+ const touches = (from, to) => {
7649
+ const parts = [];
7650
+ const args = [];
7651
+ if (direction !== "in") {
7652
+ parts.push(`${from} IN (SELECT value FROM json_each(?))`);
7653
+ args.push(jsonList(ids));
7654
+ }
7655
+ if (direction !== "out") {
7656
+ parts.push(`${to} IN (SELECT value FROM json_each(?))`);
7657
+ args.push(jsonList(ids));
7658
+ }
7659
+ return {
7660
+ sql: `(${parts.join(" OR ")})`,
7661
+ args
7662
+ };
7663
+ };
7664
+ const sources = [];
7665
+ const args = [];
7666
+ if (wanted.has("body")) {
7667
+ const near = touches("l.fromPageId", "l.toPageId");
7668
+ sources.push(`SELECT l.fromPageId AS fromPageId, l.toPageId AS toPageId, 'body' AS kind, l.count AS count FROM "${T.links}" l WHERE l.toPageId IS NOT NULL AND ${near.sql}`);
7669
+ args.push(...near.args);
7670
+ }
7671
+ if (wanted.has("note")) {
7672
+ const near = touches("n.pageId", "m.pageId");
7673
+ const visible = noteReadable("n", read);
7674
+ sources.push(`SELECT n.pageId AS fromPageId, m.pageId AS toPageId, 'note' AS kind, 1 AS count FROM "${T.mentions}" m JOIN "${T.notes}" n ON n.id = m.noteId WHERE n.deletedAt IS NULL AND ${near.sql} AND ${visible.sql}`);
7675
+ args.push(...near.args, ...visible.args);
7676
+ }
7677
+ if (sources.length === 0) return [];
7678
+ const fromReadable = pageReadable("fp", read);
7679
+ const toReadable = pageReadable("tp", read);
7680
+ return this.#query(this.#read, `SELECT e.fromPageId AS fromPageId, e.toPageId AS toPageId, e.kind AS kind, SUM(e.count) AS count
7681
+ FROM (${sources.join(" UNION ALL ")}) e
7682
+ JOIN "${T.pages}" fp ON fp.id = e.fromPageId AND fp.deletedAt IS NULL AND ${fromReadable.sql}
7683
+ JOIN "${T.pages}" tp ON tp.id = e.toPageId AND tp.deletedAt IS NULL AND ${toReadable.sql}
7684
+ WHERE e.fromPageId <> e.toPageId
7685
+ GROUP BY e.fromPageId, e.toPageId, e.kind
7686
+ ORDER BY e.fromPageId, e.toPageId, CASE e.kind WHEN 'body' THEN 0 ELSE 1 END`, [
7687
+ ...args,
7688
+ ...fromReadable.args,
7689
+ ...toReadable.args
7690
+ ]);
7691
+ }
7692
+ async countPageLinks(input) {
7693
+ const ids = [...new Set(input.pageIds)];
7694
+ const linked = new Map(ids.map((id) => [id, {
7695
+ in: /* @__PURE__ */ new Set(),
7696
+ out: /* @__PURE__ */ new Set()
7697
+ }]));
7698
+ if (ids.length === 0) return {};
7699
+ for (const row of await this.#links(input.read, input.kinds, ids, "both")) {
7700
+ const from = String(row.fromPageId);
7701
+ const to = String(row.toPageId);
7702
+ linked.get(from)?.out.add(to);
7703
+ linked.get(to)?.in.add(from);
7704
+ }
7705
+ return Object.fromEntries([...linked].map(([id, sets]) => [id, {
7706
+ in: sets.in.size,
7707
+ out: sets.out.size
7708
+ }]));
7709
+ }
7710
+ async listPageLinks(input) {
7711
+ const limit = input.limit ?? 1e3;
7712
+ if (!Number.isInteger(limit) || limit < 1) throw new RangeError("Knowledge link limit must be a positive integer");
7713
+ const ids = [...new Set(input.pageIds)];
7714
+ if (ids.length === 0) return [];
7715
+ const core = await loadPagesCore();
7716
+ return (await this.#links(input.read, input.kinds, ids, input.direction ?? "both")).slice(0, Math.min(limit, core.MAX_KNOWLEDGE_PAGE_LINKS)).map((row) => ({
7717
+ fromPageId: String(row.fromPageId),
7718
+ toPageId: String(row.toPageId),
7719
+ kind: row.kind === "note" ? "note" : "body",
7720
+ count: Number(row.count)
7721
+ }));
7722
+ }
7568
7723
  async countNotes(input) {
7569
7724
  const ids = [...new Set(input.pageIds)];
7570
7725
  const counts = Object.fromEntries(ids.map((id) => [id, 0]));
@@ -7826,17 +7981,21 @@ var LibSQLKnowledgePages = class {
7826
7981
  });
7827
7982
  }
7828
7983
  addPinAudience(input) {
7984
+ const kind = input.kind ?? "page";
7985
+ const depth = kind === "list" ? input.depth ?? 1 : null;
7829
7986
  return this.#transaction(async (tx) => {
7830
7987
  const page = await this.#livePage(tx, input.pageId);
7831
7988
  const now = (/* @__PURE__ */ new Date()).toISOString();
7832
- const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ?`, [input.pageId]))[0];
7989
+ const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ? AND kind = ?`, [input.pageId, kind]))[0];
7833
7990
  if (!existing) {
7834
7991
  const id = createKnowledgeUlid();
7835
7992
  await tx.execute({
7836
- sql: `INSERT INTO "${T.pins}" (id, pageId, audience, createdBy, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?)`,
7993
+ sql: `INSERT INTO "${T.pins}" (id, pageId, kind, depth, audience, createdBy, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
7837
7994
  args: [
7838
7995
  id,
7839
7996
  input.pageId,
7997
+ kind,
7998
+ depth,
7840
7999
  JSON.stringify([...new Set(input.audience)]),
7841
8000
  input.createdBy,
7842
8001
  now,
@@ -7853,11 +8012,13 @@ var LibSQLKnowledgePages = class {
7853
8012
  }
7854
8013
  const current = JSON.parse(String(existing.audience));
7855
8014
  const merged = [.../* @__PURE__ */ new Set([...current, ...input.audience])];
7856
- if (merged.length !== current.length) {
8015
+ const depthChanged = (existing.depth === null ? null : Number(existing.depth)) !== depth;
8016
+ if (merged.length !== current.length || depthChanged) {
7857
8017
  await tx.execute({
7858
- sql: `UPDATE "${T.pins}" SET audience = ?, updatedAt = ? WHERE id = ?`,
8018
+ sql: `UPDATE "${T.pins}" SET audience = ?, depth = ?, updatedAt = ? WHERE id = ?`,
7859
8019
  args: [
7860
8020
  JSON.stringify(merged),
8021
+ depth,
7861
8022
  now,
7862
8023
  String(existing.id)
7863
8024
  ]
@@ -7874,7 +8035,7 @@ var LibSQLKnowledgePages = class {
7874
8035
  }
7875
8036
  removePinAudience(input) {
7876
8037
  return this.#transaction(async (tx) => {
7877
- const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ?`, [input.pageId]))[0];
8038
+ const existing = (await this.#query(tx, `SELECT * FROM "${T.pins}" WHERE pageId = ? AND kind = ?`, [input.pageId, input.kind ?? "page"]))[0];
7878
8039
  if (!existing) return null;
7879
8040
  const current = JSON.parse(String(existing.audience));
7880
8041
  const remove = new Set(input.audience);
@@ -7918,15 +8079,19 @@ var LibSQLKnowledgePages = class {
7918
8079
  filters += ` AND pin.id IN (SELECT pa.pinId FROM json_each(?) a JOIN "${T.pinAudiences}" pa ON pa.audience = a.value)`;
7919
8080
  args.push(jsonList(input.audience));
7920
8081
  }
8082
+ if (input.kind) {
8083
+ filters += ` AND pin.kind = ?`;
8084
+ args.push(input.kind);
8085
+ }
7921
8086
  if (input.pageIds) {
7922
8087
  filters += ` AND pin.pageId IN (SELECT value FROM json_each(?))`;
7923
8088
  args.push(jsonList(input.pageIds));
7924
8089
  }
7925
8090
  if (input.excludePageIds?.length) {
7926
- filters += ` AND pin.pageId NOT IN (SELECT value FROM json_each(?))`;
8091
+ filters += ` AND (pin.kind <> 'page' OR pin.pageId NOT IN (SELECT value FROM json_each(?)))`;
7927
8092
  args.push(jsonList(input.excludePageIds));
7928
8093
  }
7929
- if (input.withBody) filters += ` AND p.body IS NOT NULL AND trim(p.body, char(32, 9, 10, 11, 12, 13)) <> ''`;
8094
+ if (input.withBody) filters += ` AND (pin.kind <> 'page' OR (p.body IS NOT NULL AND trim(p.body, char(32, 9, 10, 11, 12, 13)) <> ''))`;
7930
8095
  const from = `FROM "${T.pins}" pin JOIN "${T.pages}" p ON p.id = pin.pageId WHERE p.deletedAt IS NULL AND ${readable.sql}${filters}`;
7931
8096
  let total;
7932
8097
  if (input.count) total = Number((await this.#query(this.#read, `SELECT COUNT(*) AS n ${from}`, args))[0].n);
@@ -7998,7 +8163,8 @@ var KnowledgeLibSQL = class extends KnowledgeStorage {
7998
8163
  contractVersion: 4,
7999
8164
  schemaVersion: 4,
8000
8165
  supportsSchemaInspection: true,
8001
- supportsExplicitReset: true
8166
+ supportsExplicitReset: true,
8167
+ supportsPinKinds: true
8002
8168
  };
8003
8169
  }
8004
8170
  async dangerouslyClearAll() {
@@ -8028,6 +8194,7 @@ var KnowledgeLibSQL = class extends KnowledgeStorage {
8028
8194
  const inspection = await this.#inspectPages(tx);
8029
8195
  if (inspection.status === "incompatible-reset-required") throw new KnowledgeSchemaResetRequiredError(inspection);
8030
8196
  for (const statement of KNOWLEDGE_PAGE_DDL) await tx.execute(statement);
8197
+ await upgradeKnowledgePinKinds(tx);
8031
8198
  await tx.execute({
8032
8199
  sql: `INSERT OR IGNORE INTO "${TABLE_KNOWLEDGE_PAGES_STATE}" (id, schemaVersion) VALUES ('knowledge', ?)`,
8033
8200
  args: [4]
@@ -8036,7 +8203,11 @@ var KnowledgeLibSQL = class extends KnowledgeStorage {
8036
8203
  }
8037
8204
  async dangerouslyReset() {
8038
8205
  await withClientWriteLock(this.#client, async () => {
8039
- await this.#client.batch([...KNOWLEDGE_RESETTABLE_TABLE_NAMES, KNOWLEDGE_PAGE_TABLES.pinAudiences].map((table) => ({
8206
+ await this.#client.batch([
8207
+ ...KNOWLEDGE_RESETTABLE_TABLE_NAMES,
8208
+ KNOWLEDGE_PAGE_TABLES.pinAudiences,
8209
+ KNOWLEDGE_PAGE_TABLES.links
8210
+ ].map((table) => ({
8040
8211
  sql: `DROP TABLE IF EXISTS "${table}"`,
8041
8212
  args: []
8042
8213
  })), "write");
@@ -8058,6 +8229,9 @@ var KnowledgeLibSQL = class extends KnowledgeStorage {
8058
8229
  listChildScopes(input) {
8059
8230
  return this.#pages.listChildScopes(input);
8060
8231
  }
8232
+ countChildScopes(input) {
8233
+ return this.#pages.countChildScopes(input);
8234
+ }
8061
8235
  getPage(input) {
8062
8236
  return this.#pages.getPage(input);
8063
8237
  }
@@ -8097,6 +8271,18 @@ var KnowledgeLibSQL = class extends KnowledgeStorage {
8097
8271
  countChildPages(input) {
8098
8272
  return this.#pages.countChildPages(input);
8099
8273
  }
8274
+ replacePageBodyLinks(input) {
8275
+ return this.#pages.replacePageBodyLinks(input);
8276
+ }
8277
+ listPageBodyLinkSources(input) {
8278
+ return this.#pages.listPageBodyLinkSources(input);
8279
+ }
8280
+ countPageLinks(input) {
8281
+ return this.#pages.countPageLinks(input);
8282
+ }
8283
+ listPageLinks(input) {
8284
+ return this.#pages.listPageLinks(input);
8285
+ }
8100
8286
  countNotes(input) {
8101
8287
  return this.#pages.countNotes(input);
8102
8288
  }