diff --git a/synapse/synapse_rust/__init__.pyi b/synapse/synapse_rust/__init__.pyi
new file mode 100644
index 0000000000..d25c609106
--- /dev/null
+++ b/synapse/synapse_rust/__init__.pyi
@@ -0,0 +1,3 @@
+def sum_as_string(a: int, b: int) -> str: ...
+def get_rust_file_digest() -> str: ...
+def reset_logging_config() -> None: ...
diff --git a/synapse/synapse_rust/acl.pyi b/synapse/synapse_rust/acl.pyi
new file mode 100644
index 0000000000..e03989b627
--- /dev/null
+++ b/synapse/synapse_rust/acl.pyi
@@ -0,0 +1,21 @@
+# Copyright 2023 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+from typing import List
+
+class ServerAclEvaluator:
+ def __init__(
+ self, allow_ip_literals: bool, allow: List[str], deny: List[str]
+ ) -> None: ...
+ def server_matches_acl_event(self, server_name: str) -> bool: ...
diff --git a/synapse/synapse_rust/events.pyi b/synapse/synapse_rust/events.pyi
new file mode 100644
index 0000000000..423ede5969
--- /dev/null
+++ b/synapse/synapse_rust/events.pyi
@@ -0,0 +1,106 @@
+# This file is licensed under the Affero General Public License (AGPL) version 3.
+#
+# Copyright (C) 2024 New Vector, Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# See the GNU Affero General Public License for more details:
+# <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+from typing import Optional
+
+from synapse.types import JsonDict
+
+class EventInternalMetadata:
+ def __init__(self, internal_metadata_dict: JsonDict): ...
+
+ stream_ordering: Optional[int]
+ """the stream ordering of this event. None, until it has been persisted."""
+
+ outlier: bool
+ """whether this event is an outlier (ie, whether we have the state at that
+ point in the DAG)"""
+
+ out_of_band_membership: bool
+ send_on_behalf_of: str
+ recheck_redaction: bool
+ soft_failed: bool
+ proactively_send: bool
+ redacted: bool
+
+ txn_id: str
+ """The transaction ID, if it was set when the event was created."""
+ token_id: int
+ """The access token ID of the user who sent this event, if any."""
+ device_id: str
+ """The device ID of the user who sent this event, if any."""
+
+ def get_dict(self) -> JsonDict: ...
+ def is_outlier(self) -> bool: ...
+ def copy(self) -> "EventInternalMetadata": ...
+ def is_out_of_band_membership(self) -> bool:
+ """Whether this event is an out-of-band membership.
+
+ OOB memberships are a special case of outlier events: they are membership events
+ for federated rooms that we aren't full members of. Examples include invites
+ received over federation, and rejections for such invites.
+
+ The concept of an OOB membership is needed because these events need to be
+ processed as if they're new regular events (e.g. updating membership state in
+ the database, relaying to clients via /sync, etc) despite being outliers.
+
+ See also https://element-hq.github.io/synapse/develop/development/room-dag-concepts.html#out-of-band-membership-events.
+
+ (Added in synapse 0.99.0, so may be unreliable for events received before that)
+ """
+ ...
+ def get_send_on_behalf_of(self) -> Optional[str]:
+ """Whether this server should send the event on behalf of another server.
+ This is used by the federation "send_join" API to forward the initial join
+ event for a server in the room.
+
+ returns a str with the name of the server this event is sent on behalf of.
+ """
+ ...
+ def need_to_check_redaction(self) -> bool:
+ """Whether the redaction event needs to be rechecked when fetching
+ from the database.
+
+ Starting in room v3 redaction events are accepted up front, and later
+ checked to see if the redacter and redactee's domains match.
+
+ If the sender of the redaction event is allowed to redact any event
+ due to auth rules, then this will always return false.
+ """
+ ...
+ def is_soft_failed(self) -> bool:
+ """Whether the event has been soft failed.
+
+ Soft failed events should be handled as usual, except:
+ 1. They should not go down sync or event streams, or generally
+ sent to clients.
+ 2. They should not be added to the forward extremities (and
+ therefore not to current state).
+ """
+ ...
+ def should_proactively_send(self) -> bool:
+ """Whether the event, if ours, should be sent to other clients and
+ servers.
+
+ This is used for sending dummy events internally. Servers and clients
+ can still explicitly fetch the event.
+ """
+ ...
+ def is_redacted(self) -> bool:
+ """Whether the event has been redacted.
+
+ This is used for efficiently checking whether an event has been
+ marked as redacted without needing to make another database call.
+ """
+ ...
+ def is_notifiable(self) -> bool:
+ """Whether this event can trigger a push notification"""
+ ...
diff --git a/synapse/synapse_rust/push.pyi b/synapse/synapse_rust/push.pyi
new file mode 100644
index 0000000000..25259ce91d
--- /dev/null
+++ b/synapse/synapse_rust/push.pyi
@@ -0,0 +1,76 @@
+# Copyright 2022 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+from typing import Any, Collection, Dict, Mapping, Optional, Sequence, Tuple, Union
+
+from synapse.types import JsonDict, JsonValue
+
+class PushRule:
+ @property
+ def rule_id(self) -> str: ...
+ @property
+ def priority_class(self) -> int: ...
+ @property
+ def conditions(self) -> Sequence[Mapping[str, str]]: ...
+ @property
+ def actions(self) -> Sequence[Union[Mapping[str, Any], str]]: ...
+ @property
+ def default(self) -> bool: ...
+ @property
+ def default_enabled(self) -> bool: ...
+ @staticmethod
+ def from_db(
+ rule_id: str, priority_class: int, conditions: str, actions: str
+ ) -> "PushRule": ...
+
+class PushRules:
+ def __init__(self, rules: Collection[PushRule]): ...
+ def rules(self) -> Collection[PushRule]: ...
+
+class FilteredPushRules:
+ def __init__(
+ self,
+ push_rules: PushRules,
+ enabled_map: Dict[str, bool],
+ msc1767_enabled: bool,
+ msc3381_polls_enabled: bool,
+ msc3664_enabled: bool,
+ msc4028_push_encrypted_events: bool,
+ ): ...
+ def rules(self) -> Collection[Tuple[PushRule, bool]]: ...
+
+def get_base_rule_ids() -> Collection[str]: ...
+
+class PushRuleEvaluator:
+ def __init__(
+ self,
+ flattened_keys: Mapping[str, JsonValue],
+ has_mentions: bool,
+ room_member_count: int,
+ sender_power_level: Optional[int],
+ notification_power_levels: Mapping[str, int],
+ related_events_flattened: Mapping[str, Mapping[str, JsonValue]],
+ related_event_match_enabled: bool,
+ room_version_feature_flags: Tuple[str, ...],
+ msc3931_enabled: bool,
+ ): ...
+ def run(
+ self,
+ push_rules: FilteredPushRules,
+ user_id: Optional[str],
+ display_name: Optional[str],
+ ) -> Collection[Union[Mapping, str]]: ...
+ def matches(
+ self, condition: JsonDict, user_id: Optional[str], display_name: Optional[str]
+ ) -> bool: ...
|