@fedify/botkit-postgres 0.5.0-dev.290 → 0.5.0-dev.297

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
@@ -113,6 +113,7 @@ declare class PostgresRepository implements Repository, AsyncDisposable {
113
113
  removeQuoteAuthorization(identifier: string, id: Uuid): Promise<QuoteAuthorization | undefined>;
114
114
  addQuoteAuthorizationReference(identifier: string, authorization: URL, messageId: Uuid, attribution?: URL): Promise<void>;
115
115
  findQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<Uuid | undefined>;
116
+ findQuoteAuthorizationReferenceIdentifiers(authorization: URL): AsyncIterable<string>;
116
117
  findQuoteAuthorizationReferenceAttribution(identifier: string, authorization: URL): Promise<URL | undefined>;
117
118
  removeQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<void>;
118
119
  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
@@ -101,6 +101,8 @@ async function initializePostgresRepositorySchemaInTransaction(sql, validatedSch
101
101
  attribution_uri TEXT,
102
102
  PRIMARY KEY (bot_id, authorization_uri)
103
103
  )`, [], prepare);
104
+ await execute(sql, `CREATE INDEX IF NOT EXISTS "idx_quote_authorization_refs_authorization"
105
+ ON "${validatedSchema}"."quote_authorization_refs" (authorization_uri)`, [], prepare);
104
106
  await execute(sql, `ALTER TABLE "${validatedSchema}"."quote_authorization_refs"
105
107
  ADD COLUMN IF NOT EXISTS attribution_uri TEXT`, [], prepare);
106
108
  await execute(sql, `CREATE TABLE IF NOT EXISTS "${validatedSchema}"."poll_votes" (
@@ -662,6 +664,14 @@ var PostgresRepository = class {
662
664
  WHERE bot_id = $1 AND authorization_uri = $2`, [identifier, authorization.href]);
663
665
  return rows[0]?.message_id;
664
666
  }
667
+ async *findQuoteAuthorizationReferenceIdentifiers(authorization) {
668
+ await this.ensureReady();
669
+ const rows = await this.query(this.sql, `SELECT bot_id
670
+ FROM ${this.table("quote_authorization_refs")}
671
+ WHERE authorization_uri = $1
672
+ ORDER BY bot_id`, [authorization.href]);
673
+ for (const row of rows) yield row.bot_id;
674
+ }
665
675
  async findQuoteAuthorizationReferenceAttribution(identifier, authorization) {
666
676
  await this.ensureReady();
667
677
  const rows = await this.query(this.sql, `SELECT attribution_uri
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","names":["sql: TransactionalQueryable","sql: Queryable","validatedSchema: string","prepare: boolean","schema: string","table: string","options: PostgresRepositoryOptions","identifier: string","keyPairs: CryptoKeyPair[]","id: Uuid","activity: Create | Announce","updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>","options: RepositoryGetMessagesOptions","parameters: QueryParameter[]","followId: URL","follower: Actor","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>","name: string","followerId: string","followerIds: readonly string[]","query: string","parameters: readonly QueryParameter[]","value: unknown","json: unknown","parsed: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 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 { Temporal, toTemporalInstant } from \"@js-temporal/polyfill\";\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 postgres from \"postgres\";\n\nif (!(\"Temporal\" in globalThis)) {\n Reflect.set(globalThis, \"Temporal\", Temporal);\n}\nif (Date.prototype.toTemporalInstant == null) {\n Reflect.set(Date.prototype, \"toTemporalInstant\", toTemporalInstant);\n}\n\nconst logger = getLogger([\"botkit\", \"postgres\"]);\nconst schemaNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst followRequestAdvisoryLockNamespace = 0x4254;\nconst followerAdvisoryLockNamespace = 0x4246;\nconst schemaUpgradeAdvisoryLockNamespace = 0x424b;\n\ntype Queryable = Pick<postgres.Sql, \"unsafe\">;\ntype TransactionalQueryable = Queryable & Pick<postgres.Sql, \"begin\">;\ntype QueryParameter = postgres.SerializableParameter;\n\n/**\n * Common options for creating a PostgreSQL repository.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsBase {\n /**\n * The PostgreSQL schema name to use.\n * @default `\"botkit\"`\n */\n readonly schema?: string;\n\n /**\n * Whether to use prepared statements for queries.\n * @default true\n */\n readonly prepare?: boolean;\n}\n\n/**\n * Options for creating a PostgreSQL repository from an injected client.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsWithClient\n extends PostgresRepositoryOptionsBase {\n /**\n * A pre-configured PostgreSQL client to use.\n */\n readonly sql: postgres.Sql;\n\n /**\n * Disallowed when `sql` is provided.\n */\n readonly url?: never;\n\n /**\n * Disallowed when `sql` is provided.\n */\n readonly maxConnections?: never;\n}\n\n/**\n * Options for creating a PostgreSQL repository from a connection string.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsWithUrl\n extends PostgresRepositoryOptionsBase {\n /**\n * A PostgreSQL connection string to connect with.\n */\n readonly url: string | URL;\n\n /**\n * Disallowed when `url` is provided.\n */\n readonly sql?: never;\n\n /**\n * The maximum number of connections for an owned pool.\n */\n readonly maxConnections?: number;\n}\n\n/**\n * Options for creating a PostgreSQL repository.\n * @since 0.4.0\n */\nexport type PostgresRepositoryOptions =\n | PostgresRepositoryOptionsWithClient\n | PostgresRepositoryOptionsWithUrl;\n\n/**\n * Initializes the PostgreSQL schema used by BotKit repositories.\n * @param sql The PostgreSQL client to initialize the schema with.\n * @param schema The PostgreSQL schema name to initialize.\n * @param prepare Whether to use prepared statements for schema queries.\n * @since 0.4.0\n */\nexport async function initializePostgresRepositorySchema(\n sql: TransactionalQueryable,\n schema = \"botkit\",\n prepare = true,\n): Promise<void> {\n const validatedSchema = validateSchemaName(schema);\n if (!hasTransaction(sql)) {\n throw new TypeError(\n \"The PostgreSQL client must support transactions.\",\n );\n }\n await sql.begin(async (tx) => {\n await initializePostgresRepositorySchemaInTransaction(\n tx,\n validatedSchema,\n prepare,\n );\n });\n}\n\nasync function initializePostgresRepositorySchemaInTransaction(\n sql: Queryable,\n validatedSchema: string,\n prepare: boolean,\n): Promise<void> {\n await execute(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock(\n $1,\n pg_catalog.hashtext($2)\n )`,\n [schemaUpgradeAdvisoryLockNamespace, validatedSchema],\n prepare,\n );\n await execute(\n sql,\n `CREATE SCHEMA IF NOT EXISTS \"${validatedSchema}\"`,\n [],\n prepare,\n );\n await upgradeLegacySchema(sql, validatedSchema, prepare);\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"botkit_metadata\" (\n \"key\" TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"key_pairs\" (\n bot_id TEXT NOT NULL,\n position INTEGER NOT NULL,\n private_key_jwk JSONB NOT NULL,\n public_key_jwk JSONB NOT NULL,\n PRIMARY KEY (bot_id, position)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"messages\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json JSONB NOT NULL,\n published BIGINT,\n PRIMARY KEY (bot_id, id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_messages_published\"\n ON \"${validatedSchema}\".\"messages\" (bot_id, published, id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"followers\" (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"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 \"${validatedSchema}\".\"followers\" (bot_id, follower_id)\n ON DELETE CASCADE\n DEFERRABLE INITIALLY IMMEDIATE\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_follow_requests_follower\"\n ON \"${validatedSchema}\".\"follow_requests\" (bot_id, follower_id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"sent_follows\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"followees\" (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_followees_followee_id\"\n ON \"${validatedSchema}\".\"followees\" (followee_id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"quote_authorizations\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"quote_authorization_refs\" (\n bot_id TEXT NOT NULL,\n authorization_uri TEXT NOT NULL,\n message_id TEXT NOT NULL,\n attribution_uri TEXT,\n PRIMARY KEY (bot_id, authorization_uri)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `ALTER TABLE \"${validatedSchema}\".\"quote_authorization_refs\"\n ADD COLUMN IF NOT EXISTS attribution_uri TEXT`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"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 prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_poll_votes_message_option\"\n ON \"${validatedSchema}\".\"poll_votes\" (bot_id, message_id, option)`,\n [],\n prepare,\n );\n}\n\nconst upgradableTables = [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n] as const;\n\n/**\n * Upgrades tables created by \\@fedify/botkit-postgres 0.4, which had no\n * `bot_id` column, into the bot-scoped schema. Existing rows get the\n * empty-string bot ID; use {@link PostgresRepository.migrate} to assign them\n * to a bot actor identifier.\n *\n * The whole upgrade is sent as a single multi-statement query without\n * parameters, which PostgreSQL executes over the simple query protocol in\n * one implicit transaction on one connection, so it is atomic even when\n * `sql` is a connection pool.\n */\nasync function upgradeLegacySchema(\n sql: Queryable,\n schema: string,\n prepare: boolean,\n): Promise<void> {\n const rows = await execute<{ readonly table_name: string }>(\n sql,\n `SELECT t.table_name\n FROM information_schema.tables t\n WHERE t.table_schema = $1\n AND t.table_name = ANY($2)\n AND NOT EXISTS (\n SELECT 1\n FROM information_schema.columns c\n WHERE c.table_schema = t.table_schema\n AND c.table_name = t.table_name\n AND c.column_name = 'bot_id'\n )`,\n [schema, [...upgradableTables]],\n prepare,\n );\n if (rows.length < 1) return;\n const tables = rows.map((row) => row.table_name);\n logger.info(\n \"Upgrading legacy tables without a bot_id column: {tables}.\",\n { tables },\n );\n // Multiple processes can start against the same legacy schema at once, so\n // the whole upgrade runs inside one PL/pgSQL block: an advisory lock\n // serializes it, and every table is re-checked under the lock, so the\n // process that lost the race finds nothing left to do. The detection\n // query above is merely a fast path for already-upgraded schemas.\n const legacyTable = (table: string) =>\n `EXISTS (SELECT 1\n FROM information_schema.tables t\n WHERE t.table_schema = '${schema}' AND t.table_name = '${table}')\n AND NOT EXISTS (SELECT 1\n FROM information_schema.columns c\n WHERE c.table_schema = '${schema}' AND c.table_name = '${table}'\n AND c.column_name = 'bot_id')`;\n const block = `\n DO $botkit_upgrade$\n DECLARE\n upgraded boolean := false;\n BEGIN\n PERFORM pg_catalog.pg_advisory_xact_lock(\n ${schemaUpgradeAdvisoryLockNamespace},\n pg_catalog.hashtext('${schema}')\n );\n\n IF ${legacyTable(\"follow_requests\")} THEN\n -- The old foreign key referenced followers (follower_id) only; it\n -- has to go away before the followers primary key changes:\n ALTER TABLE \"${schema}\".\"follow_requests\"\n DROP CONSTRAINT IF EXISTS \"follow_requests_follower_id_fkey\";\n END IF;\n\n IF ${legacyTable(\"key_pairs\")} THEN\n ALTER TABLE \"${schema}\".\"key_pairs\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"key_pairs\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"key_pairs\"\n DROP CONSTRAINT IF EXISTS \"key_pairs_pkey\";\n ALTER TABLE \"${schema}\".\"key_pairs\" ADD PRIMARY KEY (bot_id, position);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"messages\")} THEN\n ALTER TABLE \"${schema}\".\"messages\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"messages\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"messages\"\n DROP CONSTRAINT IF EXISTS \"messages_pkey\";\n ALTER TABLE \"${schema}\".\"messages\" ADD PRIMARY KEY (bot_id, id);\n DROP INDEX IF EXISTS \"${schema}\".\"idx_messages_published\";\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"followers\")} THEN\n ALTER TABLE \"${schema}\".\"followers\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"followers\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"followers\"\n DROP CONSTRAINT IF EXISTS \"followers_pkey\";\n ALTER TABLE \"${schema}\".\"followers\"\n ADD PRIMARY KEY (bot_id, follower_id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"follow_requests\")} THEN\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"follow_requests\"\n DROP CONSTRAINT IF EXISTS \"follow_requests_pkey\";\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD PRIMARY KEY (bot_id, follow_request_id);\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD FOREIGN KEY (bot_id, follower_id)\n REFERENCES \"${schema}\".\"followers\" (bot_id, follower_id)\n ON DELETE CASCADE\n DEFERRABLE INITIALLY IMMEDIATE;\n DROP INDEX IF EXISTS \"${schema}\".\"idx_follow_requests_follower\";\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"sent_follows\")} THEN\n ALTER TABLE \"${schema}\".\"sent_follows\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"sent_follows\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"sent_follows\"\n DROP CONSTRAINT IF EXISTS \"sent_follows_pkey\";\n ALTER TABLE \"${schema}\".\"sent_follows\" ADD PRIMARY KEY (bot_id, id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"followees\")} THEN\n ALTER TABLE \"${schema}\".\"followees\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"followees\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"followees\"\n DROP CONSTRAINT IF EXISTS \"followees_pkey\";\n ALTER TABLE \"${schema}\".\"followees\"\n ADD PRIMARY KEY (bot_id, followee_id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"quote_authorizations\")} THEN\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n DROP CONSTRAINT IF EXISTS \"quote_authorizations_pkey\";\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD PRIMARY KEY (bot_id, id);\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD UNIQUE (bot_id, interacting_object);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"poll_votes\")} THEN\n ALTER TABLE \"${schema}\".\"poll_votes\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"poll_votes\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"poll_votes\"\n DROP CONSTRAINT IF EXISTS \"poll_votes_pkey\";\n ALTER TABLE \"${schema}\".\"poll_votes\"\n ADD PRIMARY KEY (bot_id, message_id, voter_id, option);\n DROP INDEX IF EXISTS \"${schema}\".\"idx_poll_votes_message_option\";\n upgraded := true;\n END IF;\n\n IF upgraded THEN\n -- The marker lets migrate() distinguish rows carried over from\n -- a legacy schema (bot_id = '') from data legitimately stored under\n -- an empty-string identifier:\n CREATE TABLE IF NOT EXISTS \"${schema}\".\"botkit_metadata\" (\n \"key\" TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n INSERT INTO \"${schema}\".\"botkit_metadata\" (\"key\", value)\n VALUES ('legacy_data', '1')\n ON CONFLICT (\"key\") DO NOTHING;\n END IF;\n END\n $botkit_upgrade$\n `;\n // DO blocks cannot be prepared:\n await execute(sql, block, [], false);\n logger.info(\"Finished upgrading legacy tables.\");\n}\n\n/**\n * A repository for storing bot data using PostgreSQL.\n * @since 0.4.0\n */\nexport class PostgresRepository implements Repository, AsyncDisposable {\n readonly sql: postgres.Sql;\n readonly schema: string;\n readonly prepare: boolean;\n private readonly ownsSql: boolean;\n private readonly ready: Promise<void>;\n\n constructor(options: PostgresRepositoryOptions) {\n this.schema = validateSchemaName(options.schema ?? \"botkit\");\n this.prepare = options.prepare ?? true;\n if (\"sql\" in options) {\n if (options.url != null || options.maxConnections != null) {\n throw new TypeError(\n \"PostgresRepositoryOptions.sql cannot be combined with PostgresRepositoryOptions.url or PostgresRepositoryOptions.maxConnections.\",\n );\n }\n this.ownsSql = false;\n this.sql = options.sql;\n } else {\n if (options.url == null) {\n throw new TypeError(\n \"PostgresRepositoryOptions.url must be provided when PostgresRepositoryOptions.sql is absent.\",\n );\n }\n this.ownsSql = true;\n const url = typeof options.url === \"string\"\n ? options.url\n : options.url.href;\n this.sql = postgres(url, {\n max: options.maxConnections,\n onnotice: () => {},\n prepare: this.prepare,\n });\n }\n const ready = initializePostgresRepositorySchema(\n this.sql,\n this.schema,\n this.prepare,\n );\n // Avoid unhandled rejection warnings before a repository method awaits it.\n ready.catch(() => {});\n this.ready = ready;\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n\n /**\n * Closes the underlying PostgreSQL connection pool if owned by the\n * repository.\n */\n async close(): Promise<void> {\n try {\n await this.ready;\n } finally {\n if (this.ownsSql) {\n await this.sql.end({ timeout: 5 });\n }\n }\n }\n\n async setKeyPairs(\n identifier: string,\n keyPairs: CryptoKeyPair[],\n ): Promise<void> {\n await this.ensureReady();\n await this.sql.begin(async (sql) => {\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"key_pairs\")} WHERE bot_id = $1`,\n [identifier],\n );\n for (const [position, keyPair] of keyPairs.entries()) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"key_pairs\")}\n (bot_id, position, private_key_jwk, public_key_jwk)\n VALUES ($1, $2, $3::jsonb, $4::jsonb)`,\n [\n identifier,\n position,\n serializeJson(privateJwk),\n serializeJson(publicJwk),\n ],\n );\n }\n });\n }\n\n async getKeyPairs(identifier: string): Promise<CryptoKeyPair[] | undefined> {\n await this.ensureReady();\n const rows = await this.query<{\n readonly private_key_jwk: unknown;\n readonly public_key_jwk: unknown;\n }>(\n this.sql,\n `SELECT private_key_jwk, public_key_jwk\n FROM ${this.table(\"key_pairs\")}\n WHERE bot_id = $1\n ORDER BY position ASC`,\n [identifier],\n );\n if (rows.length < 1) return undefined;\n const keyPairs: CryptoKeyPair[] = [];\n for (const row of rows) {\n const privateJwk = normalizeJsonObject(row.private_key_jwk);\n const publicJwk = normalizeJsonObject(row.public_key_jwk);\n if (privateJwk == null || publicJwk == null) {\n throw new TypeError(\"A stored key pair is malformed.\");\n }\n keyPairs.push({\n privateKey: await importJwk(privateJwk, \"private\"),\n publicKey: await importJwk(publicJwk, \"public\"),\n });\n }\n return keyPairs;\n }\n\n async addMessage(\n identifier: string,\n id: Uuid,\n activity: Create | Announce,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"messages\")}\n (bot_id, id, activity_json, published)\n VALUES ($1, $2, $3::jsonb, $4)`,\n [\n identifier,\n id,\n serializeJson(await activity.toJsonLd({ format: \"compact\" })),\n activity.published?.epochMilliseconds ?? null,\n ],\n );\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 await this.ensureReady();\n return await this.sql.begin(async (sql) => {\n const rows = await this.query<{ readonly activity_json: unknown }>(\n sql,\n `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2\n FOR UPDATE`,\n [identifier, id],\n );\n const row = rows[0];\n if (row == null) return false;\n const activity = await parseActivity(row.activity_json);\n if (activity == null) return false;\n const updated = await updater(activity);\n if (updated == null) return false;\n await this.query(\n sql,\n `UPDATE ${this.table(\"messages\")}\n SET activity_json = $1::jsonb,\n published = $2\n WHERE bot_id = $3 AND id = $4`,\n [\n serializeJson(await updated.toJsonLd({ format: \"compact\" })),\n updated.published?.epochMilliseconds ?? null,\n identifier,\n id,\n ],\n );\n return true;\n });\n }\n\n async removeMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING activity_json`,\n [identifier, id],\n );\n return await parseActivity(rows[0]?.activity_json);\n }\n\n async *getMessages(\n identifier: string,\n options: RepositoryGetMessagesOptions = {},\n ): AsyncIterable<Create | Announce> {\n await this.ensureReady();\n const { order = \"newest\", since, until, limit } = options;\n const parameters: QueryParameter[] = [identifier];\n let query = `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1`;\n if (since != null) {\n parameters.push(since.epochMilliseconds);\n query += ` AND published >= $${parameters.length}`;\n }\n if (until != null) {\n parameters.push(until.epochMilliseconds);\n query += ` AND published <= $${parameters.length}`;\n }\n query += order === \"oldest\"\n ? \" ORDER BY published ASC NULLS LAST, id ASC\"\n : \" ORDER BY published DESC NULLS LAST, id DESC\";\n if (limit != null) {\n parameters.push(limit);\n query += ` LIMIT $${parameters.length}`;\n }\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n query,\n parameters,\n );\n for (const row of rows) {\n const activity = await parseActivity(row.activity_json);\n if (activity != null) yield activity;\n }\n }\n\n async getMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseActivity(rows[0]?.activity_json);\n }\n\n async countMessages(identifier: string): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(*)::integer AS count\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1`,\n [identifier],\n );\n return rows[0]?.count ?? 0;\n }\n\n async addFollower(\n identifier: string,\n followId: URL,\n follower: Actor,\n ): Promise<void> {\n await this.ensureReady();\n if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n const followerId = follower.id;\n const followerJson = await follower.toJsonLd({ format: \"compact\" });\n await this.sql.begin(async (sql) => {\n await this.lockFollowRequest(sql, identifier, followId);\n const rows = await this.query<{ readonly follower_id: string }>(\n sql,\n `SELECT follower_id\n FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1 AND follow_request_id = $2\n FOR UPDATE`,\n [identifier, followId.href],\n );\n const previousFollowerId = rows[0]?.follower_id;\n await this.lockFollowers(sql, identifier, [\n followerId.href,\n ...(previousFollowerId == null ? [] : [previousFollowerId]),\n ]);\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"followers\")}\n (bot_id, follower_id, actor_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, follower_id)\n DO UPDATE SET actor_json = EXCLUDED.actor_json`,\n [identifier, followerId.href, serializeJson(followerJson)],\n );\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"follow_requests\")}\n (bot_id, follow_request_id, follower_id)\n VALUES ($1, $2, $3)\n ON CONFLICT (bot_id, follow_request_id)\n DO UPDATE SET follower_id = EXCLUDED.follower_id`,\n [identifier, followId.href, followerId.href],\n );\n if (\n previousFollowerId != null && previousFollowerId !== followerId.href\n ) {\n await this.cleanupFollower(sql, identifier, previousFollowerId);\n }\n });\n }\n\n async removeFollower(\n identifier: string,\n followId: URL,\n followerId: URL,\n ): Promise<Actor | undefined> {\n await this.ensureReady();\n return await this.sql.begin(async (sql) => {\n await this.lockFollowRequest(sql, identifier, followId);\n const rows = await this.query<{ readonly actor_json: unknown }>(\n sql,\n `SELECT f.actor_json\n FROM ${this.table(\"follow_requests\")} AS fr\n JOIN ${this.table(\"followers\")} AS f\n ON f.bot_id = fr.bot_id AND f.follower_id = fr.follower_id\n WHERE fr.bot_id = $1\n AND fr.follow_request_id = $2\n AND fr.follower_id = $3\n FOR UPDATE`,\n [identifier, followId.href, followerId.href],\n );\n const row = rows[0];\n if (row == null) return undefined;\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1 AND follow_request_id = $2`,\n [identifier, followId.href],\n );\n const removed = await this.cleanupFollower(\n sql,\n identifier,\n followerId.href,\n );\n return removed ? await parseActor(row.actor_json) : undefined;\n });\n }\n\n async hasFollower(identifier: string, followerId: URL): Promise<boolean> {\n await this.ensureReady();\n const rows = await this.query<{ readonly exists: number }>(\n this.sql,\n `SELECT 1 AS exists\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1 AND follower_id = $2`,\n [identifier, followerId.href],\n );\n return rows.length > 0;\n }\n\n async *getFollowers(\n identifier: string,\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n await this.ensureReady();\n const { offset = 0, limit } = options;\n const parameters: QueryParameter[] = [identifier];\n let query = `SELECT actor_json\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1\n ORDER BY follower_id ASC`;\n if (limit != null) {\n parameters.push(limit, offset);\n query += ` LIMIT $${parameters.length - 1} OFFSET $${parameters.length}`;\n } else if (offset > 0) {\n parameters.push(offset);\n query += ` OFFSET $${parameters.length}`;\n }\n const rows = await this.query<{ readonly actor_json: unknown }>(\n this.sql,\n query,\n parameters,\n );\n for (const row of rows) {\n const actor = await parseActor(row.actor_json);\n if (actor != null) yield actor;\n }\n }\n\n async countFollowers(identifier: string): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(*)::integer AS count\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1`,\n [identifier],\n );\n return rows[0]?.count ?? 0;\n }\n\n async addSentFollow(\n identifier: string,\n id: Uuid,\n follow: Follow,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"sent_follows\")} (bot_id, id, follow_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, id)\n DO UPDATE SET follow_json = EXCLUDED.follow_json`,\n [\n identifier,\n id,\n serializeJson(await follow.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async removeSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"sent_follows\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING follow_json`,\n [identifier, id],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async getSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `SELECT follow_json\n FROM ${this.table(\"sent_follows\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async addFollowee(\n identifier: string,\n followeeId: URL,\n follow: Follow,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"followees\")}\n (bot_id, followee_id, follow_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, followee_id)\n DO UPDATE SET follow_json = EXCLUDED.follow_json`,\n [\n identifier,\n followeeId.href,\n serializeJson(await follow.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async removeFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"followees\")}\n WHERE bot_id = $1 AND followee_id = $2\n RETURNING follow_json`,\n [identifier, followeeId.href],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async getFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `SELECT follow_json\n FROM ${this.table(\"followees\")}\n WHERE bot_id = $1 AND followee_id = $2`,\n [identifier, followeeId.href],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async *findFollowedBots(followeeId: URL): AsyncIterable<string> {\n await this.ensureReady();\n const rows = await this.query<{ readonly bot_id: string }>(\n this.sql,\n `SELECT bot_id\n FROM ${this.table(\"followees\")}\n WHERE followee_id = $1\n ORDER BY bot_id ASC`,\n [followeeId.href],\n );\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 await this.ensureReady();\n const interactingObject = authorization.interactingObjectId;\n if (interactingObject == null) {\n throw new TypeError(\n \"The quote authorization interacting object is missing.\",\n );\n }\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"quote_authorizations\")}\n (bot_id, id, interacting_object, authorization_json)\n VALUES ($1, $2, $3, $4::jsonb)\n ON CONFLICT (bot_id, interacting_object) DO NOTHING`,\n [\n identifier,\n id,\n interactingObject.href,\n serializeJson(await authorization.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async getQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `SELECT authorization_json\n FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async findQuoteAuthorization(\n identifier: string,\n interactingObject: URL,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `SELECT authorization_json\n FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND interacting_object = $2`,\n [identifier, interactingObject.href],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async removeQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING authorization_json`,\n [identifier, id],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async addQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n messageId: Uuid,\n attribution?: URL,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"quote_authorization_refs\")}\n (bot_id, authorization_uri, message_id, attribution_uri)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (bot_id, authorization_uri) DO UPDATE\n SET message_id = EXCLUDED.message_id,\n attribution_uri = EXCLUDED.attribution_uri`,\n [identifier, authorization.href, messageId, attribution?.href ?? null],\n );\n }\n\n async findQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<Uuid | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly message_id: Uuid }>(\n this.sql,\n `SELECT message_id\n FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n return rows[0]?.message_id;\n }\n\n async findQuoteAuthorizationReferenceAttribution(\n identifier: string,\n authorization: URL,\n ): Promise<URL | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly attribution_uri: string | null }>(\n this.sql,\n `SELECT attribution_uri\n FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n const attribution = rows[0]?.attribution_uri;\n if (attribution == null) return undefined;\n try {\n return new URL(attribution);\n } catch {\n return undefined;\n }\n }\n\n async removeQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `DELETE FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n }\n\n async vote(\n identifier: string,\n messageId: Uuid,\n voterId: URL,\n option: string,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"poll_votes\")}\n (bot_id, message_id, voter_id, option)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (bot_id, message_id, voter_id, option)\n DO NOTHING`,\n [identifier, messageId, voterId.href, option],\n );\n }\n\n async countVoters(identifier: string, messageId: Uuid): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(DISTINCT voter_id)::integer AS count\n FROM ${this.table(\"poll_votes\")}\n WHERE bot_id = $1 AND message_id = $2`,\n [identifier, messageId],\n );\n return rows[0]?.count ?? 0;\n }\n\n async countVotes(\n identifier: string,\n messageId: Uuid,\n ): Promise<Readonly<Record<string, number>>> {\n await this.ensureReady();\n const rows = await this.query<{\n readonly option: string;\n readonly count: number;\n }>(\n this.sql,\n `SELECT option, COUNT(*)::integer AS count\n FROM ${this.table(\"poll_votes\")}\n WHERE bot_id = $1 AND message_id = $2\n GROUP BY option\n ORDER BY option ASC`,\n [identifier, messageId],\n );\n const result: Record<string, number> = {};\n for (const row of rows) {\n result[row.option] = row.count;\n }\n return result;\n }\n\n /**\n * Migrates data stored by \\@fedify/botkit-postgres 0.4, which was not\n * scoped by bot actor identifiers, so that it belongs to the given\n * identifier. Rows carried over from a legacy schema have the\n * empty-string bot ID; this method assigns them to the identifier in\n * a single transaction. It only acts when the schema was actually\n * upgraded from a legacy layout, 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 async migrate(identifier: string): Promise<void> {\n await this.ensureReady();\n await this.sql.begin(async (sql) => {\n const rows = await this.query<{ readonly value: string }>(\n sql,\n `SELECT value FROM ${this.table(\"botkit_metadata\")}\n WHERE \"key\" = 'legacy_data'\n FOR UPDATE`,\n );\n if (rows.length < 1) return;\n // The followers and follow_requests rows move in tandem, which\n // temporarily breaks the foreign key between them; defer the check to\n // the commit:\n await execute(sql, \"SET CONSTRAINTS ALL DEFERRED\", [], false);\n for (const table of upgradableTables) {\n await this.query(\n sql,\n `UPDATE \"${this.schema}\".\"${table}\"\n SET bot_id = $1\n WHERE bot_id = ''`,\n [identifier],\n );\n }\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"botkit_metadata\")}\n WHERE \"key\" = 'legacy_data'`,\n );\n });\n }\n\n forIdentifier(identifier: string): ActorScopedRepository {\n return new ActorScopedRepository(this, identifier);\n }\n\n private table(name: string): string {\n return `\"${this.schema}\".\"${name}\"`;\n }\n\n private async lockFollowRequest(\n sql: Queryable,\n identifier: string,\n followId: URL,\n ): Promise<void> {\n await this.query(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock($1, pg_catalog.hashtext($2))`,\n [\n followRequestAdvisoryLockNamespace,\n `${this.schema}:${identifier}:${followId.href}`,\n ],\n );\n }\n\n private async lockFollower(\n sql: Queryable,\n identifier: string,\n followerId: string,\n ): Promise<void> {\n await this.query(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock($1, pg_catalog.hashtext($2))`,\n [\n followerAdvisoryLockNamespace,\n `${this.schema}:${identifier}:${followerId}`,\n ],\n );\n }\n\n private async lockFollowers(\n sql: Queryable,\n identifier: string,\n followerIds: readonly string[],\n ): Promise<void> {\n const uniqueFollowerIds = [...new Set(followerIds)].sort();\n for (const followerId of uniqueFollowerIds) {\n await this.lockFollower(sql, identifier, followerId);\n }\n }\n\n private async cleanupFollower(\n sql: Queryable,\n identifier: string,\n followerId: string,\n ): Promise<boolean> {\n await this.lockFollower(sql, identifier, followerId);\n const rows = await this.query<{ readonly follower_id: string }>(\n sql,\n `DELETE FROM ${this.table(\"followers\")}\n WHERE bot_id = $1\n AND follower_id = $2\n AND NOT EXISTS (\n SELECT 1\n FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1\n AND follower_id = $2\n )\n RETURNING follower_id`,\n [identifier, followerId],\n );\n return rows.length > 0;\n }\n\n private async ensureReady(): Promise<void> {\n await this.ready;\n }\n\n private async query<TRow extends object>(\n sql: Queryable,\n query: string,\n parameters: readonly QueryParameter[] = [],\n ): Promise<readonly TRow[]> {\n return await execute<TRow>(sql, query, parameters, this.prepare);\n }\n}\n\nfunction validateSchemaName(schema: string): string {\n if (!schemaNamePattern.test(schema)) {\n throw new TypeError(\"The PostgreSQL schema name is invalid.\");\n }\n return schema;\n}\n\nfunction hasTransaction(sql: Queryable): sql is TransactionalQueryable {\n return sql != null &&\n typeof (sql as Partial<TransactionalQueryable>).begin === \"function\";\n}\n\nasync function execute<TRow extends object>(\n sql: Queryable,\n query: string,\n parameters: readonly QueryParameter[] = [],\n prepare = true,\n): Promise<readonly TRow[]> {\n return await sql.unsafe<TRow[]>(\n query,\n [...parameters],\n { prepare },\n );\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value != null;\n}\n\nasync function parseActivity(\n json: unknown,\n): Promise<Create | Announce | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n const activity = await Activity.fromJsonLd(normalized);\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity.\", { error });\n }\n return undefined;\n}\n\nasync function parseActor(json: unknown): Promise<Actor | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n const actor = await Object.fromJsonLd(normalized);\n if (isActor(actor)) return actor;\n } catch (error) {\n logger.warn(\"Failed to parse follower actor.\", { error });\n }\n return undefined;\n}\n\nasync function parseFollow(json: unknown): Promise<Follow | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n return await Follow.fromJsonLd(normalized);\n } catch (error) {\n logger.warn(\"Failed to parse follow activity.\", { error });\n }\n return undefined;\n}\n\nasync function parseQuoteAuthorization(\n json: unknown,\n): Promise<QuoteAuthorization | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n return await QuoteAuthorization.fromJsonLd(normalized);\n } catch (error) {\n logger.warn(\"Failed to parse quote authorization.\", { error });\n }\n return undefined;\n}\n\nfunction normalizeJsonObject(\n value: unknown,\n): Record<string, unknown> | undefined {\n if (isJsonObject(value)) return value;\n if (typeof value !== \"string\") return undefined;\n try {\n const parsed: unknown = JSON.parse(value);\n if (isJsonObject(parsed)) return parsed;\n } catch {\n return undefined;\n }\n return undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mod.js","names":["sql: TransactionalQueryable","sql: Queryable","validatedSchema: string","prepare: boolean","schema: string","table: string","options: PostgresRepositoryOptions","identifier: string","keyPairs: CryptoKeyPair[]","id: Uuid","activity: Create | Announce","updater: (\n existing: Create | Announce,\n ) => Create | Announce | undefined | Promise<Create | Announce | undefined>","options: RepositoryGetMessagesOptions","parameters: QueryParameter[]","followId: URL","follower: Actor","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>","name: string","followerId: string","followerIds: readonly string[]","query: string","parameters: readonly QueryParameter[]","value: unknown","json: unknown","parsed: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 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 { Temporal, toTemporalInstant } from \"@js-temporal/polyfill\";\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 postgres from \"postgres\";\n\nif (!(\"Temporal\" in globalThis)) {\n Reflect.set(globalThis, \"Temporal\", Temporal);\n}\nif (Date.prototype.toTemporalInstant == null) {\n Reflect.set(Date.prototype, \"toTemporalInstant\", toTemporalInstant);\n}\n\nconst logger = getLogger([\"botkit\", \"postgres\"]);\nconst schemaNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst followRequestAdvisoryLockNamespace = 0x4254;\nconst followerAdvisoryLockNamespace = 0x4246;\nconst schemaUpgradeAdvisoryLockNamespace = 0x424b;\n\ntype Queryable = Pick<postgres.Sql, \"unsafe\">;\ntype TransactionalQueryable = Queryable & Pick<postgres.Sql, \"begin\">;\ntype QueryParameter = postgres.SerializableParameter;\n\n/**\n * Common options for creating a PostgreSQL repository.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsBase {\n /**\n * The PostgreSQL schema name to use.\n * @default `\"botkit\"`\n */\n readonly schema?: string;\n\n /**\n * Whether to use prepared statements for queries.\n * @default true\n */\n readonly prepare?: boolean;\n}\n\n/**\n * Options for creating a PostgreSQL repository from an injected client.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsWithClient\n extends PostgresRepositoryOptionsBase {\n /**\n * A pre-configured PostgreSQL client to use.\n */\n readonly sql: postgres.Sql;\n\n /**\n * Disallowed when `sql` is provided.\n */\n readonly url?: never;\n\n /**\n * Disallowed when `sql` is provided.\n */\n readonly maxConnections?: never;\n}\n\n/**\n * Options for creating a PostgreSQL repository from a connection string.\n * @since 0.4.0\n */\ninterface PostgresRepositoryOptionsWithUrl\n extends PostgresRepositoryOptionsBase {\n /**\n * A PostgreSQL connection string to connect with.\n */\n readonly url: string | URL;\n\n /**\n * Disallowed when `url` is provided.\n */\n readonly sql?: never;\n\n /**\n * The maximum number of connections for an owned pool.\n */\n readonly maxConnections?: number;\n}\n\n/**\n * Options for creating a PostgreSQL repository.\n * @since 0.4.0\n */\nexport type PostgresRepositoryOptions =\n | PostgresRepositoryOptionsWithClient\n | PostgresRepositoryOptionsWithUrl;\n\n/**\n * Initializes the PostgreSQL schema used by BotKit repositories.\n * @param sql The PostgreSQL client to initialize the schema with.\n * @param schema The PostgreSQL schema name to initialize.\n * @param prepare Whether to use prepared statements for schema queries.\n * @since 0.4.0\n */\nexport async function initializePostgresRepositorySchema(\n sql: TransactionalQueryable,\n schema = \"botkit\",\n prepare = true,\n): Promise<void> {\n const validatedSchema = validateSchemaName(schema);\n if (!hasTransaction(sql)) {\n throw new TypeError(\n \"The PostgreSQL client must support transactions.\",\n );\n }\n await sql.begin(async (tx) => {\n await initializePostgresRepositorySchemaInTransaction(\n tx,\n validatedSchema,\n prepare,\n );\n });\n}\n\nasync function initializePostgresRepositorySchemaInTransaction(\n sql: Queryable,\n validatedSchema: string,\n prepare: boolean,\n): Promise<void> {\n await execute(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock(\n $1,\n pg_catalog.hashtext($2)\n )`,\n [schemaUpgradeAdvisoryLockNamespace, validatedSchema],\n prepare,\n );\n await execute(\n sql,\n `CREATE SCHEMA IF NOT EXISTS \"${validatedSchema}\"`,\n [],\n prepare,\n );\n await upgradeLegacySchema(sql, validatedSchema, prepare);\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"botkit_metadata\" (\n \"key\" TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"key_pairs\" (\n bot_id TEXT NOT NULL,\n position INTEGER NOT NULL,\n private_key_jwk JSONB NOT NULL,\n public_key_jwk JSONB NOT NULL,\n PRIMARY KEY (bot_id, position)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"messages\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n activity_json JSONB NOT NULL,\n published BIGINT,\n PRIMARY KEY (bot_id, id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_messages_published\"\n ON \"${validatedSchema}\".\"messages\" (bot_id, published, id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"followers\" (\n bot_id TEXT NOT NULL,\n follower_id TEXT NOT NULL,\n actor_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, follower_id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"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 \"${validatedSchema}\".\"followers\" (bot_id, follower_id)\n ON DELETE CASCADE\n DEFERRABLE INITIALLY IMMEDIATE\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_follow_requests_follower\"\n ON \"${validatedSchema}\".\"follow_requests\" (bot_id, follower_id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"sent_follows\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n follow_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"followees\" (\n bot_id TEXT NOT NULL,\n followee_id TEXT NOT NULL,\n follow_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, followee_id)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_followees_followee_id\"\n ON \"${validatedSchema}\".\"followees\" (followee_id)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"quote_authorizations\" (\n bot_id TEXT NOT NULL,\n id TEXT NOT NULL,\n interacting_object TEXT NOT NULL,\n authorization_json JSONB NOT NULL,\n PRIMARY KEY (bot_id, id),\n UNIQUE (bot_id, interacting_object)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"quote_authorization_refs\" (\n bot_id TEXT NOT NULL,\n authorization_uri TEXT NOT NULL,\n message_id TEXT NOT NULL,\n attribution_uri TEXT,\n PRIMARY KEY (bot_id, authorization_uri)\n )`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_quote_authorization_refs_authorization\"\n ON \"${validatedSchema}\".\"quote_authorization_refs\" (authorization_uri)`,\n [],\n prepare,\n );\n await execute(\n sql,\n `ALTER TABLE \"${validatedSchema}\".\"quote_authorization_refs\"\n ADD COLUMN IF NOT EXISTS attribution_uri TEXT`,\n [],\n prepare,\n );\n await execute(\n sql,\n `CREATE TABLE IF NOT EXISTS \"${validatedSchema}\".\"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 prepare,\n );\n await execute(\n sql,\n `CREATE INDEX IF NOT EXISTS \"idx_poll_votes_message_option\"\n ON \"${validatedSchema}\".\"poll_votes\" (bot_id, message_id, option)`,\n [],\n prepare,\n );\n}\n\nconst upgradableTables = [\n \"key_pairs\",\n \"messages\",\n \"followers\",\n \"follow_requests\",\n \"sent_follows\",\n \"followees\",\n \"quote_authorizations\",\n \"poll_votes\",\n] as const;\n\n/**\n * Upgrades tables created by \\@fedify/botkit-postgres 0.4, which had no\n * `bot_id` column, into the bot-scoped schema. Existing rows get the\n * empty-string bot ID; use {@link PostgresRepository.migrate} to assign them\n * to a bot actor identifier.\n *\n * The whole upgrade is sent as a single multi-statement query without\n * parameters, which PostgreSQL executes over the simple query protocol in\n * one implicit transaction on one connection, so it is atomic even when\n * `sql` is a connection pool.\n */\nasync function upgradeLegacySchema(\n sql: Queryable,\n schema: string,\n prepare: boolean,\n): Promise<void> {\n const rows = await execute<{ readonly table_name: string }>(\n sql,\n `SELECT t.table_name\n FROM information_schema.tables t\n WHERE t.table_schema = $1\n AND t.table_name = ANY($2)\n AND NOT EXISTS (\n SELECT 1\n FROM information_schema.columns c\n WHERE c.table_schema = t.table_schema\n AND c.table_name = t.table_name\n AND c.column_name = 'bot_id'\n )`,\n [schema, [...upgradableTables]],\n prepare,\n );\n if (rows.length < 1) return;\n const tables = rows.map((row) => row.table_name);\n logger.info(\n \"Upgrading legacy tables without a bot_id column: {tables}.\",\n { tables },\n );\n // Multiple processes can start against the same legacy schema at once, so\n // the whole upgrade runs inside one PL/pgSQL block: an advisory lock\n // serializes it, and every table is re-checked under the lock, so the\n // process that lost the race finds nothing left to do. The detection\n // query above is merely a fast path for already-upgraded schemas.\n const legacyTable = (table: string) =>\n `EXISTS (SELECT 1\n FROM information_schema.tables t\n WHERE t.table_schema = '${schema}' AND t.table_name = '${table}')\n AND NOT EXISTS (SELECT 1\n FROM information_schema.columns c\n WHERE c.table_schema = '${schema}' AND c.table_name = '${table}'\n AND c.column_name = 'bot_id')`;\n const block = `\n DO $botkit_upgrade$\n DECLARE\n upgraded boolean := false;\n BEGIN\n PERFORM pg_catalog.pg_advisory_xact_lock(\n ${schemaUpgradeAdvisoryLockNamespace},\n pg_catalog.hashtext('${schema}')\n );\n\n IF ${legacyTable(\"follow_requests\")} THEN\n -- The old foreign key referenced followers (follower_id) only; it\n -- has to go away before the followers primary key changes:\n ALTER TABLE \"${schema}\".\"follow_requests\"\n DROP CONSTRAINT IF EXISTS \"follow_requests_follower_id_fkey\";\n END IF;\n\n IF ${legacyTable(\"key_pairs\")} THEN\n ALTER TABLE \"${schema}\".\"key_pairs\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"key_pairs\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"key_pairs\"\n DROP CONSTRAINT IF EXISTS \"key_pairs_pkey\";\n ALTER TABLE \"${schema}\".\"key_pairs\" ADD PRIMARY KEY (bot_id, position);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"messages\")} THEN\n ALTER TABLE \"${schema}\".\"messages\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"messages\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"messages\"\n DROP CONSTRAINT IF EXISTS \"messages_pkey\";\n ALTER TABLE \"${schema}\".\"messages\" ADD PRIMARY KEY (bot_id, id);\n DROP INDEX IF EXISTS \"${schema}\".\"idx_messages_published\";\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"followers\")} THEN\n ALTER TABLE \"${schema}\".\"followers\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"followers\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"followers\"\n DROP CONSTRAINT IF EXISTS \"followers_pkey\";\n ALTER TABLE \"${schema}\".\"followers\"\n ADD PRIMARY KEY (bot_id, follower_id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"follow_requests\")} THEN\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"follow_requests\"\n DROP CONSTRAINT IF EXISTS \"follow_requests_pkey\";\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD PRIMARY KEY (bot_id, follow_request_id);\n ALTER TABLE \"${schema}\".\"follow_requests\"\n ADD FOREIGN KEY (bot_id, follower_id)\n REFERENCES \"${schema}\".\"followers\" (bot_id, follower_id)\n ON DELETE CASCADE\n DEFERRABLE INITIALLY IMMEDIATE;\n DROP INDEX IF EXISTS \"${schema}\".\"idx_follow_requests_follower\";\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"sent_follows\")} THEN\n ALTER TABLE \"${schema}\".\"sent_follows\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"sent_follows\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"sent_follows\"\n DROP CONSTRAINT IF EXISTS \"sent_follows_pkey\";\n ALTER TABLE \"${schema}\".\"sent_follows\" ADD PRIMARY KEY (bot_id, id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"followees\")} THEN\n ALTER TABLE \"${schema}\".\"followees\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"followees\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"followees\"\n DROP CONSTRAINT IF EXISTS \"followees_pkey\";\n ALTER TABLE \"${schema}\".\"followees\"\n ADD PRIMARY KEY (bot_id, followee_id);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"quote_authorizations\")} THEN\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n DROP CONSTRAINT IF EXISTS \"quote_authorizations_pkey\";\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD PRIMARY KEY (bot_id, id);\n ALTER TABLE \"${schema}\".\"quote_authorizations\"\n ADD UNIQUE (bot_id, interacting_object);\n upgraded := true;\n END IF;\n\n IF ${legacyTable(\"poll_votes\")} THEN\n ALTER TABLE \"${schema}\".\"poll_votes\"\n ADD COLUMN bot_id TEXT NOT NULL DEFAULT '';\n ALTER TABLE \"${schema}\".\"poll_votes\" ALTER COLUMN bot_id DROP DEFAULT;\n ALTER TABLE \"${schema}\".\"poll_votes\"\n DROP CONSTRAINT IF EXISTS \"poll_votes_pkey\";\n ALTER TABLE \"${schema}\".\"poll_votes\"\n ADD PRIMARY KEY (bot_id, message_id, voter_id, option);\n DROP INDEX IF EXISTS \"${schema}\".\"idx_poll_votes_message_option\";\n upgraded := true;\n END IF;\n\n IF upgraded THEN\n -- The marker lets migrate() distinguish rows carried over from\n -- a legacy schema (bot_id = '') from data legitimately stored under\n -- an empty-string identifier:\n CREATE TABLE IF NOT EXISTS \"${schema}\".\"botkit_metadata\" (\n \"key\" TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n INSERT INTO \"${schema}\".\"botkit_metadata\" (\"key\", value)\n VALUES ('legacy_data', '1')\n ON CONFLICT (\"key\") DO NOTHING;\n END IF;\n END\n $botkit_upgrade$\n `;\n // DO blocks cannot be prepared:\n await execute(sql, block, [], false);\n logger.info(\"Finished upgrading legacy tables.\");\n}\n\n/**\n * A repository for storing bot data using PostgreSQL.\n * @since 0.4.0\n */\nexport class PostgresRepository implements Repository, AsyncDisposable {\n readonly sql: postgres.Sql;\n readonly schema: string;\n readonly prepare: boolean;\n private readonly ownsSql: boolean;\n private readonly ready: Promise<void>;\n\n constructor(options: PostgresRepositoryOptions) {\n this.schema = validateSchemaName(options.schema ?? \"botkit\");\n this.prepare = options.prepare ?? true;\n if (\"sql\" in options) {\n if (options.url != null || options.maxConnections != null) {\n throw new TypeError(\n \"PostgresRepositoryOptions.sql cannot be combined with PostgresRepositoryOptions.url or PostgresRepositoryOptions.maxConnections.\",\n );\n }\n this.ownsSql = false;\n this.sql = options.sql;\n } else {\n if (options.url == null) {\n throw new TypeError(\n \"PostgresRepositoryOptions.url must be provided when PostgresRepositoryOptions.sql is absent.\",\n );\n }\n this.ownsSql = true;\n const url = typeof options.url === \"string\"\n ? options.url\n : options.url.href;\n this.sql = postgres(url, {\n max: options.maxConnections,\n onnotice: () => {},\n prepare: this.prepare,\n });\n }\n const ready = initializePostgresRepositorySchema(\n this.sql,\n this.schema,\n this.prepare,\n );\n // Avoid unhandled rejection warnings before a repository method awaits it.\n ready.catch(() => {});\n this.ready = ready;\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n\n /**\n * Closes the underlying PostgreSQL connection pool if owned by the\n * repository.\n */\n async close(): Promise<void> {\n try {\n await this.ready;\n } finally {\n if (this.ownsSql) {\n await this.sql.end({ timeout: 5 });\n }\n }\n }\n\n async setKeyPairs(\n identifier: string,\n keyPairs: CryptoKeyPair[],\n ): Promise<void> {\n await this.ensureReady();\n await this.sql.begin(async (sql) => {\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"key_pairs\")} WHERE bot_id = $1`,\n [identifier],\n );\n for (const [position, keyPair] of keyPairs.entries()) {\n const privateJwk = await exportJwk(keyPair.privateKey);\n const publicJwk = await exportJwk(keyPair.publicKey);\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"key_pairs\")}\n (bot_id, position, private_key_jwk, public_key_jwk)\n VALUES ($1, $2, $3::jsonb, $4::jsonb)`,\n [\n identifier,\n position,\n serializeJson(privateJwk),\n serializeJson(publicJwk),\n ],\n );\n }\n });\n }\n\n async getKeyPairs(identifier: string): Promise<CryptoKeyPair[] | undefined> {\n await this.ensureReady();\n const rows = await this.query<{\n readonly private_key_jwk: unknown;\n readonly public_key_jwk: unknown;\n }>(\n this.sql,\n `SELECT private_key_jwk, public_key_jwk\n FROM ${this.table(\"key_pairs\")}\n WHERE bot_id = $1\n ORDER BY position ASC`,\n [identifier],\n );\n if (rows.length < 1) return undefined;\n const keyPairs: CryptoKeyPair[] = [];\n for (const row of rows) {\n const privateJwk = normalizeJsonObject(row.private_key_jwk);\n const publicJwk = normalizeJsonObject(row.public_key_jwk);\n if (privateJwk == null || publicJwk == null) {\n throw new TypeError(\"A stored key pair is malformed.\");\n }\n keyPairs.push({\n privateKey: await importJwk(privateJwk, \"private\"),\n publicKey: await importJwk(publicJwk, \"public\"),\n });\n }\n return keyPairs;\n }\n\n async addMessage(\n identifier: string,\n id: Uuid,\n activity: Create | Announce,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"messages\")}\n (bot_id, id, activity_json, published)\n VALUES ($1, $2, $3::jsonb, $4)`,\n [\n identifier,\n id,\n serializeJson(await activity.toJsonLd({ format: \"compact\" })),\n activity.published?.epochMilliseconds ?? null,\n ],\n );\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 await this.ensureReady();\n return await this.sql.begin(async (sql) => {\n const rows = await this.query<{ readonly activity_json: unknown }>(\n sql,\n `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2\n FOR UPDATE`,\n [identifier, id],\n );\n const row = rows[0];\n if (row == null) return false;\n const activity = await parseActivity(row.activity_json);\n if (activity == null) return false;\n const updated = await updater(activity);\n if (updated == null) return false;\n await this.query(\n sql,\n `UPDATE ${this.table(\"messages\")}\n SET activity_json = $1::jsonb,\n published = $2\n WHERE bot_id = $3 AND id = $4`,\n [\n serializeJson(await updated.toJsonLd({ format: \"compact\" })),\n updated.published?.epochMilliseconds ?? null,\n identifier,\n id,\n ],\n );\n return true;\n });\n }\n\n async removeMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING activity_json`,\n [identifier, id],\n );\n return await parseActivity(rows[0]?.activity_json);\n }\n\n async *getMessages(\n identifier: string,\n options: RepositoryGetMessagesOptions = {},\n ): AsyncIterable<Create | Announce> {\n await this.ensureReady();\n const { order = \"newest\", since, until, limit } = options;\n const parameters: QueryParameter[] = [identifier];\n let query = `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1`;\n if (since != null) {\n parameters.push(since.epochMilliseconds);\n query += ` AND published >= $${parameters.length}`;\n }\n if (until != null) {\n parameters.push(until.epochMilliseconds);\n query += ` AND published <= $${parameters.length}`;\n }\n query += order === \"oldest\"\n ? \" ORDER BY published ASC NULLS LAST, id ASC\"\n : \" ORDER BY published DESC NULLS LAST, id DESC\";\n if (limit != null) {\n parameters.push(limit);\n query += ` LIMIT $${parameters.length}`;\n }\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n query,\n parameters,\n );\n for (const row of rows) {\n const activity = await parseActivity(row.activity_json);\n if (activity != null) yield activity;\n }\n }\n\n async getMessage(\n identifier: string,\n id: Uuid,\n ): Promise<Create | Announce | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly activity_json: unknown }>(\n this.sql,\n `SELECT activity_json\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseActivity(rows[0]?.activity_json);\n }\n\n async countMessages(identifier: string): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(*)::integer AS count\n FROM ${this.table(\"messages\")}\n WHERE bot_id = $1`,\n [identifier],\n );\n return rows[0]?.count ?? 0;\n }\n\n async addFollower(\n identifier: string,\n followId: URL,\n follower: Actor,\n ): Promise<void> {\n await this.ensureReady();\n if (follower.id == null) {\n throw new TypeError(\"The follower ID is missing.\");\n }\n const followerId = follower.id;\n const followerJson = await follower.toJsonLd({ format: \"compact\" });\n await this.sql.begin(async (sql) => {\n await this.lockFollowRequest(sql, identifier, followId);\n const rows = await this.query<{ readonly follower_id: string }>(\n sql,\n `SELECT follower_id\n FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1 AND follow_request_id = $2\n FOR UPDATE`,\n [identifier, followId.href],\n );\n const previousFollowerId = rows[0]?.follower_id;\n await this.lockFollowers(sql, identifier, [\n followerId.href,\n ...(previousFollowerId == null ? [] : [previousFollowerId]),\n ]);\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"followers\")}\n (bot_id, follower_id, actor_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, follower_id)\n DO UPDATE SET actor_json = EXCLUDED.actor_json`,\n [identifier, followerId.href, serializeJson(followerJson)],\n );\n await this.query(\n sql,\n `INSERT INTO ${this.table(\"follow_requests\")}\n (bot_id, follow_request_id, follower_id)\n VALUES ($1, $2, $3)\n ON CONFLICT (bot_id, follow_request_id)\n DO UPDATE SET follower_id = EXCLUDED.follower_id`,\n [identifier, followId.href, followerId.href],\n );\n if (\n previousFollowerId != null && previousFollowerId !== followerId.href\n ) {\n await this.cleanupFollower(sql, identifier, previousFollowerId);\n }\n });\n }\n\n async removeFollower(\n identifier: string,\n followId: URL,\n followerId: URL,\n ): Promise<Actor | undefined> {\n await this.ensureReady();\n return await this.sql.begin(async (sql) => {\n await this.lockFollowRequest(sql, identifier, followId);\n const rows = await this.query<{ readonly actor_json: unknown }>(\n sql,\n `SELECT f.actor_json\n FROM ${this.table(\"follow_requests\")} AS fr\n JOIN ${this.table(\"followers\")} AS f\n ON f.bot_id = fr.bot_id AND f.follower_id = fr.follower_id\n WHERE fr.bot_id = $1\n AND fr.follow_request_id = $2\n AND fr.follower_id = $3\n FOR UPDATE`,\n [identifier, followId.href, followerId.href],\n );\n const row = rows[0];\n if (row == null) return undefined;\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1 AND follow_request_id = $2`,\n [identifier, followId.href],\n );\n const removed = await this.cleanupFollower(\n sql,\n identifier,\n followerId.href,\n );\n return removed ? await parseActor(row.actor_json) : undefined;\n });\n }\n\n async hasFollower(identifier: string, followerId: URL): Promise<boolean> {\n await this.ensureReady();\n const rows = await this.query<{ readonly exists: number }>(\n this.sql,\n `SELECT 1 AS exists\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1 AND follower_id = $2`,\n [identifier, followerId.href],\n );\n return rows.length > 0;\n }\n\n async *getFollowers(\n identifier: string,\n options: RepositoryGetFollowersOptions = {},\n ): AsyncIterable<Actor> {\n await this.ensureReady();\n const { offset = 0, limit } = options;\n const parameters: QueryParameter[] = [identifier];\n let query = `SELECT actor_json\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1\n ORDER BY follower_id ASC`;\n if (limit != null) {\n parameters.push(limit, offset);\n query += ` LIMIT $${parameters.length - 1} OFFSET $${parameters.length}`;\n } else if (offset > 0) {\n parameters.push(offset);\n query += ` OFFSET $${parameters.length}`;\n }\n const rows = await this.query<{ readonly actor_json: unknown }>(\n this.sql,\n query,\n parameters,\n );\n for (const row of rows) {\n const actor = await parseActor(row.actor_json);\n if (actor != null) yield actor;\n }\n }\n\n async countFollowers(identifier: string): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(*)::integer AS count\n FROM ${this.table(\"followers\")}\n WHERE bot_id = $1`,\n [identifier],\n );\n return rows[0]?.count ?? 0;\n }\n\n async addSentFollow(\n identifier: string,\n id: Uuid,\n follow: Follow,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"sent_follows\")} (bot_id, id, follow_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, id)\n DO UPDATE SET follow_json = EXCLUDED.follow_json`,\n [\n identifier,\n id,\n serializeJson(await follow.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async removeSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"sent_follows\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING follow_json`,\n [identifier, id],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async getSentFollow(\n identifier: string,\n id: Uuid,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `SELECT follow_json\n FROM ${this.table(\"sent_follows\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async addFollowee(\n identifier: string,\n followeeId: URL,\n follow: Follow,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"followees\")}\n (bot_id, followee_id, follow_json)\n VALUES ($1, $2, $3::jsonb)\n ON CONFLICT (bot_id, followee_id)\n DO UPDATE SET follow_json = EXCLUDED.follow_json`,\n [\n identifier,\n followeeId.href,\n serializeJson(await follow.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async removeFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"followees\")}\n WHERE bot_id = $1 AND followee_id = $2\n RETURNING follow_json`,\n [identifier, followeeId.href],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async getFollowee(\n identifier: string,\n followeeId: URL,\n ): Promise<Follow | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly follow_json: unknown }>(\n this.sql,\n `SELECT follow_json\n FROM ${this.table(\"followees\")}\n WHERE bot_id = $1 AND followee_id = $2`,\n [identifier, followeeId.href],\n );\n return await parseFollow(rows[0]?.follow_json);\n }\n\n async *findFollowedBots(followeeId: URL): AsyncIterable<string> {\n await this.ensureReady();\n const rows = await this.query<{ readonly bot_id: string }>(\n this.sql,\n `SELECT bot_id\n FROM ${this.table(\"followees\")}\n WHERE followee_id = $1\n ORDER BY bot_id ASC`,\n [followeeId.href],\n );\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 await this.ensureReady();\n const interactingObject = authorization.interactingObjectId;\n if (interactingObject == null) {\n throw new TypeError(\n \"The quote authorization interacting object is missing.\",\n );\n }\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"quote_authorizations\")}\n (bot_id, id, interacting_object, authorization_json)\n VALUES ($1, $2, $3, $4::jsonb)\n ON CONFLICT (bot_id, interacting_object) DO NOTHING`,\n [\n identifier,\n id,\n interactingObject.href,\n serializeJson(await authorization.toJsonLd({ format: \"compact\" })),\n ],\n );\n }\n\n async getQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `SELECT authorization_json\n FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND id = $2`,\n [identifier, id],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async findQuoteAuthorization(\n identifier: string,\n interactingObject: URL,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `SELECT authorization_json\n FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND interacting_object = $2`,\n [identifier, interactingObject.href],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async removeQuoteAuthorization(\n identifier: string,\n id: Uuid,\n ): Promise<QuoteAuthorization | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly authorization_json: unknown }>(\n this.sql,\n `DELETE FROM ${this.table(\"quote_authorizations\")}\n WHERE bot_id = $1 AND id = $2\n RETURNING authorization_json`,\n [identifier, id],\n );\n return await parseQuoteAuthorization(rows[0]?.authorization_json);\n }\n\n async addQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n messageId: Uuid,\n attribution?: URL,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"quote_authorization_refs\")}\n (bot_id, authorization_uri, message_id, attribution_uri)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (bot_id, authorization_uri) DO UPDATE\n SET message_id = EXCLUDED.message_id,\n attribution_uri = EXCLUDED.attribution_uri`,\n [identifier, authorization.href, messageId, attribution?.href ?? null],\n );\n }\n\n async findQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<Uuid | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly message_id: Uuid }>(\n this.sql,\n `SELECT message_id\n FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n return rows[0]?.message_id;\n }\n\n async *findQuoteAuthorizationReferenceIdentifiers(\n authorization: URL,\n ): AsyncIterable<string> {\n await this.ensureReady();\n const rows = await this.query<{ readonly bot_id: string }>(\n this.sql,\n `SELECT bot_id\n FROM ${this.table(\"quote_authorization_refs\")}\n WHERE authorization_uri = $1\n ORDER BY bot_id`,\n [authorization.href],\n );\n for (const row of rows) yield row.bot_id;\n }\n\n async findQuoteAuthorizationReferenceAttribution(\n identifier: string,\n authorization: URL,\n ): Promise<URL | undefined> {\n await this.ensureReady();\n const rows = await this.query<{ readonly attribution_uri: string | null }>(\n this.sql,\n `SELECT attribution_uri\n FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n const attribution = rows[0]?.attribution_uri;\n if (attribution == null) return undefined;\n try {\n return new URL(attribution);\n } catch {\n return undefined;\n }\n }\n\n async removeQuoteAuthorizationReference(\n identifier: string,\n authorization: URL,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `DELETE FROM ${this.table(\"quote_authorization_refs\")}\n WHERE bot_id = $1 AND authorization_uri = $2`,\n [identifier, authorization.href],\n );\n }\n\n async vote(\n identifier: string,\n messageId: Uuid,\n voterId: URL,\n option: string,\n ): Promise<void> {\n await this.ensureReady();\n await this.query(\n this.sql,\n `INSERT INTO ${this.table(\"poll_votes\")}\n (bot_id, message_id, voter_id, option)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (bot_id, message_id, voter_id, option)\n DO NOTHING`,\n [identifier, messageId, voterId.href, option],\n );\n }\n\n async countVoters(identifier: string, messageId: Uuid): Promise<number> {\n await this.ensureReady();\n const rows = await this.query<{ readonly count: number }>(\n this.sql,\n `SELECT COUNT(DISTINCT voter_id)::integer AS count\n FROM ${this.table(\"poll_votes\")}\n WHERE bot_id = $1 AND message_id = $2`,\n [identifier, messageId],\n );\n return rows[0]?.count ?? 0;\n }\n\n async countVotes(\n identifier: string,\n messageId: Uuid,\n ): Promise<Readonly<Record<string, number>>> {\n await this.ensureReady();\n const rows = await this.query<{\n readonly option: string;\n readonly count: number;\n }>(\n this.sql,\n `SELECT option, COUNT(*)::integer AS count\n FROM ${this.table(\"poll_votes\")}\n WHERE bot_id = $1 AND message_id = $2\n GROUP BY option\n ORDER BY option ASC`,\n [identifier, messageId],\n );\n const result: Record<string, number> = {};\n for (const row of rows) {\n result[row.option] = row.count;\n }\n return result;\n }\n\n /**\n * Migrates data stored by \\@fedify/botkit-postgres 0.4, which was not\n * scoped by bot actor identifiers, so that it belongs to the given\n * identifier. Rows carried over from a legacy schema have the\n * empty-string bot ID; this method assigns them to the identifier in\n * a single transaction. It only acts when the schema was actually\n * upgraded from a legacy layout, 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 async migrate(identifier: string): Promise<void> {\n await this.ensureReady();\n await this.sql.begin(async (sql) => {\n const rows = await this.query<{ readonly value: string }>(\n sql,\n `SELECT value FROM ${this.table(\"botkit_metadata\")}\n WHERE \"key\" = 'legacy_data'\n FOR UPDATE`,\n );\n if (rows.length < 1) return;\n // The followers and follow_requests rows move in tandem, which\n // temporarily breaks the foreign key between them; defer the check to\n // the commit:\n await execute(sql, \"SET CONSTRAINTS ALL DEFERRED\", [], false);\n for (const table of upgradableTables) {\n await this.query(\n sql,\n `UPDATE \"${this.schema}\".\"${table}\"\n SET bot_id = $1\n WHERE bot_id = ''`,\n [identifier],\n );\n }\n await this.query(\n sql,\n `DELETE FROM ${this.table(\"botkit_metadata\")}\n WHERE \"key\" = 'legacy_data'`,\n );\n });\n }\n\n forIdentifier(identifier: string): ActorScopedRepository {\n return new ActorScopedRepository(this, identifier);\n }\n\n private table(name: string): string {\n return `\"${this.schema}\".\"${name}\"`;\n }\n\n private async lockFollowRequest(\n sql: Queryable,\n identifier: string,\n followId: URL,\n ): Promise<void> {\n await this.query(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock($1, pg_catalog.hashtext($2))`,\n [\n followRequestAdvisoryLockNamespace,\n `${this.schema}:${identifier}:${followId.href}`,\n ],\n );\n }\n\n private async lockFollower(\n sql: Queryable,\n identifier: string,\n followerId: string,\n ): Promise<void> {\n await this.query(\n sql,\n `SELECT pg_catalog.pg_advisory_xact_lock($1, pg_catalog.hashtext($2))`,\n [\n followerAdvisoryLockNamespace,\n `${this.schema}:${identifier}:${followerId}`,\n ],\n );\n }\n\n private async lockFollowers(\n sql: Queryable,\n identifier: string,\n followerIds: readonly string[],\n ): Promise<void> {\n const uniqueFollowerIds = [...new Set(followerIds)].sort();\n for (const followerId of uniqueFollowerIds) {\n await this.lockFollower(sql, identifier, followerId);\n }\n }\n\n private async cleanupFollower(\n sql: Queryable,\n identifier: string,\n followerId: string,\n ): Promise<boolean> {\n await this.lockFollower(sql, identifier, followerId);\n const rows = await this.query<{ readonly follower_id: string }>(\n sql,\n `DELETE FROM ${this.table(\"followers\")}\n WHERE bot_id = $1\n AND follower_id = $2\n AND NOT EXISTS (\n SELECT 1\n FROM ${this.table(\"follow_requests\")}\n WHERE bot_id = $1\n AND follower_id = $2\n )\n RETURNING follower_id`,\n [identifier, followerId],\n );\n return rows.length > 0;\n }\n\n private async ensureReady(): Promise<void> {\n await this.ready;\n }\n\n private async query<TRow extends object>(\n sql: Queryable,\n query: string,\n parameters: readonly QueryParameter[] = [],\n ): Promise<readonly TRow[]> {\n return await execute<TRow>(sql, query, parameters, this.prepare);\n }\n}\n\nfunction validateSchemaName(schema: string): string {\n if (!schemaNamePattern.test(schema)) {\n throw new TypeError(\"The PostgreSQL schema name is invalid.\");\n }\n return schema;\n}\n\nfunction hasTransaction(sql: Queryable): sql is TransactionalQueryable {\n return sql != null &&\n typeof (sql as Partial<TransactionalQueryable>).begin === \"function\";\n}\n\nasync function execute<TRow extends object>(\n sql: Queryable,\n query: string,\n parameters: readonly QueryParameter[] = [],\n prepare = true,\n): Promise<readonly TRow[]> {\n return await sql.unsafe<TRow[]>(\n query,\n [...parameters],\n { prepare },\n );\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value != null;\n}\n\nasync function parseActivity(\n json: unknown,\n): Promise<Create | Announce | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n const activity = await Activity.fromJsonLd(normalized);\n if (activity instanceof Create || activity instanceof Announce) {\n return activity;\n }\n } catch (error) {\n logger.warn(\"Failed to parse message activity.\", { error });\n }\n return undefined;\n}\n\nasync function parseActor(json: unknown): Promise<Actor | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n const actor = await Object.fromJsonLd(normalized);\n if (isActor(actor)) return actor;\n } catch (error) {\n logger.warn(\"Failed to parse follower actor.\", { error });\n }\n return undefined;\n}\n\nasync function parseFollow(json: unknown): Promise<Follow | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n return await Follow.fromJsonLd(normalized);\n } catch (error) {\n logger.warn(\"Failed to parse follow activity.\", { error });\n }\n return undefined;\n}\n\nasync function parseQuoteAuthorization(\n json: unknown,\n): Promise<QuoteAuthorization | undefined> {\n const normalized = normalizeJsonObject(json);\n if (normalized == null) return undefined;\n try {\n return await QuoteAuthorization.fromJsonLd(normalized);\n } catch (error) {\n logger.warn(\"Failed to parse quote authorization.\", { error });\n }\n return undefined;\n}\n\nfunction normalizeJsonObject(\n value: unknown,\n): Record<string, unknown> | undefined {\n if (isJsonObject(value)) return value;\n if (typeof value !== \"string\") return undefined;\n try {\n const parsed: unknown = JSON.parse(value);\n if (isJsonObject(parsed)) return parsed;\n } catch {\n return undefined;\n }\n return undefined;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/botkit-postgres",
3
- "version": "0.5.0-dev.290",
3
+ "version": "0.5.0-dev.297",
4
4
  "description": "PostgreSQL-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.297+1a0cd9c4"
47
47
  },
48
48
  "dependencies": {
49
49
  "@fedify/fedify": "^2.3.1",