archastro.platform.channels.api_artifact_channel
1# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. 2# This file is auto-generated by @archastro/sdk-generator. Do not edit. 3# Content hash: 681181d58578 4 5from collections.abc import Callable 6from typing import TYPE_CHECKING, Any, Literal, Required, TypedDict 7 8if TYPE_CHECKING: 9 from archastro.phx_channel.socket import Socket 10 11 12class OperationInputCursor(TypedDict, total=False): 13 position: Required[int] 14 "Zero-based Unicode code-point position." 15 selection_end: int | None 16 "Zero-based Unicode code-point selection endpoint." 17 18 19class OperationInput(TypedDict, total=False): 20 "Submit an OT operation against a live revision; success replies only after application." 21 22 cursor: OperationInputCursor 23 "A Unicode code-point cursor and optional selection endpoint." 24 op: Required[list[Any]] 25 op_id: str 26 revision: Required[int] 27 28 29class CursorInputCursor(TypedDict, total=False): 30 position: Required[int] 31 "Zero-based Unicode code-point position." 32 selection_end: int | None 33 "Zero-based Unicode code-point selection endpoint." 34 35 36class CursorInput(TypedDict, total=False): 37 "Publish a cursor mapped from the supplied revision to the current head." 38 39 cursor: CursorInputCursor 40 "A Unicode code-point cursor and optional selection endpoint." 41 revision: int 42 43 44class SignalInput(TypedDict): 45 "Relay opaque, transient coordination to joined actors in document order." 46 47 kind: str 48 payload: dict[str, Any] 49 to: str 50 51 52class OpRejectedPayload(TypedDict): 53 "An identified operation was refused; it was not applied." 54 55 op_id: str 56 reason: str 57 58 59class OperationPayloadCursor(TypedDict, total=False): 60 position: Required[int] 61 "Zero-based Unicode code-point position." 62 selection_end: int | None 63 "Zero-based Unicode code-point selection endpoint." 64 65 66class OperationPayload(TypedDict): 67 "A peer operation applied by the authoritative OT server." 68 69 actor_id: str 70 cursor: OperationPayloadCursor | None 71 "A Unicode code-point cursor and optional selection endpoint." 72 incarnation: str 73 op: list[Any] 74 revision: int 75 76 77SignalPayload = TypedDict( 78 "SignalPayload", 79 { 80 "from": str, 81 "incarnation": str, 82 "kind": str, 83 "payload": dict[str, Any], 84 "revision": int, 85 "to": str, 86 }, 87) 88"Opaque coordination from another joined actor; never persisted or replayed." 89 90 91class PresencePayloadCursor(TypedDict, total=False): 92 position: Required[int] 93 "Zero-based Unicode code-point position." 94 selection_end: int | None 95 "Zero-based Unicode code-point selection endpoint." 96 97 98class PresencePayload(TypedDict): 99 "A peer joined, moved its cursor, or left." 100 101 actor_id: str 102 cursor: PresencePayloadCursor | None 103 "A Unicode code-point cursor and optional selection endpoint." 104 incarnation: str 105 meta: dict[str, Any] | None 106 revision: int | None 107 type: Literal["joined", "cursor", "left"] 108 109 110class CheckpointPayload(TypedDict): 111 "A live revision reached durable ArtifactVersion storage." 112 113 artifact_version: str 114 artifact_version_number: int 115 checkpointed_revision: int 116 dirty: bool 117 incarnation: str 118 119 120class CheckpointFailedPayload(TypedDict): 121 "A save failed; the dirty live tail remains crash-loss exposed." 122 123 automatic: bool 124 checkpointed_revision: int 125 dirty: bool 126 incarnation: str 127 reason: str 128 revision: int 129 130 131class SessionInvalidPayload(TypedDict): 132 "The live version was replaced, archived, or deleted and this incarnation is terminal." 133 134 incarnation: str 135 reason: Literal["replaced", "archived", "deleted", "owner_down"] 136 137 138class AccessRevokedPayload(TypedDict): 139 "Current read authority failed; this subscriber was detached before further egress." 140 141 reason: str 142 143 144# Authenticated collaborative editing for durable Artifacts. 145# The live OT revision and `dirty` flag describe synchronization, not durability. 146# Only `checkpointed_revision` and checkpoint events confirm a completed save; 147# process or node loss can discard the dirty tail after the last successful save. 148class ApiArtifactChannel: 149 def __init__(self, channel, join_response=None): 150 self._channel = channel 151 self.join_response = join_response 152 153 # Join an Artifact's authenticated live editing session. 154 @staticmethod 155 def topic_artifact(artifact_id: str) -> str: 156 return f"api:artifact:{artifact_id}" 157 158 # Join an Artifact's authenticated live editing session. 159 @classmethod 160 async def join_artifact( 161 cls, socket: "Socket", artifact_id: str, *, as_agent: str | None = None 162 ) -> "ApiArtifactChannel": 163 topic = cls.topic_artifact(artifact_id) 164 channel = socket.channel(topic) 165 payload: dict[str, object] = {} 166 if as_agent is not None: 167 payload["as_agent"] = as_agent 168 join_response = await channel.join(payload) 169 return cls(channel, join_response) 170 171 # Leave the underlying channel. 172 async def leave(self): 173 await self._channel.leave() 174 175 # Submit an OT operation against a live revision; success replies only after application. 176 async def operation(self, payload: OperationInput) -> dict[str, Any]: 177 return await self._channel.push("operation", payload) 178 179 # Publish a cursor mapped from the supplied revision to the current head. 180 async def cursor(self, payload: CursorInput) -> dict[str, Any]: 181 return await self._channel.push("cursor", payload) 182 183 # Relay opaque, transient coordination to joined actors in document order. 184 async def signal(self, payload: SignalInput) -> dict[str, Any]: 185 return await self._channel.push("signal", payload) 186 187 # Persist the current live snapshot as a new durable ArtifactVersion. 188 async def checkpoint(self, payload: dict) -> dict[str, Any]: 189 return await self._channel.push("checkpoint", payload) 190 191 # Detach this server-issued actor from the live session. 192 async def leave_message(self, payload: dict) -> dict[str, Any]: 193 return await self._channel.push("leave", payload) 194 195 # An identified operation was refused; it was not applied. 196 def on_op_rejected(self, callback: Callable[[OpRejectedPayload], None]) -> Callable[[], None]: 197 return self._channel.on("op_rejected", callback) 198 199 # A peer operation applied by the authoritative OT server. 200 def on_operation(self, callback: Callable[[OperationPayload], None]) -> Callable[[], None]: 201 return self._channel.on("operation", callback) 202 203 # Opaque coordination from another joined actor; never persisted or replayed. 204 def on_signal(self, callback: Callable[[SignalPayload], None]) -> Callable[[], None]: 205 return self._channel.on("signal", callback) 206 207 # A peer joined, moved its cursor, or left. 208 def on_presence(self, callback: Callable[[PresencePayload], None]) -> Callable[[], None]: 209 return self._channel.on("presence", callback) 210 211 # A live revision reached durable ArtifactVersion storage. 212 def on_checkpoint(self, callback: Callable[[CheckpointPayload], None]) -> Callable[[], None]: 213 return self._channel.on("checkpoint", callback) 214 215 # A save failed; the dirty live tail remains crash-loss exposed. 216 def on_checkpoint_failed( 217 self, callback: Callable[[CheckpointFailedPayload], None] 218 ) -> Callable[[], None]: 219 return self._channel.on("checkpoint_failed", callback) 220 221 # The live version was replaced, archived, or deleted and this incarnation is terminal. 222 def on_session_invalid( 223 self, callback: Callable[[SessionInvalidPayload], None] 224 ) -> Callable[[], None]: 225 return self._channel.on("session_invalid", callback) 226 227 # Current read authority failed; this subscriber was detached before further egress. 228 def on_access_revoked( 229 self, callback: Callable[[AccessRevokedPayload], None] 230 ) -> Callable[[], None]: 231 return self._channel.on("access_revoked", callback)
class
OperationInputCursor(typing.TypedDict):
class
OperationInput(typing.TypedDict):
20class OperationInput(TypedDict, total=False): 21 "Submit an OT operation against a live revision; success replies only after application." 22 23 cursor: OperationInputCursor 24 "A Unicode code-point cursor and optional selection endpoint." 25 op: Required[list[Any]] 26 op_id: str 27 revision: Required[int]
Submit an OT operation against a live revision; success replies only after application.
class
CursorInputCursor(typing.TypedDict):
class
CursorInput(typing.TypedDict):
37class CursorInput(TypedDict, total=False): 38 "Publish a cursor mapped from the supplied revision to the current head." 39 40 cursor: CursorInputCursor 41 "A Unicode code-point cursor and optional selection endpoint." 42 revision: int
Publish a cursor mapped from the supplied revision to the current head.
class
SignalInput(typing.TypedDict):
45class SignalInput(TypedDict): 46 "Relay opaque, transient coordination to joined actors in document order." 47 48 kind: str 49 payload: dict[str, Any] 50 to: str
Relay opaque, transient coordination to joined actors in document order.
class
OpRejectedPayload(typing.TypedDict):
53class OpRejectedPayload(TypedDict): 54 "An identified operation was refused; it was not applied." 55 56 op_id: str 57 reason: str
An identified operation was refused; it was not applied.
class
OperationPayloadCursor(typing.TypedDict):
class
OperationPayload(typing.TypedDict):
67class OperationPayload(TypedDict): 68 "A peer operation applied by the authoritative OT server." 69 70 actor_id: str 71 cursor: OperationPayloadCursor | None 72 "A Unicode code-point cursor and optional selection endpoint." 73 incarnation: str 74 op: list[Any] 75 revision: int
A peer operation applied by the authoritative OT server.
class
SignalPayload(typing.TypedDict):
Opaque coordination from another joined actor; never persisted or replayed.
class
PresencePayloadCursor(typing.TypedDict):
class
PresencePayload(typing.TypedDict):
99class PresencePayload(TypedDict): 100 "A peer joined, moved its cursor, or left." 101 102 actor_id: str 103 cursor: PresencePayloadCursor | None 104 "A Unicode code-point cursor and optional selection endpoint." 105 incarnation: str 106 meta: dict[str, Any] | None 107 revision: int | None 108 type: Literal["joined", "cursor", "left"]
A peer joined, moved its cursor, or left.
class
CheckpointPayload(typing.TypedDict):
111class CheckpointPayload(TypedDict): 112 "A live revision reached durable ArtifactVersion storage." 113 114 artifact_version: str 115 artifact_version_number: int 116 checkpointed_revision: int 117 dirty: bool 118 incarnation: str
A live revision reached durable ArtifactVersion storage.
class
CheckpointFailedPayload(typing.TypedDict):
121class CheckpointFailedPayload(TypedDict): 122 "A save failed; the dirty live tail remains crash-loss exposed." 123 124 automatic: bool 125 checkpointed_revision: int 126 dirty: bool 127 incarnation: str 128 reason: str 129 revision: int
A save failed; the dirty live tail remains crash-loss exposed.
class
SessionInvalidPayload(typing.TypedDict):
132class SessionInvalidPayload(TypedDict): 133 "The live version was replaced, archived, or deleted and this incarnation is terminal." 134 135 incarnation: str 136 reason: Literal["replaced", "archived", "deleted", "owner_down"]
The live version was replaced, archived, or deleted and this incarnation is terminal.
class
AccessRevokedPayload(typing.TypedDict):
139class AccessRevokedPayload(TypedDict): 140 "Current read authority failed; this subscriber was detached before further egress." 141 142 reason: str
Current read authority failed; this subscriber was detached before further egress.
class
ApiArtifactChannel:
149class ApiArtifactChannel: 150 def __init__(self, channel, join_response=None): 151 self._channel = channel 152 self.join_response = join_response 153 154 # Join an Artifact's authenticated live editing session. 155 @staticmethod 156 def topic_artifact(artifact_id: str) -> str: 157 return f"api:artifact:{artifact_id}" 158 159 # Join an Artifact's authenticated live editing session. 160 @classmethod 161 async def join_artifact( 162 cls, socket: "Socket", artifact_id: str, *, as_agent: str | None = None 163 ) -> "ApiArtifactChannel": 164 topic = cls.topic_artifact(artifact_id) 165 channel = socket.channel(topic) 166 payload: dict[str, object] = {} 167 if as_agent is not None: 168 payload["as_agent"] = as_agent 169 join_response = await channel.join(payload) 170 return cls(channel, join_response) 171 172 # Leave the underlying channel. 173 async def leave(self): 174 await self._channel.leave() 175 176 # Submit an OT operation against a live revision; success replies only after application. 177 async def operation(self, payload: OperationInput) -> dict[str, Any]: 178 return await self._channel.push("operation", payload) 179 180 # Publish a cursor mapped from the supplied revision to the current head. 181 async def cursor(self, payload: CursorInput) -> dict[str, Any]: 182 return await self._channel.push("cursor", payload) 183 184 # Relay opaque, transient coordination to joined actors in document order. 185 async def signal(self, payload: SignalInput) -> dict[str, Any]: 186 return await self._channel.push("signal", payload) 187 188 # Persist the current live snapshot as a new durable ArtifactVersion. 189 async def checkpoint(self, payload: dict) -> dict[str, Any]: 190 return await self._channel.push("checkpoint", payload) 191 192 # Detach this server-issued actor from the live session. 193 async def leave_message(self, payload: dict) -> dict[str, Any]: 194 return await self._channel.push("leave", payload) 195 196 # An identified operation was refused; it was not applied. 197 def on_op_rejected(self, callback: Callable[[OpRejectedPayload], None]) -> Callable[[], None]: 198 return self._channel.on("op_rejected", callback) 199 200 # A peer operation applied by the authoritative OT server. 201 def on_operation(self, callback: Callable[[OperationPayload], None]) -> Callable[[], None]: 202 return self._channel.on("operation", callback) 203 204 # Opaque coordination from another joined actor; never persisted or replayed. 205 def on_signal(self, callback: Callable[[SignalPayload], None]) -> Callable[[], None]: 206 return self._channel.on("signal", callback) 207 208 # A peer joined, moved its cursor, or left. 209 def on_presence(self, callback: Callable[[PresencePayload], None]) -> Callable[[], None]: 210 return self._channel.on("presence", callback) 211 212 # A live revision reached durable ArtifactVersion storage. 213 def on_checkpoint(self, callback: Callable[[CheckpointPayload], None]) -> Callable[[], None]: 214 return self._channel.on("checkpoint", callback) 215 216 # A save failed; the dirty live tail remains crash-loss exposed. 217 def on_checkpoint_failed( 218 self, callback: Callable[[CheckpointFailedPayload], None] 219 ) -> Callable[[], None]: 220 return self._channel.on("checkpoint_failed", callback) 221 222 # The live version was replaced, archived, or deleted and this incarnation is terminal. 223 def on_session_invalid( 224 self, callback: Callable[[SessionInvalidPayload], None] 225 ) -> Callable[[], None]: 226 return self._channel.on("session_invalid", callback) 227 228 # Current read authority failed; this subscriber was detached before further egress. 229 def on_access_revoked( 230 self, callback: Callable[[AccessRevokedPayload], None] 231 ) -> Callable[[], None]: 232 return self._channel.on("access_revoked", callback)
@classmethod
async def
join_artifact( cls, socket: archastro.phx_channel.Socket, artifact_id: str, *, as_agent: str | None = None) -> ApiArtifactChannel:
160 @classmethod 161 async def join_artifact( 162 cls, socket: "Socket", artifact_id: str, *, as_agent: str | None = None 163 ) -> "ApiArtifactChannel": 164 topic = cls.topic_artifact(artifact_id) 165 channel = socket.channel(topic) 166 payload: dict[str, object] = {} 167 if as_agent is not None: 168 payload["as_agent"] = as_agent 169 join_response = await channel.join(payload) 170 return cls(channel, join_response)
def
on_checkpoint_failed( self, callback: Callable[[CheckpointFailedPayload], None]) -> Callable[[], None]:
def
on_session_invalid( self, callback: Callable[[SessionInvalidPayload], None]) -> Callable[[], None]:
def
on_access_revoked( self, callback: Callable[[AccessRevokedPayload], None]) -> Callable[[], None]: