@fedify/botkit-sqlite 0.5.0-dev.290 → 0.5.0-dev.298

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
@@ -88,6 +88,7 @@ declare class SqliteRepository implements Repository, Disposable {
88
88
  removeQuoteAuthorization(identifier: string, id: Uuid): Promise<QuoteAuthorization | undefined>;
89
89
  addQuoteAuthorizationReference(identifier: string, authorization: URL, messageId: Uuid, attribution?: URL): Promise<void>;
90
90
  findQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<Uuid | undefined>;
91
+ findQuoteAuthorizationReferenceIdentifiers(authorization: URL): AsyncIterable<string>;
91
92
  findQuoteAuthorizationReferenceAttribution(identifier: string, authorization: URL): Promise<URL | undefined>;
92
93
  removeQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<void>;
93
94
  vote(identifier: string, messageId: Uuid, voterId: URL, option: string): Promise<void>;
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
@@ -349,6 +349,10 @@ var SqliteRepository = class {
349
349
  attribution TEXT,
350
350
  PRIMARY KEY (bot_id, authorization)
351
351
  )
352
+ `);
353
+ this.db.exec(`
354
+ CREATE INDEX IF NOT EXISTS idx_quote_authorization_refs_authorization
355
+ ON quote_authorization_refs(authorization)
352
356
  `);
353
357
  if (!this.hasColumn("quote_authorization_refs", "attribution")) this.db.exec(`
354
358
  ALTER TABLE quote_authorization_refs ADD COLUMN attribution TEXT
@@ -750,6 +754,14 @@ var SqliteRepository = class {
750
754
  const row = stmt.get(identifier, authorization.href);
751
755
  return Promise.resolve(row?.message_id);
752
756
  }
757
+ async *findQuoteAuthorizationReferenceIdentifiers(authorization) {
758
+ const stmt = this.db.prepare(`
759
+ SELECT bot_id FROM quote_authorization_refs
760
+ WHERE authorization = ? ORDER BY bot_id
761
+ `);
762
+ const rows = stmt.all(authorization.href);
763
+ for (const row of rows) yield row.bot_id;
764
+ }
753
765
  findQuoteAuthorizationReferenceAttribution(identifier, authorization) {
754
766
  const stmt = this.db.prepare(`
755
767
  SELECT attribution FROM quote_authorization_refs
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","names":["options: SqliteRepositoryOptions","table: string","column: string","identifier: string","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","follow: Follow","followeeId: URL","authorization: QuoteAuthorization","interactingObject: URL","authorization: URL","messageId: Uuid","attribution?: URL","voterId: URL","option: string","result: Record<string, number>","json: string | undefined"],"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 {\n ActorScopedRepository,\n type Repository,\n type RepositoryGetFollowersOptions,\n type RepositoryGetMessagesOptions,\n type 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 QuoteAuthorization,\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 tableExists(table: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM sqlite_master\n WHERE type = 'table' AND name = ?\n `);\n const row = stmt.get(table) as { count: number };\n return row.count > 0;\n }\n\n private hasBotIdColumn(table: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM pragma_table_info(?)\n WHERE name = 'bot_id'\n `);\n const row = stmt.get(table) as { count: number };\n return row.count > 0;\n }\n\n private hasColumn(table: string, column: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM pragma_table_info(?)\n WHERE name = ?\n `);\n const row = stmt.get(table, column) as { count: number };\n return row.count > 0;\n }\n\n /**\n * Rebuilds tables created by \\@fedify/botkit-sqlite 0.4 or earlier, which\n * had no `bot_id` column, into the bot-scoped schema. Existing rows get\n * the empty-string bot ID; use {@link SqliteRepository.migrate} to assign\n * them to a bot actor identifier.\n */\n private rebuildLegacyTables(): void {\n const tables = [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n ].filter((table) => this.tableExists(table) && !this.hasBotIdColumn(table));\n if (tables.length < 1) return;\n logger.info(\n \"Rebuilding legacy tables without a bot_id column: {tables}.\",\n { tables },\n );\n // The marker lets migrate() distinguish rows carried over from a legacy\n // database (bot_id = '') from data legitimately stored under an\n // empty-string identifier:\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS botkit_metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )\n `);\n // SQLite cannot add a column to a composite primary key, so the tables\n // are rebuilt (create new, copy, drop, rename) in a single transaction.\n // Foreign key enforcement is turned off during the rebuild since\n // follow_requests references followers.\n this.db.exec(\"PRAGMA foreign_keys = OFF;\");\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n if (tables.includes(\"key_pairs\")) {\n // The primary key does not change; adding the column suffices:\n this.db.exec(`\n ALTER TABLE key_pairs ADD COLUMN bot_id TEXT NOT NULL DEFAULT ''\n `);\n }\n if (tables.includes(\"messages\")) {\n this.db.exec(`\n CREATE TABLE messages_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json TEXT NOT NULL,\n published INTEGER,\n PRIMARY KEY (bot_id, id)\n )\n `);\n this.db.exec(`\n INSERT INTO messages_new (bot_id, id, activity_json, published)\n SELECT '', id, activity_json, published FROM messages\n `);\n this.db.exec(\"DROP TABLE messages\");\n this.db.exec(\"ALTER TABLE messages_new RENAME TO messages\");\n }\n if (tables.includes(\"followers\")) {\n this.db.exec(`\n CREATE TABLE followers_new (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )\n `);\n this.db.exec(`\n INSERT INTO followers_new (bot_id, follower_id, actor_json)\n SELECT '', follower_id, actor_json FROM followers\n `);\n this.db.exec(\"DROP TABLE followers\");\n this.db.exec(\"ALTER TABLE followers_new RENAME TO followers\");\n }\n if (tables.includes(\"follow_requests\")) {\n this.db.exec(`\n CREATE TABLE follow_requests_new (\n bot_id TEXT NOT NULL,\n follow_request_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n PRIMARY KEY (bot_id, follow_request_id),\n FOREIGN KEY (bot_id, follower_id)\n REFERENCES followers(bot_id, follower_id)\n )\n `);\n this.db.exec(`\n INSERT INTO follow_requests_new\n (bot_id, follow_request_id, follower_id)\n SELECT '', follow_request_id, follower_id FROM follow_requests\n `);\n this.db.exec(\"DROP TABLE follow_requests\");\n this.db.exec(\n \"ALTER TABLE follow_requests_new RENAME TO follow_requests\",\n );\n }\n if (tables.includes(\"sent_follows\")) {\n this.db.exec(`\n CREATE TABLE sent_follows_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id)\n )\n `);\n this.db.exec(`\n INSERT INTO sent_follows_new (bot_id, id, follow_json)\n SELECT '', id, follow_json FROM sent_follows\n `);\n this.db.exec(\"DROP TABLE sent_follows\");\n this.db.exec(\"ALTER TABLE sent_follows_new RENAME TO sent_follows\");\n }\n if (tables.includes(\"followees\")) {\n this.db.exec(`\n CREATE TABLE followees_new (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )\n `);\n this.db.exec(`\n INSERT INTO followees_new (bot_id, followee_id, follow_json)\n SELECT '', followee_id, follow_json FROM followees\n `);\n this.db.exec(\"DROP TABLE followees\");\n this.db.exec(\"ALTER TABLE followees_new RENAME TO followees\");\n }\n if (tables.includes(\"quote_authorizations\")) {\n this.db.exec(`\n CREATE TABLE quote_authorizations_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )\n `);\n this.db.exec(`\n INSERT INTO quote_authorizations_new\n (bot_id, id, interacting_object, authorization_json)\n SELECT '', id, interacting_object, authorization_json\n FROM quote_authorizations\n `);\n this.db.exec(\"DROP TABLE quote_authorizations\");\n this.db.exec(\n \"ALTER TABLE quote_authorizations_new RENAME TO quote_authorizations\",\n );\n }\n if (tables.includes(\"poll_votes\")) {\n this.db.exec(`\n CREATE TABLE poll_votes_new (\n bot_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (bot_id, message_id, voter_id, option)\n )\n `);\n this.db.exec(`\n INSERT INTO poll_votes_new (bot_id, message_id, voter_id, option)\n SELECT '', message_id, voter_id, option FROM poll_votes\n `);\n this.db.exec(\"DROP TABLE poll_votes\");\n this.db.exec(\"ALTER TABLE poll_votes_new RENAME TO poll_votes\");\n }\n this.db.exec(`\n INSERT OR REPLACE INTO botkit_metadata (key, value)\n VALUES ('legacy_data', '1')\n `);\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n throw error;\n }\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n logger.info(\"Finished rebuilding legacy tables.\");\n }\n\n /**\n * Migrates data stored by \\@fedify/botkit-sqlite 0.4 or earlier, which was\n * not scoped by bot actor identifiers, so that it belongs to the given\n * identifier. Rows carried over from a legacy database have the\n * empty-string bot ID; this method assigns them to the identifier in\n * a single transaction. It only acts when the database was actually\n * rebuilt from a legacy schema, so data legitimately stored under an\n * empty-string identifier is never touched, and calling it again is\n * a no-op.\n * @param identifier The identifier of the bot actor that adopts the legacy\n * data.\n * @since 0.5.0\n */\n migrate(identifier: string): Promise<void> {\n if (!this.tableExists(\"botkit_metadata\")) return Promise.resolve();\n const marker = this.db.prepare(\n \"SELECT value FROM botkit_metadata WHERE key = 'legacy_data'\",\n ).get() as { value: string } | undefined;\n if (marker == null) return Promise.resolve();\n this.db.exec(\"BEGIN TRANSACTION\");\n // Updating followers and follow_requests rows in tandem temporarily\n // breaks the foreign key between them; defer the check to the commit:\n this.db.exec(\"PRAGMA defer_foreign_keys = ON\");\n try {\n for (\n const table of [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n ]\n ) {\n this.db.prepare(`UPDATE ${table} SET bot_id = ? WHERE bot_id = ''`)\n .run(identifier);\n }\n this.db.exec(\"DELETE FROM botkit_metadata WHERE key = 'legacy_data'\");\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n return Promise.resolve();\n }\n\n private initializeTables(): void {\n this.rebuildLegacyTables();\n\n // Key pairs table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS key_pairs (\n id INTEGER PRIMARY KEY,\n bot_id TEXT NOT NULL,\n private_key_jwk TEXT NOT NULL,\n public_key_jwk TEXT NOT NULL\n )\n `);\n\n // Create index on bot_id for efficient per-bot lookup\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_key_pairs_bot_id ON key_pairs(bot_id)\n `);\n\n // Messages table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json TEXT NOT NULL,\n published INTEGER,\n PRIMARY KEY (bot_id, id)\n )\n `);\n\n // Create index on published timestamp for efficient ordering\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_bot_published\n ON messages(bot_id, published)\n `);\n\n // Followers table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followers (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )\n `);\n\n // Follow requests mapping table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS follow_requests (\n bot_id TEXT NOT NULL,\n follow_request_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n PRIMARY KEY (bot_id, follow_request_id),\n FOREIGN KEY (bot_id, follower_id)\n REFERENCES followers(bot_id, 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 bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id)\n )\n `);\n\n // Followees table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followees (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )\n `);\n\n // Create index for reverse lookup of bots following an actor\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_followees_followee_id\n ON followees(followee_id)\n `);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS quote_authorizations (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )\n `);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS quote_authorization_refs (\n bot_id TEXT NOT NULL,\n authorization TEXT NOT NULL,\n message_id TEXT NOT NULL,\n attribution TEXT,\n PRIMARY KEY (bot_id, authorization)\n )\n `);\n if (!this.hasColumn(\"quote_authorization_refs\", \"attribution\")) {\n this.db.exec(`\n ALTER TABLE quote_authorization_refs ADD COLUMN attribution TEXT\n `);\n }\n\n // Poll votes table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS poll_votes (\n bot_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (bot_id, 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_bot_message_option\n ON poll_votes(bot_id, message_id, option)\n `);\n }\n\n async setKeyPairs(\n identifier: string,\n keyPairs: CryptoKeyPair[],\n ): Promise<void> {\n const deleteStmt = this.db.prepare(\n \"DELETE FROM key_pairs WHERE bot_id = ?\",\n );\n const insertStmt = this.db.prepare(`\n INSERT INTO key_pairs (bot_id, private_key_jwk, public_key_jwk)\n VALUES (?, ?, ?)\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n deleteStmt.run(identifier);\n\n for (const keyPair of keyPairs) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n insertStmt.run(\n identifier,\n JSON.stringify(privateJwk),\n JSON.stringify(publicJwk),\n );\n }\n\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async getKeyPairs(identifier: string): Promise<CryptoKeyPair[] | undefined> {\n const stmt = this.db.prepare(`\n SELECT private_key_jwk, public_key_jwk FROM key_pairs\n WHERE bot_id = ? ORDER BY id\n `);\n const rows = stmt.all(identifier) 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(\n identifier: string,\n id: Uuid,\n activity: Create | Announce,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT INTO messages (bot_id, 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(identifier, id, activityJson, published);\n }\n\n async updateMessage(\n identifier: string,\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 bot_id = ? AND id = ?\n `);\n const row = selectStmt.get(identifier, id) as\n | { activity_json: string }\n | 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 bot_id = ? AND 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, identifier, id);\n return true;\n }\n\n async removeMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE bot_id = ? AND id = ?\n `);\n const row = selectStmt.get(identifier, id) as\n | { activity_json: string }\n | undefined;\n\n if (!row) return undefined;\n\n const deleteStmt = this.db.prepare(`\n DELETE FROM messages WHERE bot_id = ? AND id = ?\n `);\n deleteStmt.run(identifier, 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 identifier: string,\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 bot_id = ?\";\n const params: (number | string)[] = [identifier];\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(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n const stmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) as\n | { activity_json: string }\n | 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(identifier: string): Promise<number> {\n const stmt = this.db.prepare(\n \"SELECT COUNT(*) as count FROM messages WHERE bot_id = ?\",\n );\n const row = stmt.get(identifier) as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addFollower(\n identifier: string,\n followRequestId: URL,\n follower: Actor,\n ): 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 (bot_id, follower_id, actor_json)\n VALUES (?, ?, ?)\n ON CONFLICT(bot_id, follower_id)\n DO UPDATE SET actor_json = excluded.actor_json\n `);\n\n const insertRequestStmt = this.db.prepare(`\n INSERT INTO follow_requests\n (bot_id, follow_request_id, follower_id)\n VALUES (?, ?, ?)\n ON CONFLICT(bot_id, follow_request_id)\n DO UPDATE SET follower_id = excluded.follower_id\n `);\n\n const previousFollowerStmt = this.db.prepare(`\n SELECT follower_id\n FROM follow_requests\n WHERE bot_id = ? AND follow_request_id = ?\n `);\n\n this.db.exec(\"BEGIN IMMEDIATE TRANSACTION\");\n try {\n const previousRow = previousFollowerStmt.get(\n identifier,\n followRequestId.href,\n ) as\n | { follower_id: string }\n | undefined;\n insertFollowerStmt.run(identifier, follower.id.href, followerJson);\n insertRequestStmt.run(\n identifier,\n followRequestId.href,\n follower.id.href,\n );\n if (\n previousRow != null && previousRow.follower_id !== follower.id.href\n ) {\n this.cleanupFollower(identifier, 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 identifier: string,\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\n ON fr.bot_id = f.bot_id AND fr.follower_id = f.follower_id\n WHERE fr.bot_id = ? AND fr.follow_request_id = ? AND fr.follower_id = ?\n `);\n\n const deleteRequestStmt = this.db.prepare(`\n DELETE FROM follow_requests\n WHERE bot_id = ? AND 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(identifier, 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 identifier,\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(identifier, 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(identifier: string, followerId: string): boolean {\n const deleteFollowerStmt = this.db.prepare(`\n DELETE FROM followers\n WHERE bot_id = ? AND follower_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM follow_requests\n WHERE bot_id = ? AND follower_id = ?\n )\n `);\n\n const result = deleteFollowerStmt.run(\n identifier,\n followerId,\n identifier,\n followerId,\n ) as {\n readonly changes: number;\n };\n return result.changes > 0;\n }\n\n hasFollower(identifier: string, followerId: URL): Promise<boolean> {\n const stmt = this.db.prepare(`\n SELECT 1 FROM followers WHERE bot_id = ? AND follower_id = ?\n `);\n const row = stmt.get(identifier, followerId.href);\n return Promise.resolve(row != null);\n }\n\n async *getFollowers(\n identifier: string,\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n const { offset = 0, limit } = options;\n\n let sql =\n \"SELECT actor_json FROM followers WHERE bot_id = ? ORDER BY follower_id\";\n const params: (number | string)[] = [identifier];\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(identifier: string): Promise<number> {\n const stmt = this.db.prepare(\n \"SELECT COUNT(*) as count FROM followers WHERE bot_id = ?\",\n );\n const row = stmt.get(identifier) as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addSentFollow(\n identifier: string,\n id: Uuid,\n follow: Follow,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO sent_follows (bot_id, id, follow_json)\n VALUES (?, ?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(identifier, id, followJson);\n }\n\n async removeSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n const follow = await this.getSentFollow(identifier, id);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\n \"DELETE FROM sent_follows WHERE bot_id = ? AND id = ?\",\n );\n stmt.run(identifier, id);\n\n return follow;\n }\n\n async getSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM sent_follows WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) 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 sent follow activity\", { id, error });\n return undefined;\n }\n }\n\n async addFollowee(\n identifier: string,\n followeeId: URL,\n follow: Follow,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO followees (bot_id, followee_id, follow_json)\n VALUES (?, ?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(identifier, followeeId.href, followJson);\n }\n\n async removeFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n const follow = await this.getFollowee(identifier, followeeId);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\n \"DELETE FROM followees WHERE bot_id = ? AND followee_id = ?\",\n );\n stmt.run(identifier, followeeId.href);\n\n return follow;\n }\n\n async getFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM followees WHERE bot_id = ? AND followee_id = ?\n `);\n const row = stmt.get(identifier, 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 async *findFollowedBots(followeeId: URL): AsyncIterable<string> {\n const stmt = this.db.prepare(`\n SELECT bot_id FROM followees WHERE followee_id = ? ORDER BY bot_id\n `);\n const rows = stmt.all(followeeId.href) as { bot_id: string }[];\n for (const row of rows) yield row.bot_id;\n }\n\n async addQuoteAuthorization(\n identifier: string,\n id: Uuid,\n authorization: QuoteAuthorization,\n ): Promise<void> {\n const interactingObject = authorization.interactingObjectId;\n if (interactingObject == null) {\n throw new TypeError(\n \"The quote authorization interacting object is missing.\",\n );\n }\n const stmt = this.db.prepare(`\n INSERT INTO quote_authorizations\n (bot_id, id, interacting_object, authorization_json)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(bot_id, interacting_object) DO NOTHING\n `);\n stmt.run(\n identifier,\n id,\n interactingObject.href,\n JSON.stringify(await authorization.toJsonLd({ format: \"compact\" })),\n );\n }\n\n async getQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(`\n SELECT authorization_json FROM quote_authorizations\n WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n async findQuoteAuthorization(\n identifier: string,\n interactingObject: URL,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(`\n SELECT authorization_json FROM quote_authorizations\n WHERE bot_id = ? AND interacting_object = ?\n `);\n const row = stmt.get(identifier, interactingObject.href) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n async removeQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(\n \"DELETE FROM quote_authorizations WHERE bot_id = ? AND id = ? \" +\n \"RETURNING authorization_json\",\n );\n const row = stmt.get(identifier, id) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n addQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n messageId: Uuid,\n attribution?: URL,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO quote_authorization_refs\n (bot_id, authorization, message_id, attribution)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(\n identifier,\n authorization.href,\n messageId,\n attribution?.href ?? null,\n );\n return Promise.resolve();\n }\n\n findQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<Uuid | undefined> {\n const stmt = this.db.prepare(`\n SELECT message_id FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n const row = stmt.get(identifier, authorization.href) as\n | { message_id: Uuid }\n | undefined;\n return Promise.resolve(row?.message_id);\n }\n\n findQuoteAuthorizationReferenceAttribution(\n identifier: string,\n authorization: URL,\n ): Promise<URL | undefined> {\n const stmt = this.db.prepare(`\n SELECT attribution FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n const row = stmt.get(identifier, authorization.href) as\n | { attribution: string | null }\n | undefined;\n if (row?.attribution == null) return Promise.resolve(undefined);\n try {\n return Promise.resolve(new URL(row.attribution));\n } catch {\n return Promise.resolve(undefined);\n }\n }\n\n removeQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n DELETE FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n stmt.run(identifier, authorization.href);\n return Promise.resolve();\n }\n\n vote(\n identifier: string,\n messageId: Uuid,\n voterId: URL,\n option: string,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR IGNORE INTO poll_votes (bot_id, message_id, voter_id, option)\n VALUES (?, ?, ?, ?)\n `);\n\n stmt.run(identifier, messageId, voterId.href, option);\n return Promise.resolve();\n }\n\n countVoters(identifier: string, messageId: Uuid): Promise<number> {\n const stmt = this.db.prepare(`\n SELECT COUNT(DISTINCT voter_id) as count\n FROM poll_votes\n WHERE bot_id = ? AND message_id = ?\n `);\n const row = stmt.get(identifier, messageId) as { count: number };\n return Promise.resolve(row.count);\n }\n\n countVotes(\n identifier: string,\n messageId: Uuid,\n ): Promise<Readonly<Record<string, number>>> {\n const stmt = this.db.prepare(`\n SELECT option, COUNT(*) as count\n FROM poll_votes\n WHERE bot_id = ? AND message_id = ?\n GROUP BY option\n `);\n const rows = stmt.all(identifier, 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 forIdentifier(identifier: string): ActorScopedRepository {\n return new ActorScopedRepository(this, identifier);\n }\n}\n\nasync function parseQuoteAuthorizationJson(\n json: string | undefined,\n): Promise<QuoteAuthorization | undefined> {\n if (json == null) return undefined;\n try {\n return await QuoteAuthorization.fromJsonLd(JSON.parse(json));\n } catch (error) {\n logger.warn(\"Failed to parse quote authorization\", { error });\n return undefined;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mod.js","names":["options: SqliteRepositoryOptions","table: string","column: string","identifier: string","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","follow: Follow","followeeId: URL","authorization: QuoteAuthorization","interactingObject: URL","authorization: URL","messageId: Uuid","attribution?: URL","voterId: URL","option: string","result: Record<string, number>","json: string | undefined"],"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 {\n ActorScopedRepository,\n type Repository,\n type RepositoryGetFollowersOptions,\n type RepositoryGetMessagesOptions,\n type 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 QuoteAuthorization,\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 tableExists(table: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM sqlite_master\n WHERE type = 'table' AND name = ?\n `);\n const row = stmt.get(table) as { count: number };\n return row.count > 0;\n }\n\n private hasBotIdColumn(table: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM pragma_table_info(?)\n WHERE name = 'bot_id'\n `);\n const row = stmt.get(table) as { count: number };\n return row.count > 0;\n }\n\n private hasColumn(table: string, column: string): boolean {\n const stmt = this.db.prepare(`\n SELECT COUNT(*) AS count FROM pragma_table_info(?)\n WHERE name = ?\n `);\n const row = stmt.get(table, column) as { count: number };\n return row.count > 0;\n }\n\n /**\n * Rebuilds tables created by \\@fedify/botkit-sqlite 0.4 or earlier, which\n * had no `bot_id` column, into the bot-scoped schema. Existing rows get\n * the empty-string bot ID; use {@link SqliteRepository.migrate} to assign\n * them to a bot actor identifier.\n */\n private rebuildLegacyTables(): void {\n const tables = [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n ].filter((table) => this.tableExists(table) && !this.hasBotIdColumn(table));\n if (tables.length < 1) return;\n logger.info(\n \"Rebuilding legacy tables without a bot_id column: {tables}.\",\n { tables },\n );\n // The marker lets migrate() distinguish rows carried over from a legacy\n // database (bot_id = '') from data legitimately stored under an\n // empty-string identifier:\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS botkit_metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )\n `);\n // SQLite cannot add a column to a composite primary key, so the tables\n // are rebuilt (create new, copy, drop, rename) in a single transaction.\n // Foreign key enforcement is turned off during the rebuild since\n // follow_requests references followers.\n this.db.exec(\"PRAGMA foreign_keys = OFF;\");\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n if (tables.includes(\"key_pairs\")) {\n // The primary key does not change; adding the column suffices:\n this.db.exec(`\n ALTER TABLE key_pairs ADD COLUMN bot_id TEXT NOT NULL DEFAULT ''\n `);\n }\n if (tables.includes(\"messages\")) {\n this.db.exec(`\n CREATE TABLE messages_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json TEXT NOT NULL,\n published INTEGER,\n PRIMARY KEY (bot_id, id)\n )\n `);\n this.db.exec(`\n INSERT INTO messages_new (bot_id, id, activity_json, published)\n SELECT '', id, activity_json, published FROM messages\n `);\n this.db.exec(\"DROP TABLE messages\");\n this.db.exec(\"ALTER TABLE messages_new RENAME TO messages\");\n }\n if (tables.includes(\"followers\")) {\n this.db.exec(`\n CREATE TABLE followers_new (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )\n `);\n this.db.exec(`\n INSERT INTO followers_new (bot_id, follower_id, actor_json)\n SELECT '', follower_id, actor_json FROM followers\n `);\n this.db.exec(\"DROP TABLE followers\");\n this.db.exec(\"ALTER TABLE followers_new RENAME TO followers\");\n }\n if (tables.includes(\"follow_requests\")) {\n this.db.exec(`\n CREATE TABLE follow_requests_new (\n bot_id TEXT NOT NULL,\n follow_request_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n PRIMARY KEY (bot_id, follow_request_id),\n FOREIGN KEY (bot_id, follower_id)\n REFERENCES followers(bot_id, follower_id)\n )\n `);\n this.db.exec(`\n INSERT INTO follow_requests_new\n (bot_id, follow_request_id, follower_id)\n SELECT '', follow_request_id, follower_id FROM follow_requests\n `);\n this.db.exec(\"DROP TABLE follow_requests\");\n this.db.exec(\n \"ALTER TABLE follow_requests_new RENAME TO follow_requests\",\n );\n }\n if (tables.includes(\"sent_follows\")) {\n this.db.exec(`\n CREATE TABLE sent_follows_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id)\n )\n `);\n this.db.exec(`\n INSERT INTO sent_follows_new (bot_id, id, follow_json)\n SELECT '', id, follow_json FROM sent_follows\n `);\n this.db.exec(\"DROP TABLE sent_follows\");\n this.db.exec(\"ALTER TABLE sent_follows_new RENAME TO sent_follows\");\n }\n if (tables.includes(\"followees\")) {\n this.db.exec(`\n CREATE TABLE followees_new (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )\n `);\n this.db.exec(`\n INSERT INTO followees_new (bot_id, followee_id, follow_json)\n SELECT '', followee_id, follow_json FROM followees\n `);\n this.db.exec(\"DROP TABLE followees\");\n this.db.exec(\"ALTER TABLE followees_new RENAME TO followees\");\n }\n if (tables.includes(\"quote_authorizations\")) {\n this.db.exec(`\n CREATE TABLE quote_authorizations_new (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )\n `);\n this.db.exec(`\n INSERT INTO quote_authorizations_new\n (bot_id, id, interacting_object, authorization_json)\n SELECT '', id, interacting_object, authorization_json\n FROM quote_authorizations\n `);\n this.db.exec(\"DROP TABLE quote_authorizations\");\n this.db.exec(\n \"ALTER TABLE quote_authorizations_new RENAME TO quote_authorizations\",\n );\n }\n if (tables.includes(\"poll_votes\")) {\n this.db.exec(`\n CREATE TABLE poll_votes_new (\n bot_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (bot_id, message_id, voter_id, option)\n )\n `);\n this.db.exec(`\n INSERT INTO poll_votes_new (bot_id, message_id, voter_id, option)\n SELECT '', message_id, voter_id, option FROM poll_votes\n `);\n this.db.exec(\"DROP TABLE poll_votes\");\n this.db.exec(\"ALTER TABLE poll_votes_new RENAME TO poll_votes\");\n }\n this.db.exec(`\n INSERT OR REPLACE INTO botkit_metadata (key, value)\n VALUES ('legacy_data', '1')\n `);\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n throw error;\n }\n this.db.exec(\"PRAGMA foreign_keys = ON;\");\n logger.info(\"Finished rebuilding legacy tables.\");\n }\n\n /**\n * Migrates data stored by \\@fedify/botkit-sqlite 0.4 or earlier, which was\n * not scoped by bot actor identifiers, so that it belongs to the given\n * identifier. Rows carried over from a legacy database have the\n * empty-string bot ID; this method assigns them to the identifier in\n * a single transaction. It only acts when the database was actually\n * rebuilt from a legacy schema, so data legitimately stored under an\n * empty-string identifier is never touched, and calling it again is\n * a no-op.\n * @param identifier The identifier of the bot actor that adopts the legacy\n * data.\n * @since 0.5.0\n */\n migrate(identifier: string): Promise<void> {\n if (!this.tableExists(\"botkit_metadata\")) return Promise.resolve();\n const marker = this.db.prepare(\n \"SELECT value FROM botkit_metadata WHERE key = 'legacy_data'\",\n ).get() as { value: string } | undefined;\n if (marker == null) return Promise.resolve();\n this.db.exec(\"BEGIN TRANSACTION\");\n // Updating followers and follow_requests rows in tandem temporarily\n // breaks the foreign key between them; defer the check to the commit:\n this.db.exec(\"PRAGMA defer_foreign_keys = ON\");\n try {\n for (\n const table of [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n ]\n ) {\n this.db.prepare(`UPDATE ${table} SET bot_id = ? WHERE bot_id = ''`)\n .run(identifier);\n }\n this.db.exec(\"DELETE FROM botkit_metadata WHERE key = 'legacy_data'\");\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n return Promise.resolve();\n }\n\n private initializeTables(): void {\n this.rebuildLegacyTables();\n\n // Key pairs table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS key_pairs (\n id INTEGER PRIMARY KEY,\n bot_id TEXT NOT NULL,\n private_key_jwk TEXT NOT NULL,\n public_key_jwk TEXT NOT NULL\n )\n `);\n\n // Create index on bot_id for efficient per-bot lookup\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_key_pairs_bot_id ON key_pairs(bot_id)\n `);\n\n // Messages table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json TEXT NOT NULL,\n published INTEGER,\n PRIMARY KEY (bot_id, id)\n )\n `);\n\n // Create index on published timestamp for efficient ordering\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_bot_published\n ON messages(bot_id, published)\n `);\n\n // Followers table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followers (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )\n `);\n\n // Follow requests mapping table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS follow_requests (\n bot_id TEXT NOT NULL,\n follow_request_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n PRIMARY KEY (bot_id, follow_request_id),\n FOREIGN KEY (bot_id, follower_id)\n REFERENCES followers(bot_id, 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 bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id)\n )\n `);\n\n // Followees table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS followees (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )\n `);\n\n // Create index for reverse lookup of bots following an actor\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_followees_followee_id\n ON followees(followee_id)\n `);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS quote_authorizations (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json TEXT NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )\n `);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS quote_authorization_refs (\n bot_id TEXT NOT NULL,\n authorization TEXT NOT NULL,\n message_id TEXT NOT NULL,\n attribution TEXT,\n PRIMARY KEY (bot_id, authorization)\n )\n `);\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_quote_authorization_refs_authorization\n ON quote_authorization_refs(authorization)\n `);\n if (!this.hasColumn(\"quote_authorization_refs\", \"attribution\")) {\n this.db.exec(`\n ALTER TABLE quote_authorization_refs ADD COLUMN attribution TEXT\n `);\n }\n\n // Poll votes table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS poll_votes (\n bot_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n voter_id TEXT NOT NULL,\n option TEXT NOT NULL,\n PRIMARY KEY (bot_id, 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_bot_message_option\n ON poll_votes(bot_id, message_id, option)\n `);\n }\n\n async setKeyPairs(\n identifier: string,\n keyPairs: CryptoKeyPair[],\n ): Promise<void> {\n const deleteStmt = this.db.prepare(\n \"DELETE FROM key_pairs WHERE bot_id = ?\",\n );\n const insertStmt = this.db.prepare(`\n INSERT INTO key_pairs (bot_id, private_key_jwk, public_key_jwk)\n VALUES (?, ?, ?)\n `);\n\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n deleteStmt.run(identifier);\n\n for (const keyPair of keyPairs) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n insertStmt.run(\n identifier,\n JSON.stringify(privateJwk),\n JSON.stringify(publicJwk),\n );\n }\n\n this.db.exec(\"COMMIT\");\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n\n async getKeyPairs(identifier: string): Promise<CryptoKeyPair[] | undefined> {\n const stmt = this.db.prepare(`\n SELECT private_key_jwk, public_key_jwk FROM key_pairs\n WHERE bot_id = ? ORDER BY id\n `);\n const rows = stmt.all(identifier) 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(\n identifier: string,\n id: Uuid,\n activity: Create | Announce,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT INTO messages (bot_id, 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(identifier, id, activityJson, published);\n }\n\n async updateMessage(\n identifier: string,\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 bot_id = ? AND id = ?\n `);\n const row = selectStmt.get(identifier, id) as\n | { activity_json: string }\n | 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 bot_id = ? AND 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, identifier, id);\n return true;\n }\n\n async removeMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n const selectStmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE bot_id = ? AND id = ?\n `);\n const row = selectStmt.get(identifier, id) as\n | { activity_json: string }\n | undefined;\n\n if (!row) return undefined;\n\n const deleteStmt = this.db.prepare(`\n DELETE FROM messages WHERE bot_id = ? AND id = ?\n `);\n deleteStmt.run(identifier, 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 identifier: string,\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 bot_id = ?\";\n const params: (number | string)[] = [identifier];\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(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n const stmt = this.db.prepare(`\n SELECT activity_json FROM messages WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) as\n | { activity_json: string }\n | 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(identifier: string): Promise<number> {\n const stmt = this.db.prepare(\n \"SELECT COUNT(*) as count FROM messages WHERE bot_id = ?\",\n );\n const row = stmt.get(identifier) as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addFollower(\n identifier: string,\n followRequestId: URL,\n follower: Actor,\n ): 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 (bot_id, follower_id, actor_json)\n VALUES (?, ?, ?)\n ON CONFLICT(bot_id, follower_id)\n DO UPDATE SET actor_json = excluded.actor_json\n `);\n\n const insertRequestStmt = this.db.prepare(`\n INSERT INTO follow_requests\n (bot_id, follow_request_id, follower_id)\n VALUES (?, ?, ?)\n ON CONFLICT(bot_id, follow_request_id)\n DO UPDATE SET follower_id = excluded.follower_id\n `);\n\n const previousFollowerStmt = this.db.prepare(`\n SELECT follower_id\n FROM follow_requests\n WHERE bot_id = ? AND follow_request_id = ?\n `);\n\n this.db.exec(\"BEGIN IMMEDIATE TRANSACTION\");\n try {\n const previousRow = previousFollowerStmt.get(\n identifier,\n followRequestId.href,\n ) as\n | { follower_id: string }\n | undefined;\n insertFollowerStmt.run(identifier, follower.id.href, followerJson);\n insertRequestStmt.run(\n identifier,\n followRequestId.href,\n follower.id.href,\n );\n if (\n previousRow != null && previousRow.follower_id !== follower.id.href\n ) {\n this.cleanupFollower(identifier, 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 identifier: string,\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\n ON fr.bot_id = f.bot_id AND fr.follower_id = f.follower_id\n WHERE fr.bot_id = ? AND fr.follow_request_id = ? AND fr.follower_id = ?\n `);\n\n const deleteRequestStmt = this.db.prepare(`\n DELETE FROM follow_requests\n WHERE bot_id = ? AND 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(identifier, 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 identifier,\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(identifier, 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(identifier: string, followerId: string): boolean {\n const deleteFollowerStmt = this.db.prepare(`\n DELETE FROM followers\n WHERE bot_id = ? AND follower_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM follow_requests\n WHERE bot_id = ? AND follower_id = ?\n )\n `);\n\n const result = deleteFollowerStmt.run(\n identifier,\n followerId,\n identifier,\n followerId,\n ) as {\n readonly changes: number;\n };\n return result.changes > 0;\n }\n\n hasFollower(identifier: string, followerId: URL): Promise<boolean> {\n const stmt = this.db.prepare(`\n SELECT 1 FROM followers WHERE bot_id = ? AND follower_id = ?\n `);\n const row = stmt.get(identifier, followerId.href);\n return Promise.resolve(row != null);\n }\n\n async *getFollowers(\n identifier: string,\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n const { offset = 0, limit } = options;\n\n let sql =\n \"SELECT actor_json FROM followers WHERE bot_id = ? ORDER BY follower_id\";\n const params: (number | string)[] = [identifier];\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(identifier: string): Promise<number> {\n const stmt = this.db.prepare(\n \"SELECT COUNT(*) as count FROM followers WHERE bot_id = ?\",\n );\n const row = stmt.get(identifier) as { count: number };\n return Promise.resolve(row.count);\n }\n\n async addSentFollow(\n identifier: string,\n id: Uuid,\n follow: Follow,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO sent_follows (bot_id, id, follow_json)\n VALUES (?, ?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(identifier, id, followJson);\n }\n\n async removeSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n const follow = await this.getSentFollow(identifier, id);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\n \"DELETE FROM sent_follows WHERE bot_id = ? AND id = ?\",\n );\n stmt.run(identifier, id);\n\n return follow;\n }\n\n async getSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM sent_follows WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) 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 sent follow activity\", { id, error });\n return undefined;\n }\n }\n\n async addFollowee(\n identifier: string,\n followeeId: URL,\n follow: Follow,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO followees (bot_id, followee_id, follow_json)\n VALUES (?, ?, ?)\n `);\n\n const followJson = JSON.stringify(\n await follow.toJsonLd({ format: \"compact\" }),\n );\n\n stmt.run(identifier, followeeId.href, followJson);\n }\n\n async removeFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n const follow = await this.getFollowee(identifier, followeeId);\n if (follow == null) return undefined;\n\n const stmt = this.db.prepare(\n \"DELETE FROM followees WHERE bot_id = ? AND followee_id = ?\",\n );\n stmt.run(identifier, followeeId.href);\n\n return follow;\n }\n\n async getFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n const stmt = this.db.prepare(`\n SELECT follow_json FROM followees WHERE bot_id = ? AND followee_id = ?\n `);\n const row = stmt.get(identifier, 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 async *findFollowedBots(followeeId: URL): AsyncIterable<string> {\n const stmt = this.db.prepare(`\n SELECT bot_id FROM followees WHERE followee_id = ? ORDER BY bot_id\n `);\n const rows = stmt.all(followeeId.href) as { bot_id: string }[];\n for (const row of rows) yield row.bot_id;\n }\n\n async addQuoteAuthorization(\n identifier: string,\n id: Uuid,\n authorization: QuoteAuthorization,\n ): Promise<void> {\n const interactingObject = authorization.interactingObjectId;\n if (interactingObject == null) {\n throw new TypeError(\n \"The quote authorization interacting object is missing.\",\n );\n }\n const stmt = this.db.prepare(`\n INSERT INTO quote_authorizations\n (bot_id, id, interacting_object, authorization_json)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(bot_id, interacting_object) DO NOTHING\n `);\n stmt.run(\n identifier,\n id,\n interactingObject.href,\n JSON.stringify(await authorization.toJsonLd({ format: \"compact\" })),\n );\n }\n\n async getQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(`\n SELECT authorization_json FROM quote_authorizations\n WHERE bot_id = ? AND id = ?\n `);\n const row = stmt.get(identifier, id) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n async findQuoteAuthorization(\n identifier: string,\n interactingObject: URL,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(`\n SELECT authorization_json FROM quote_authorizations\n WHERE bot_id = ? AND interacting_object = ?\n `);\n const row = stmt.get(identifier, interactingObject.href) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n async removeQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n const stmt = this.db.prepare(\n \"DELETE FROM quote_authorizations WHERE bot_id = ? AND id = ? \" +\n \"RETURNING authorization_json\",\n );\n const row = stmt.get(identifier, id) as\n | { authorization_json: string }\n | undefined;\n return await parseQuoteAuthorizationJson(row?.authorization_json);\n }\n\n addQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n messageId: Uuid,\n attribution?: URL,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO quote_authorization_refs\n (bot_id, authorization, message_id, attribution)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(\n identifier,\n authorization.href,\n messageId,\n attribution?.href ?? null,\n );\n return Promise.resolve();\n }\n\n findQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<Uuid | undefined> {\n const stmt = this.db.prepare(`\n SELECT message_id FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n const row = stmt.get(identifier, authorization.href) as\n | { message_id: Uuid }\n | undefined;\n return Promise.resolve(row?.message_id);\n }\n\n async *findQuoteAuthorizationReferenceIdentifiers(\n authorization: URL,\n ): AsyncIterable<string> {\n const stmt = this.db.prepare(`\n SELECT bot_id FROM quote_authorization_refs\n WHERE authorization = ? ORDER BY bot_id\n `);\n const rows = stmt.all(authorization.href) as { bot_id: string }[];\n for (const row of rows) yield row.bot_id;\n }\n\n findQuoteAuthorizationReferenceAttribution(\n identifier: string,\n authorization: URL,\n ): Promise<URL | undefined> {\n const stmt = this.db.prepare(`\n SELECT attribution FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n const row = stmt.get(identifier, authorization.href) as\n | { attribution: string | null }\n | undefined;\n if (row?.attribution == null) return Promise.resolve(undefined);\n try {\n return Promise.resolve(new URL(row.attribution));\n } catch {\n return Promise.resolve(undefined);\n }\n }\n\n removeQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n DELETE FROM quote_authorization_refs\n WHERE bot_id = ? AND authorization = ?\n `);\n stmt.run(identifier, authorization.href);\n return Promise.resolve();\n }\n\n vote(\n identifier: string,\n messageId: Uuid,\n voterId: URL,\n option: string,\n ): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR IGNORE INTO poll_votes (bot_id, message_id, voter_id, option)\n VALUES (?, ?, ?, ?)\n `);\n\n stmt.run(identifier, messageId, voterId.href, option);\n return Promise.resolve();\n }\n\n countVoters(identifier: string, messageId: Uuid): Promise<number> {\n const stmt = this.db.prepare(`\n SELECT COUNT(DISTINCT voter_id) as count\n FROM poll_votes\n WHERE bot_id = ? AND message_id = ?\n `);\n const row = stmt.get(identifier, messageId) as { count: number };\n return Promise.resolve(row.count);\n }\n\n countVotes(\n identifier: string,\n messageId: Uuid,\n ): Promise<Readonly<Record<string, number>>> {\n const stmt = this.db.prepare(`\n SELECT option, COUNT(*) as count\n FROM poll_votes\n WHERE bot_id = ? AND message_id = ?\n GROUP BY option\n `);\n const rows = stmt.all(identifier, 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 forIdentifier(identifier: string): ActorScopedRepository {\n return new ActorScopedRepository(this, identifier);\n }\n}\n\nasync function parseQuoteAuthorizationJson(\n json: string | undefined,\n): Promise<QuoteAuthorization | undefined> {\n if (json == null) return undefined;\n try {\n return await QuoteAuthorization.fromJsonLd(JSON.parse(json));\n } catch (error) {\n logger.warn(\"Failed to parse quote authorization\", { error });\n return undefined;\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.5.0-dev.290",
3
+ "version": "0.5.0-dev.298",
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.5.0-dev.290+c9aae4c7"
46
+ "@fedify/botkit": "^0.5.0-dev.298+a8b6a5fd"
47
47
  },
48
48
  "dependencies": {
49
49
  "@fedify/fedify": "~2.3.1",