@fedify/botkit-sqlite 0.4.3 → 0.4.4

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/mod.d.ts CHANGED
@@ -47,6 +47,7 @@ declare class SqliteRepository implements Repository, Disposable {
47
47
  countMessages(): Promise<number>;
48
48
  addFollower(followRequestId: URL, follower: Actor): Promise<void>;
49
49
  removeFollower(followRequestId: URL, actorId: URL): Promise<Actor | undefined>;
50
+ private cleanupFollower;
50
51
  hasFollower(followerId: URL): Promise<boolean>;
51
52
  getFollowers(options?: RepositoryGetFollowersOptions): AsyncIterable<Actor>;
52
53
  countFollowers(): Promise<number>;
package/dist/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/mod.js CHANGED
@@ -65,6 +65,10 @@ var SqliteRepository = class {
65
65
  follower_id TEXT NOT NULL,
66
66
  FOREIGN KEY (follower_id) REFERENCES followers(follower_id)
67
67
  )
68
+ `);
69
+ this.db.exec(`
70
+ CREATE INDEX IF NOT EXISTS idx_follow_requests_follower
71
+ ON follow_requests(follower_id)
68
72
  `);
69
73
  this.db.exec(`
70
74
  CREATE TABLE IF NOT EXISTS sent_follows (
@@ -235,17 +239,26 @@ var SqliteRepository = class {
235
239
  if (follower.id == null) throw new TypeError("The follower ID is missing.");
236
240
  const followerJson = JSON.stringify(await follower.toJsonLd({ format: "compact" }));
237
241
  const insertFollowerStmt = this.db.prepare(`
238
- INSERT OR REPLACE INTO followers (follower_id, actor_json)
242
+ INSERT INTO followers (follower_id, actor_json)
239
243
  VALUES (?, ?)
244
+ ON CONFLICT(follower_id)
245
+ DO UPDATE SET actor_json = excluded.actor_json
240
246
  `);
241
247
  const insertRequestStmt = this.db.prepare(`
242
- INSERT OR REPLACE INTO follow_requests (follow_request_id, follower_id)
248
+ INSERT INTO follow_requests (follow_request_id, follower_id)
243
249
  VALUES (?, ?)
250
+ ON CONFLICT(follow_request_id)
251
+ DO UPDATE SET follower_id = excluded.follower_id
244
252
  `);
245
- this.db.exec("BEGIN TRANSACTION");
253
+ const previousFollowerStmt = this.db.prepare(`
254
+ SELECT follower_id FROM follow_requests WHERE follow_request_id = ?
255
+ `);
256
+ this.db.exec("BEGIN IMMEDIATE TRANSACTION");
246
257
  try {
258
+ const previousRow = previousFollowerStmt.get(followRequestId.href);
247
259
  insertFollowerStmt.run(follower.id.href, followerJson);
248
260
  insertRequestStmt.run(followRequestId.href, follower.id.href);
261
+ if (previousRow != null && previousRow.follower_id !== follower.id.href) this.cleanupFollower(previousRow.follower_id);
249
262
  this.db.exec("COMMIT");
250
263
  } catch (error) {
251
264
  this.db.exec("ROLLBACK");
@@ -254,28 +267,36 @@ var SqliteRepository = class {
254
267
  }
255
268
  async removeFollower(followRequestId, actorId) {
256
269
  const checkStmt = this.db.prepare(`
257
- SELECT fr.follower_id, f.actor_json
258
- FROM follow_requests fr
259
- JOIN followers f ON fr.follower_id = f.follower_id
270
+ SELECT fr.follower_id, f.actor_json
271
+ FROM follow_requests fr
272
+ JOIN followers f ON fr.follower_id = f.follower_id
260
273
  WHERE fr.follow_request_id = ? AND fr.follower_id = ?
261
274
  `);
262
- const row = checkStmt.get(followRequestId.href, actorId.href);
263
- if (!row) return void 0;
264
275
  const deleteRequestStmt = this.db.prepare(`
265
- DELETE FROM follow_requests WHERE follow_request_id = ?
266
- `);
267
- const deleteFollowerStmt = this.db.prepare(`
268
- DELETE FROM followers WHERE follower_id = ?
276
+ DELETE FROM follow_requests
277
+ WHERE follow_request_id = ? AND follower_id = ?
269
278
  `);
270
- this.db.exec("BEGIN TRANSACTION");
279
+ let row;
280
+ let removed = false;
281
+ this.db.exec("BEGIN IMMEDIATE TRANSACTION");
271
282
  try {
272
- deleteRequestStmt.run(followRequestId.href);
273
- deleteFollowerStmt.run(actorId.href);
283
+ row = checkStmt.get(followRequestId.href, actorId.href);
284
+ if (row == null) {
285
+ this.db.exec("COMMIT");
286
+ return void 0;
287
+ }
288
+ const deleteResult = deleteRequestStmt.run(followRequestId.href, actorId.href);
289
+ if (deleteResult.changes < 1) {
290
+ this.db.exec("COMMIT");
291
+ return void 0;
292
+ }
293
+ removed = this.cleanupFollower(actorId.href);
274
294
  this.db.exec("COMMIT");
275
295
  } catch (error) {
276
296
  this.db.exec("ROLLBACK");
277
297
  throw error;
278
298
  }
299
+ if (!removed || row == null) return void 0;
279
300
  try {
280
301
  const actorData = JSON.parse(row.actor_json);
281
302
  const actor = await Object$1.fromJsonLd(actorData);
@@ -285,6 +306,17 @@ var SqliteRepository = class {
285
306
  }
286
307
  return void 0;
287
308
  }
309
+ cleanupFollower(followerId) {
310
+ const deleteFollowerStmt = this.db.prepare(`
311
+ DELETE FROM followers
312
+ WHERE follower_id = ?
313
+ AND NOT EXISTS (
314
+ SELECT 1 FROM follow_requests WHERE follower_id = ?
315
+ )
316
+ `);
317
+ const result = deleteFollowerStmt.run(followerId, followerId);
318
+ return result.changes > 0;
319
+ }
288
320
  hasFollower(followerId) {
289
321
  const stmt = this.db.prepare(`
290
322
  SELECT 1 FROM followers WHERE follower_id = ?
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","names":["options: SqliteRepositoryOptions","keyPairs: CryptoKeyPair[]","id: Uuid","activity: Create | Announce","updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>","options: RepositoryGetMessagesOptions","params: (number | string)[]","followRequestId: URL","follower: Actor","actorId: URL","followerId: URL","options: RepositoryGetFollowersOptions","params: number[]","follow: Follow","followeeId: URL","messageId: Uuid","voterId: URL","option: string","result: Record<string, number>"],"sources":["../src/mod.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type {\n Repository,\n RepositoryGetFollowersOptions,\n RepositoryGetMessagesOptions,\n Uuid,\n} from \"@fedify/botkit/repository\";\nimport { exportJwk, importJwk } from \"@fedify/fedify/sig\";\nimport {\n Activity,\n type Actor,\n Announce,\n Create,\n Follow,\n isActor,\n Object,\n} from \"@fedify/vocab\";\nimport { getLogger } from \"@logtape/logtape\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nconst logger = getLogger([\"botkit\", \"sqlite\"]);\n\n/**\n * Options for creating a SQLite repository.\n * @since 0.3.0\n */\nexport interface SqliteRepositoryOptions {\n /**\n * The path to the SQLite database file.\n * If not provided, an in-memory database will be used.\n */\n readonly path?: string;\n\n /**\n * Whether to enable Write-Ahead Logging (WAL) mode.\n * @default true\n */\n readonly wal?: boolean;\n}\n\n/**\n * A repository for storing bot data using SQLite.\n * @since 0.3.0\n */\nexport class SqliteRepository implements Repository, Disposable {\n private readonly db: DatabaseSync;\n\n /**\n * Creates a new SQLite repository.\n * @param options The options for creating the repository.\n */\n constructor(options: SqliteRepositoryOptions = {}) {\n const { path = \":memory:\", wal = true } = options;\n\n this.db = new DatabaseSync(path);\n\n // Enable foreign key constraints\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n\n if (wal && path !== \":memory:\") {\n this.db.exec(\"PRAGMA journal_mode = WAL;\");\n }\n\n this.initializeTables();\n }\n\n [Symbol.dispose]() {\n this.close();\n }\n\n /**\n * Closes the database connection.\n */\n close(): void {\n this.db.close();\n }\n\n private initializeTables(): void {\n // Key pairs table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS key_pairs (\n id INTEGER PRIMARY KEY,\n private_key_jwk TEXT NOT NULL,\n public_key_jwk TEXT NOT NULL\n )\n `);\n\n // Messages table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n activity_json TEXT NOT NULL,\n published INTEGER\n )\n `);\n\n // Create index on published timestamp for efficient ordering\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_published ON messages(published)\n `);\n\n // Followers table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followers (\n follower_id TEXT PRIMARY KEY,\n actor_json TEXT NOT NULL\n )\n `);\n\n // Follow requests mapping table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS follow_requests (\n follow_request_id TEXT PRIMARY KEY,\n follower_id TEXT NOT NULL,\n FOREIGN KEY (follower_id) REFERENCES followers(follower_id)\n )\n `);\n\n // Sent follows table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS sent_follows (\n id TEXT PRIMARY KEY,\n follow_json TEXT NOT NULL\n )\n `);\n\n // Followees table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followees (\n followee_id TEXT PRIMARY KEY,\n follow_json TEXT NOT NULL\n )\n `);\n\n // Poll votes table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS poll_votes (\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (message_id, voter_id, option)\n )\n `);\n\n // Create index for efficient vote counting\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_poll_votes_message_option \n ON poll_votes(message_id, option)\n `);\n }\n\n async setKeyPairs(keyPairs: CryptoKeyPair[]): Promise<void> {\n const deleteStmt = this.db.prepare(\"DELETE FROM key_pairs\");\n const insertStmt = this.db.prepare(`\n INSERT INTO key_pairs (private_key_jwk, public_key_jwk) \n VALUES (?, ?)\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n deleteStmt.run();\n\n for (const keyPair of keyPairs) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n insertStmt.run(JSON.stringify(privateJwk), JSON.stringify(publicJwk));\n }\n\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async getKeyPairs(): Promise<CryptoKeyPair[] | undefined> {\n const stmt = this.db.prepare(`\n SELECT private_key_jwk, public_key_jwk FROM key_pairs\n `);\n const rows = stmt.all() as Array<{\n private_key_jwk: string;\n public_key_jwk: string;\n }>;\n\n if (rows.length === 0) return undefined;\n\n const keyPairs: CryptoKeyPair[] = [];\n for (const row of rows) {\n const privateJwk = JSON.parse(row.private_key_jwk);\n const publicJwk = JSON.parse(row.public_key_jwk);\n\n keyPairs.push({\n privateKey: await importJwk(privateJwk, \"private\"),\n publicKey: await importJwk(publicJwk, \"public\"),\n });\n }\n\n return keyPairs;\n }\n\n async addMessage(id: Uuid, activity: Create | Announce): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT INTO messages (id, activity_json, published) \n VALUES (?, ?, ?)\n `);\n\n const activityJson = JSON.stringify(\n await activity.toJsonLd({ format: \"compact\" }),\n );\n const published = activity.published?.epochMilliseconds ?? null;\n\n stmt.run(id, activityJson, published);\n }\n\n async updateMessage(\n id: Uuid,\n updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>,\n ): Promise<boolean> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = selectStmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return false;\n\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (!(activity instanceof Create || activity instanceof Announce)) {\n return false;\n }\n\n const newActivity = await updater(activity);\n if (newActivity == null) return false;\n\n const updateStmt = this.db.prepare(`\n UPDATE messages \n SET activity_json = ?, published = ? \n WHERE id = ?\n `);\n\n const newActivityJson = JSON.stringify(\n await newActivity.toJsonLd({ format: \"compact\" }),\n );\n const published = newActivity.published?.epochMilliseconds ?? null;\n\n updateStmt.run(newActivityJson, published, id);\n return true;\n }\n\n async removeMessage(id: Uuid): Promise<Create | Announce | undefined> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = selectStmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return undefined;\n\n const deleteStmt = this.db.prepare(`\n DELETE FROM messages WHERE id = ?\n `);\n deleteStmt.run(id);\n\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse removed message activity\", { id, error });\n }\n\n return undefined;\n }\n\n async *getMessages(\n options: RepositoryGetMessagesOptions = {},\n ): AsyncIterable<Create | Announce> {\n const { order = \"newest\", until, since, limit } = options;\n\n let sql = \"SELECT activity_json FROM messages WHERE 1=1\";\n const params: (number | string)[] = [];\n\n if (since != null) {\n sql += \" AND published >= ?\";\n params.push(since.epochMilliseconds);\n }\n\n if (until != null) {\n sql += \" AND published <= ?\";\n params.push(until.epochMilliseconds);\n }\n\n sql += order === \"oldest\"\n ? \" ORDER BY published ASC\"\n : \" ORDER BY published DESC\";\n\n if (limit != null) {\n sql += \" LIMIT ?\";\n params.push(limit);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as Array<{ activity_json: string }>;\n\n for (const row of rows) {\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n yield activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity\", { error });\n continue;\n }\n }\n }\n\n async getMessage(id: Uuid): Promise<Create | Announce | undefined> {\n const stmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = stmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return undefined;\n\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity\", { id, error });\n }\n\n return undefined;\n }\n\n countMessages(): Promise<number> {\n const stmt = this.db.prepare(\"SELECT COUNT(*) as count FROM messages\");\n const row = stmt.get() as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addFollower(followRequestId: URL, follower: Actor): Promise<void> {\n if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n\n const followerJson = JSON.stringify(\n await follower.toJsonLd({ format: \"compact\" }),\n );\n\n const insertFollowerStmt = this.db.prepare(`\n INSERT OR REPLACE INTO followers (follower_id, actor_json) \n VALUES (?, ?)\n `);\n\n const insertRequestStmt = this.db.prepare(`\n INSERT OR REPLACE INTO follow_requests (follow_request_id, follower_id) \n VALUES (?, ?)\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n insertFollowerStmt.run(follower.id.href, followerJson);\n insertRequestStmt.run(followRequestId.href, follower.id.href);\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async removeFollower(\n followRequestId: URL,\n actorId: URL,\n ): Promise<Actor | undefined> {\n // Check if the follow request exists and matches the actor\n const checkStmt = this.db.prepare(`\n SELECT fr.follower_id, f.actor_json \n FROM follow_requests fr \n JOIN followers f ON fr.follower_id = f.follower_id \n WHERE fr.follow_request_id = ? AND fr.follower_id = ?\n `);\n\n const row = checkStmt.get(followRequestId.href, actorId.href) as {\n follower_id: string;\n actor_json: string;\n } | undefined;\n\n if (!row) return undefined;\n\n // Remove the follower and follow request\n const deleteRequestStmt = this.db.prepare(`\n DELETE FROM follow_requests WHERE follow_request_id = ?\n `);\n\n const deleteFollowerStmt = this.db.prepare(`\n DELETE FROM followers WHERE follower_id = ?\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n deleteRequestStmt.run(followRequestId.href);\n deleteFollowerStmt.run(actorId.href);\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n\n try {\n const actorData = JSON.parse(row.actor_json);\n const actor = await Object.fromJsonLd(actorData);\n\n if (isActor(actor)) {\n return actor;\n }\n } catch (error) {\n logger.warn(\"Failed to parse removed follower actor\", { error });\n }\n\n return undefined;\n }\n\n hasFollower(followerId: URL): Promise<boolean> {\n const stmt = this.db.prepare(`\n SELECT 1 FROM followers WHERE follower_id = ?\n `);\n const row = stmt.get(followerId.href);\n return Promise.resolve(row != null);\n }\n\n async *getFollowers(\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n const { offset = 0, limit } = options;\n\n let sql = \"SELECT actor_json FROM followers ORDER BY follower_id\";\n const params: number[] = [];\n\n if (limit != null) {\n sql += \" LIMIT ? OFFSET ?\";\n params.push(limit, offset);\n } else if (offset > 0) {\n sql += \" LIMIT -1 OFFSET ?\";\n params.push(offset);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as { actor_json: string }[];\n\n for (const row of rows) {\n try {\n const actorData = JSON.parse(row.actor_json);\n const actor = await Object.fromJsonLd(actorData);\n\n if (isActor(actor)) {\n yield actor;\n }\n } catch (error) {\n logger.warn(\"Failed to parse follower actor\", { error });\n continue;\n }\n }\n }\n\n countFollowers(): Promise<number> {\n const stmt = this.db.prepare(\"SELECT COUNT(*) as count FROM followers\");\n const row = stmt.get() as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addSentFollow(id: Uuid, follow: Follow): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO sent_follows (id, follow_json) \n VALUES (?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(id, followJson);\n }\n\n async removeSentFollow(id: Uuid): Promise<Follow | undefined> {\n const follow = await this.getSentFollow(id);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\"DELETE FROM sent_follows WHERE id = ?\");\n stmt.run(id);\n\n return follow;\n }\n\n async getSentFollow(id: Uuid): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM sent_follows WHERE id = ?\n `);\n const row = stmt.get(id) as { follow_json: string } | undefined;\n\n if (!row) return undefined;\n\n try {\n const followData = JSON.parse(row.follow_json);\n return await Follow.fromJsonLd(followData);\n } catch (error) {\n logger.warn(\"Failed to parse sent follow activity\", { id, error });\n return undefined;\n }\n }\n\n async addFollowee(followeeId: URL, follow: Follow): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO followees (followee_id, follow_json) \n VALUES (?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(followeeId.href, followJson);\n }\n\n async removeFollowee(followeeId: URL): Promise<Follow | undefined> {\n const follow = await this.getFollowee(followeeId);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\"DELETE FROM followees WHERE followee_id = ?\");\n stmt.run(followeeId.href);\n\n return follow;\n }\n\n async getFollowee(followeeId: URL): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM followees WHERE followee_id = ?\n `);\n const row = stmt.get(followeeId.href) as\n | { follow_json: string }\n | undefined;\n\n if (!row) return undefined;\n\n try {\n const followData = JSON.parse(row.follow_json);\n return await Follow.fromJsonLd(followData);\n } catch (error) {\n logger.warn(\"Failed to parse followee activity\", {\n followeeId: followeeId.href,\n error,\n });\n return undefined;\n }\n }\n\n vote(messageId: Uuid, voterId: URL, option: string): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR IGNORE INTO poll_votes (message_id, voter_id, option) \n VALUES (?, ?, ?)\n `);\n\n stmt.run(messageId, voterId.href, option);\n return Promise.resolve();\n }\n\n countVoters(messageId: Uuid): Promise<number> {\n const stmt = this.db.prepare(`\n SELECT COUNT(DISTINCT voter_id) as count \n FROM poll_votes \n WHERE message_id = ?\n `);\n const row = stmt.get(messageId) as { count: number };\n return Promise.resolve(row.count);\n }\n\n countVotes(messageId: Uuid): Promise<Readonly<Record<string, number>>> {\n const stmt = this.db.prepare(`\n SELECT option, COUNT(*) as count \n FROM poll_votes \n WHERE message_id = ? \n GROUP BY option\n `);\n const rows = stmt.all(messageId) as Array<{\n option: string;\n count: number;\n }>;\n\n const result: Record<string, number> = {};\n for (const row of rows) {\n result[row.option] = row.count;\n }\n\n return Promise.resolve(result);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mod.js","names":["options: SqliteRepositoryOptions","keyPairs: CryptoKeyPair[]","id: Uuid","activity: Create | Announce","updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>","options: RepositoryGetMessagesOptions","params: (number | string)[]","followRequestId: URL","follower: Actor","actorId: URL","row: { follower_id: string; actor_json: string } | undefined","followerId: string","followerId: URL","options: RepositoryGetFollowersOptions","params: number[]","follow: Follow","followeeId: URL","messageId: Uuid","voterId: URL","option: string","result: Record<string, number>"],"sources":["../src/mod.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport type {\n Repository,\n RepositoryGetFollowersOptions,\n RepositoryGetMessagesOptions,\n Uuid,\n} from \"@fedify/botkit/repository\";\nimport { exportJwk, importJwk } from \"@fedify/fedify/sig\";\nimport {\n Activity,\n type Actor,\n Announce,\n Create,\n Follow,\n isActor,\n Object,\n} from \"@fedify/vocab\";\nimport { getLogger } from \"@logtape/logtape\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nconst logger = getLogger([\"botkit\", \"sqlite\"]);\n\n/**\n * Options for creating a SQLite repository.\n * @since 0.3.0\n */\nexport interface SqliteRepositoryOptions {\n /**\n * The path to the SQLite database file.\n * If not provided, an in-memory database will be used.\n */\n readonly path?: string;\n\n /**\n * Whether to enable Write-Ahead Logging (WAL) mode.\n * @default true\n */\n readonly wal?: boolean;\n}\n\n/**\n * A repository for storing bot data using SQLite.\n * @since 0.3.0\n */\nexport class SqliteRepository implements Repository, Disposable {\n private readonly db: DatabaseSync;\n\n /**\n * Creates a new SQLite repository.\n * @param options The options for creating the repository.\n */\n constructor(options: SqliteRepositoryOptions = {}) {\n const { path = \":memory:\", wal = true } = options;\n\n this.db = new DatabaseSync(path);\n\n // Enable foreign key constraints\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n\n if (wal && path !== \":memory:\") {\n this.db.exec(\"PRAGMA journal_mode = WAL;\");\n }\n\n this.initializeTables();\n }\n\n [Symbol.dispose]() {\n this.close();\n }\n\n /**\n * Closes the database connection.\n */\n close(): void {\n this.db.close();\n }\n\n private initializeTables(): void {\n // Key pairs table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS key_pairs (\n id INTEGER PRIMARY KEY,\n private_key_jwk TEXT NOT NULL,\n public_key_jwk TEXT NOT NULL\n )\n `);\n\n // Messages table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n activity_json TEXT NOT NULL,\n published INTEGER\n )\n `);\n\n // Create index on published timestamp for efficient ordering\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_published ON messages(published)\n `);\n\n // Followers table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followers (\n follower_id TEXT PRIMARY KEY,\n actor_json TEXT NOT NULL\n )\n `);\n\n // Follow requests mapping table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS follow_requests (\n follow_request_id TEXT PRIMARY KEY,\n follower_id TEXT NOT NULL,\n FOREIGN KEY (follower_id) REFERENCES followers(follower_id)\n )\n `);\n\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_follow_requests_follower\n ON follow_requests(follower_id)\n `);\n\n // Sent follows table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS sent_follows (\n id TEXT PRIMARY KEY,\n follow_json TEXT NOT NULL\n )\n `);\n\n // Followees table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followees (\n followee_id TEXT PRIMARY KEY,\n follow_json TEXT NOT NULL\n )\n `);\n\n // Poll votes table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS poll_votes (\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (message_id, voter_id, option)\n )\n `);\n\n // Create index for efficient vote counting\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_poll_votes_message_option \n ON poll_votes(message_id, option)\n `);\n }\n\n async setKeyPairs(keyPairs: CryptoKeyPair[]): Promise<void> {\n const deleteStmt = this.db.prepare(\"DELETE FROM key_pairs\");\n const insertStmt = this.db.prepare(`\n INSERT INTO key_pairs (private_key_jwk, public_key_jwk) \n VALUES (?, ?)\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n deleteStmt.run();\n\n for (const keyPair of keyPairs) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n insertStmt.run(JSON.stringify(privateJwk), JSON.stringify(publicJwk));\n }\n\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async getKeyPairs(): Promise<CryptoKeyPair[] | undefined> {\n const stmt = this.db.prepare(`\n SELECT private_key_jwk, public_key_jwk FROM key_pairs\n `);\n const rows = stmt.all() as Array<{\n private_key_jwk: string;\n public_key_jwk: string;\n }>;\n\n if (rows.length === 0) return undefined;\n\n const keyPairs: CryptoKeyPair[] = [];\n for (const row of rows) {\n const privateJwk = JSON.parse(row.private_key_jwk);\n const publicJwk = JSON.parse(row.public_key_jwk);\n\n keyPairs.push({\n privateKey: await importJwk(privateJwk, \"private\"),\n publicKey: await importJwk(publicJwk, \"public\"),\n });\n }\n\n return keyPairs;\n }\n\n async addMessage(id: Uuid, activity: Create | Announce): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT INTO messages (id, activity_json, published) \n VALUES (?, ?, ?)\n `);\n\n const activityJson = JSON.stringify(\n await activity.toJsonLd({ format: \"compact\" }),\n );\n const published = activity.published?.epochMilliseconds ?? null;\n\n stmt.run(id, activityJson, published);\n }\n\n async updateMessage(\n id: Uuid,\n updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>,\n ): Promise<boolean> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = selectStmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return false;\n\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (!(activity instanceof Create || activity instanceof Announce)) {\n return false;\n }\n\n const newActivity = await updater(activity);\n if (newActivity == null) return false;\n\n const updateStmt = this.db.prepare(`\n UPDATE messages \n SET activity_json = ?, published = ? \n WHERE id = ?\n `);\n\n const newActivityJson = JSON.stringify(\n await newActivity.toJsonLd({ format: \"compact\" }),\n );\n const published = newActivity.published?.epochMilliseconds ?? null;\n\n updateStmt.run(newActivityJson, published, id);\n return true;\n }\n\n async removeMessage(id: Uuid): Promise<Create | Announce | undefined> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = selectStmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return undefined;\n\n const deleteStmt = this.db.prepare(`\n DELETE FROM messages WHERE id = ?\n `);\n deleteStmt.run(id);\n\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse removed message activity\", { id, error });\n }\n\n return undefined;\n }\n\n async *getMessages(\n options: RepositoryGetMessagesOptions = {},\n ): AsyncIterable<Create | Announce> {\n const { order = \"newest\", until, since, limit } = options;\n\n let sql = \"SELECT activity_json FROM messages WHERE 1=1\";\n const params: (number | string)[] = [];\n\n if (since != null) {\n sql += \" AND published >= ?\";\n params.push(since.epochMilliseconds);\n }\n\n if (until != null) {\n sql += \" AND published <= ?\";\n params.push(until.epochMilliseconds);\n }\n\n sql += order === \"oldest\"\n ? \" ORDER BY published ASC\"\n : \" ORDER BY published DESC\";\n\n if (limit != null) {\n sql += \" LIMIT ?\";\n params.push(limit);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as Array<{ activity_json: string }>;\n\n for (const row of rows) {\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n yield activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity\", { error });\n continue;\n }\n }\n }\n\n async getMessage(id: Uuid): Promise<Create | Announce | undefined> {\n const stmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE id = ?\n `);\n const row = stmt.get(id) as { activity_json: string } | undefined;\n\n if (!row) return undefined;\n\n try {\n const activityData = JSON.parse(row.activity_json);\n const activity = await Activity.fromJsonLd(activityData);\n\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity\", { id, error });\n }\n\n return undefined;\n }\n\n countMessages(): Promise<number> {\n const stmt = this.db.prepare(\"SELECT COUNT(*) as count FROM messages\");\n const row = stmt.get() as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addFollower(followRequestId: URL, follower: Actor): Promise<void> {\n if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n\n const followerJson = JSON.stringify(\n await follower.toJsonLd({ format: \"compact\" }),\n );\n\n const insertFollowerStmt = this.db.prepare(`\n INSERT INTO followers (follower_id, actor_json)\n VALUES (?, ?)\n ON CONFLICT(follower_id)\n DO UPDATE SET actor_json = excluded.actor_json\n `);\n\n const insertRequestStmt = this.db.prepare(`\n INSERT INTO follow_requests (follow_request_id, follower_id)\n VALUES (?, ?)\n ON CONFLICT(follow_request_id)\n DO UPDATE SET follower_id = excluded.follower_id\n `);\n\n const previousFollowerStmt = this.db.prepare(`\n SELECT follower_id FROM follow_requests WHERE follow_request_id = ?\n `);\n\n this.db.exec(\"BEGIN IMMEDIATE TRANSACTION\");\n try {\n const previousRow = previousFollowerStmt.get(followRequestId.href) as\n | { follower_id: string }\n | undefined;\n insertFollowerStmt.run(follower.id.href, followerJson);\n insertRequestStmt.run(followRequestId.href, follower.id.href);\n if (\n previousRow != null && previousRow.follower_id !== follower.id.href\n ) {\n this.cleanupFollower(previousRow.follower_id);\n }\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async removeFollower(\n followRequestId: URL,\n actorId: URL,\n ): Promise<Actor | undefined> {\n const checkStmt = this.db.prepare(`\n SELECT fr.follower_id, f.actor_json\n FROM follow_requests fr\n JOIN followers f ON fr.follower_id = f.follower_id\n WHERE fr.follow_request_id = ? AND fr.follower_id = ?\n `);\n\n const deleteRequestStmt = this.db.prepare(`\n DELETE FROM follow_requests\n WHERE follow_request_id = ? AND follower_id = ?\n `);\n\n let row: { follower_id: string; actor_json: string } | undefined;\n let removed = false;\n this.db.exec(\"BEGIN IMMEDIATE TRANSACTION\");\n try {\n row = checkStmt.get(followRequestId.href, actorId.href) as\n | { follower_id: string; actor_json: string }\n | undefined;\n if (row == null) {\n this.db.exec(\"COMMIT\");\n return undefined;\n }\n const deleteResult = deleteRequestStmt.run(\n followRequestId.href,\n actorId.href,\n ) as { readonly changes: number };\n if (deleteResult.changes < 1) {\n this.db.exec(\"COMMIT\");\n return undefined;\n }\n removed = this.cleanupFollower(actorId.href);\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n\n if (!removed || row == null) return undefined;\n\n try {\n const actorData = JSON.parse(row.actor_json);\n const actor = await Object.fromJsonLd(actorData);\n\n if (isActor(actor)) {\n return actor;\n }\n } catch (error) {\n logger.warn(\"Failed to parse removed follower actor\", { error });\n }\n\n return undefined;\n }\n\n private cleanupFollower(followerId: string): boolean {\n const deleteFollowerStmt = this.db.prepare(`\n DELETE FROM followers\n WHERE follower_id = ?\n AND NOT EXISTS (\n SELECT 1 FROM follow_requests WHERE follower_id = ?\n )\n `);\n\n const result = deleteFollowerStmt.run(followerId, followerId) as {\n readonly changes: number;\n };\n return result.changes > 0;\n }\n\n hasFollower(followerId: URL): Promise<boolean> {\n const stmt = this.db.prepare(`\n SELECT 1 FROM followers WHERE follower_id = ?\n `);\n const row = stmt.get(followerId.href);\n return Promise.resolve(row != null);\n }\n\n async *getFollowers(\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n const { offset = 0, limit } = options;\n\n let sql = \"SELECT actor_json FROM followers ORDER BY follower_id\";\n const params: number[] = [];\n\n if (limit != null) {\n sql += \" LIMIT ? OFFSET ?\";\n params.push(limit, offset);\n } else if (offset > 0) {\n sql += \" LIMIT -1 OFFSET ?\";\n params.push(offset);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as { actor_json: string }[];\n\n for (const row of rows) {\n try {\n const actorData = JSON.parse(row.actor_json);\n const actor = await Object.fromJsonLd(actorData);\n\n if (isActor(actor)) {\n yield actor;\n }\n } catch (error) {\n logger.warn(\"Failed to parse follower actor\", { error });\n continue;\n }\n }\n }\n\n countFollowers(): Promise<number> {\n const stmt = this.db.prepare(\"SELECT COUNT(*) as count FROM followers\");\n const row = stmt.get() as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addSentFollow(id: Uuid, follow: Follow): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO sent_follows (id, follow_json) \n VALUES (?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(id, followJson);\n }\n\n async removeSentFollow(id: Uuid): Promise<Follow | undefined> {\n const follow = await this.getSentFollow(id);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\"DELETE FROM sent_follows WHERE id = ?\");\n stmt.run(id);\n\n return follow;\n }\n\n async getSentFollow(id: Uuid): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM sent_follows WHERE id = ?\n `);\n const row = stmt.get(id) as { follow_json: string } | undefined;\n\n if (!row) return undefined;\n\n try {\n const followData = JSON.parse(row.follow_json);\n return await Follow.fromJsonLd(followData);\n } catch (error) {\n logger.warn(\"Failed to parse sent follow activity\", { id, error });\n return undefined;\n }\n }\n\n async addFollowee(followeeId: URL, follow: Follow): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO followees (followee_id, follow_json) \n VALUES (?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(followeeId.href, followJson);\n }\n\n async removeFollowee(followeeId: URL): Promise<Follow | undefined> {\n const follow = await this.getFollowee(followeeId);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\"DELETE FROM followees WHERE followee_id = ?\");\n stmt.run(followeeId.href);\n\n return follow;\n }\n\n async getFollowee(followeeId: URL): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM followees WHERE followee_id = ?\n `);\n const row = stmt.get(followeeId.href) as\n | { follow_json: string }\n | undefined;\n\n if (!row) return undefined;\n\n try {\n const followData = JSON.parse(row.follow_json);\n return await Follow.fromJsonLd(followData);\n } catch (error) {\n logger.warn(\"Failed to parse followee activity\", {\n followeeId: followeeId.href,\n error,\n });\n return undefined;\n }\n }\n\n vote(messageId: Uuid, voterId: URL, option: string): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR IGNORE INTO poll_votes (message_id, voter_id, option) \n VALUES (?, ?, ?)\n `);\n\n stmt.run(messageId, voterId.href, option);\n return Promise.resolve();\n }\n\n countVoters(messageId: Uuid): Promise<number> {\n const stmt = this.db.prepare(`\n SELECT COUNT(DISTINCT voter_id) as count \n FROM poll_votes \n WHERE message_id = ?\n `);\n const row = stmt.get(messageId) as { count: number };\n return Promise.resolve(row.count);\n }\n\n countVotes(messageId: Uuid): Promise<Readonly<Record<string, number>>> {\n const stmt = this.db.prepare(`\n SELECT option, COUNT(*) as count \n FROM poll_votes \n WHERE message_id = ? \n GROUP BY option\n `);\n const rows = stmt.all(messageId) as Array<{\n option: string;\n count: number;\n }>;\n\n const result: Record<string, number> = {};\n for (const row of rows) {\n result[row.option] = row.count;\n }\n\n return Promise.resolve(result);\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/botkit-sqlite",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "SQLite-based repository for BotKit",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": {
@@ -43,7 +43,7 @@
43
43
  "README.md"
44
44
  ],
45
45
  "peerDependencies": {
46
- "@fedify/botkit": "0.4.3"
46
+ "@fedify/botkit": "0.4.4"
47
47
  },
48
48
  "dependencies": {
49
49
  "@fedify/fedify": "~2.1.15",