feat: complete Ancestor quote bot with production-ready Docker support

This commit is contained in:
unfunny
2026-09-13 14:14:38 -04:00
parent f2016da05a
commit fe7351a7dc
1145 changed files with 30890 additions and 97684 deletions

View File

@@ -1,4 +1,16 @@
import _defineProperty from "@babel/runtime/helpers/defineProperty";
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RelationsEvent = exports.Relations = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _event = require("./event");
var _logger = require("../logger");
var _event2 = require("../@types/event");
var _typedEventEmitter = require("./typed-event-emitter");
var _room = require("./room");
/*
Copyright 2019, 2021, 2023 The Matrix.org Foundation C.I.C.
@@ -14,18 +26,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { EventStatus, MatrixEventEvent } from "./event.js";
import { logger } from "../logger.js";
import { RelationType } from "../@types/event.js";
import { TypedEventEmitter } from "./typed-event-emitter.js";
import { Room } from "./room.js";
export let RelationsEvent = /*#__PURE__*/function (RelationsEvent) {
let RelationsEvent = /*#__PURE__*/function (RelationsEvent) {
RelationsEvent["Add"] = "Relations.add";
RelationsEvent["Remove"] = "Relations.remove";
RelationsEvent["Redaction"] = "Relations.redaction";
return RelationsEvent;
}({});
exports.RelationsEvent = RelationsEvent;
const matchesEventType = (eventType, targetEventType, altTargetEventTypes = []) => [targetEventType, ...altTargetEventTypes].includes(eventType);
/**
@@ -36,7 +43,7 @@ const matchesEventType = (eventType, targetEventType, altTargetEventTypes = [])
* The typical way to get one of these containers is via
* EventTimelineSet#getRelationsForEvent.
*/
export class Relations extends TypedEventEmitter {
class Relations extends _typedEventEmitter.TypedEventEmitter {
/**
* @param relationType - The type of relation involved, such as "m.annotation", "m.reference", "m.replace", etc.
* @param eventType - The relation event's type, such as "m.reaction", etc.
@@ -45,32 +52,34 @@ export class Relations extends TypedEventEmitter {
*/
constructor(relationType, eventType, client, altEventTypes) {
super();
_defineProperty(this, "relationEventIds", new Set());
_defineProperty(this, "relations", new Set());
_defineProperty(this, "annotationsByKey", {});
_defineProperty(this, "annotationsBySender", {});
_defineProperty(this, "sortedAnnotationsByKey", []);
_defineProperty(this, "targetEvent", null);
_defineProperty(this, "creationEmitted", false);
_defineProperty(this, "replacementUpdateId", 0);
_defineProperty(this, "client", void 0);
this.relationType = relationType;
this.eventType = eventType;
this.altEventTypes = altEventTypes;
(0, _defineProperty2.default)(this, "relationEventIds", new Set());
(0, _defineProperty2.default)(this, "relations", new Set());
(0, _defineProperty2.default)(this, "annotationsByKey", {});
(0, _defineProperty2.default)(this, "annotationsBySender", {});
(0, _defineProperty2.default)(this, "sortedAnnotationsByKey", []);
(0, _defineProperty2.default)(this, "targetEvent", null);
(0, _defineProperty2.default)(this, "creationEmitted", false);
(0, _defineProperty2.default)(this, "client", void 0);
/**
* Listens for event status changes to remove cancelled events.
*
* @param event - The event whose status has changed
* @param status - The new status
*/
_defineProperty(this, "onEventStatus", (event, status) => {
(0, _defineProperty2.default)(this, "onEventStatus", (event, status) => {
if (!event.isSending()) {
// Sending is done, so we don't need to listen anymore
event.removeListener(MatrixEventEvent.Status, this.onEventStatus);
event.removeListener(_event.MatrixEventEvent.Status, this.onEventStatus);
return;
}
if (status !== EventStatus.CANCELLED) {
if (status !== _event.EventStatus.CANCELLED) {
return;
}
// Event was cancelled, remove from the collection
event.removeListener(MatrixEventEvent.Status, this.onEventStatus);
event.removeListener(_event.MatrixEventEvent.Status, this.onEventStatus);
this.removeEvent(event);
});
/**
@@ -83,24 +92,22 @@ export class Relations extends TypedEventEmitter {
*
* @param redactedEvent - The original relation event that is about to be redacted.
*/
_defineProperty(this, "onBeforeRedaction", async redactedEvent => {
(0, _defineProperty2.default)(this, "onBeforeRedaction", async redactedEvent => {
if (!this.relations.has(redactedEvent)) {
return;
}
this.relations.delete(redactedEvent);
if (this.relationType === RelationType.Annotation) {
if (this.relationType === _event2.RelationType.Annotation) {
// Remove the redacted annotation from aggregation by key
this.removeAnnotationFromAggregation(redactedEvent);
} else if (this.relationType === RelationType.Replace) {
await this.updateTargetEventReplacement();
} else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
}
redactedEvent.removeListener(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
redactedEvent.removeListener(_event.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
this.emit(RelationsEvent.Redaction, redactedEvent);
});
this.relationType = relationType;
this.eventType = eventType;
this.altEventTypes = altEventTypes;
this.client = client instanceof Room ? client.client : client;
this.client = client instanceof _room.Room ? client.client : client;
}
/**
@@ -114,29 +121,30 @@ export class Relations extends TypedEventEmitter {
}
const relation = event.getRelation();
if (!relation) {
logger.error("Event must have relation info");
_logger.logger.error("Event must have relation info");
return;
}
const relationType = relation.rel_type;
const eventType = event.getType();
if (this.relationType !== relationType || !matchesEventType(eventType, this.eventType, this.altEventTypes)) {
logger.error("Event relation info doesn't match this container");
_logger.logger.error("Event relation info doesn't match this container");
return;
}
// If the event is in the process of being sent, listen for cancellation
// so we can remove the event from the collection.
if (event.isSending()) {
event.on(MatrixEventEvent.Status, this.onEventStatus);
event.on(_event.MatrixEventEvent.Status, this.onEventStatus);
}
this.relations.add(event);
this.relationEventIds.add(event.getId());
if (this.relationType === RelationType.Annotation) {
if (this.relationType === _event2.RelationType.Annotation) {
this.addAnnotationToAggregation(event);
} else if (this.relationType === RelationType.Replace) {
await this.updateTargetEventReplacement();
} else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
}
event.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
event.on(_event.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
this.emit(RelationsEvent.Add, event);
this.maybeEmitCreated();
}
@@ -151,10 +159,11 @@ export class Relations extends TypedEventEmitter {
return;
}
this.relations.delete(event);
if (this.relationType === RelationType.Annotation) {
if (this.relationType === _event2.RelationType.Annotation) {
this.removeAnnotationFromAggregation(event);
} else if (this.relationType === RelationType.Replace) {
await this.updateTargetEventReplacement();
} else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
}
this.emit(RelationsEvent.Remove, event);
}
@@ -171,9 +180,10 @@ export class Relations extends TypedEventEmitter {
return [...this.relations];
}
addAnnotationToAggregation(event) {
var _event$getRelation;
const {
key
} = event.getRelation() ?? {};
} = (_event$getRelation = event.getRelation()) !== null && _event$getRelation !== void 0 ? _event$getRelation : {};
if (!key) return;
let eventsForKey = this.annotationsByKey[key];
if (!eventsForKey) {
@@ -197,9 +207,10 @@ export class Relations extends TypedEventEmitter {
eventsFromSender.add(event);
}
removeAnnotationFromAggregation(event) {
var _event$getRelation2;
const {
key
} = event.getRelation() ?? {};
} = (_event$getRelation2 = event.getRelation()) !== null && _event$getRelation2 !== void 0 ? _event$getRelation2 : {};
if (!key) return;
const eventsForKey = this.annotationsByKey[key];
if (eventsForKey) {
@@ -228,7 +239,7 @@ export class Relations extends TypedEventEmitter {
* The events are stored in a Set (which preserves insertion order).
*/
getSortedAnnotationsByKey() {
if (this.relationType !== RelationType.Annotation) {
if (this.relationType !== _event2.RelationType.Annotation) {
// Other relation types are not grouped currently.
return null;
}
@@ -244,7 +255,7 @@ export class Relations extends TypedEventEmitter {
* events for that sender as a value.
*/
getAnnotationsBySender() {
if (this.relationType !== RelationType.Annotation) {
if (this.relationType !== _event2.RelationType.Annotation) {
// Other relation types are not grouped currently.
return null;
}
@@ -258,7 +269,7 @@ export class Relations extends TypedEventEmitter {
* once the target event is known, see `addEvent`.
*/
async getLastReplacement() {
if (this.relationType !== RelationType.Replace) {
if (this.relationType !== _event2.RelationType.Replace) {
// Aggregating on last only makes sense for this relation type
return null;
}
@@ -271,8 +282,8 @@ export class Relations extends TypedEventEmitter {
// the all-knowning server tells us that the event at some point had
// this timestamp for its replacement, so any following replacement should definitely not be less
const replaceRelation = this.targetEvent.getServerAggregatedRelation(RelationType.Replace);
const minTs = replaceRelation?.origin_server_ts;
const replaceRelation = this.targetEvent.getServerAggregatedRelation(_event2.RelationType.Replace);
const minTs = replaceRelation === null || replaceRelation === void 0 ? void 0 : replaceRelation.origin_server_ts;
const lastReplacement = this.getRelations().reduce((last, event) => {
if (event.getSender() !== this.targetEvent.getSender()) {
return last;
@@ -285,10 +296,9 @@ export class Relations extends TypedEventEmitter {
}
return event;
}, null);
if (lastReplacement?.shouldAttemptDecryption() && this.client.getCrypto()) {
// Dirty but we are expecting to pass the cryptoBackend which is not accessible here
await lastReplacement.attemptDecryption(this.client.getCrypto());
} else if (lastReplacement?.isBeingDecrypted()) {
if (lastReplacement !== null && lastReplacement !== void 0 && lastReplacement.shouldAttemptDecryption() && this.client.isCryptoEnabled()) {
await lastReplacement.attemptDecryption(this.client.crypto);
} else if (lastReplacement !== null && lastReplacement !== void 0 && lastReplacement.isBeingDecrypted()) {
await lastReplacement.getDecryptionPromise();
}
return lastReplacement;
@@ -298,42 +308,20 @@ export class Relations extends TypedEventEmitter {
* @param targetEvent - the event the relations are related to.
*/
async setTargetEvent(event) {
if (this.targetEvent === event) {
if (this.targetEvent) {
return;
}
this.targetEvent = event;
if (this.relationType === RelationType.Replace) {
await this.updateTargetEventReplacement();
if (this.relationType === _event2.RelationType.Replace && !this.targetEvent.isState()) {
const replacement = await this.getLastReplacement();
// this is the initial update, so only call it if we already have something
// to not emit Event.replaced needlessly
if (replacement) {
this.targetEvent.makeReplaced(replacement);
}
}
this.maybeEmitCreated();
}
/**
* Updates the target event with the latest replacement.
*
* Multiple replacement updates can be triggered concurrently (for example
* while edits are still being decrypted). A monotonic update counter guards
* against older async resolutions overriding newer replacement selections.
*/
async updateTargetEventReplacement() {
if (!this.targetEvent || this.targetEvent.isState()) {
return;
}
const targetEvent = this.targetEvent;
const updateId = ++this.replacementUpdateId;
const lastReplacement = await this.getLastReplacement();
// If a newer update started while we were awaiting, discard this stale result.
if (updateId !== this.replacementUpdateId || this.targetEvent !== targetEvent) {
return;
}
// Avoid emitting Event.replaced when there is no replacement and none currently set.
if (!lastReplacement && !targetEvent.replacingEvent()) {
return;
}
targetEvent.makeReplaced(lastReplacement ?? undefined);
}
maybeEmitCreated() {
if (this.creationEmitted) {
return;
@@ -344,7 +332,8 @@ export class Relations extends TypedEventEmitter {
return;
}
this.creationEmitted = true;
this.targetEvent.emit(MatrixEventEvent.RelationsCreated, this.relationType, this.eventType);
this.targetEvent.emit(_event.MatrixEventEvent.RelationsCreated, this.relationType, this.eventType);
}
}
exports.Relations = Relations;
//# sourceMappingURL=relations.js.map