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):
13class OperationInputCursor(TypedDict, total=False):
14    position: Required[int]
15    "Zero-based Unicode code-point position."
16    selection_end: int | None
17    "Zero-based Unicode code-point selection endpoint."
position: Required[int]

Zero-based Unicode code-point position.

selection_end: int | None

Zero-based Unicode code-point selection endpoint.

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.

A Unicode code-point cursor and optional selection endpoint.

op: Required[list[Any]]
op_id: str
revision: Required[int]
class CursorInputCursor(typing.TypedDict):
30class CursorInputCursor(TypedDict, total=False):
31    position: Required[int]
32    "Zero-based Unicode code-point position."
33    selection_end: int | None
34    "Zero-based Unicode code-point selection endpoint."
position: Required[int]

Zero-based Unicode code-point position.

selection_end: int | None

Zero-based Unicode code-point selection endpoint.

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.

A Unicode code-point cursor and optional selection endpoint.

revision: int
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.

kind: str
payload: dict[str, typing.Any]
to: str
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.

op_id: str
reason: str
class OperationPayloadCursor(typing.TypedDict):
60class OperationPayloadCursor(TypedDict, total=False):
61    position: Required[int]
62    "Zero-based Unicode code-point position."
63    selection_end: int | None
64    "Zero-based Unicode code-point selection endpoint."
position: Required[int]

Zero-based Unicode code-point position.

selection_end: int | None

Zero-based Unicode code-point selection endpoint.

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.

actor_id: str
cursor: OperationPayloadCursor | None

A Unicode code-point cursor and optional selection endpoint.

incarnation: str
op: list[typing.Any]
revision: int
class SignalPayload(typing.TypedDict):

Opaque coordination from another joined actor; never persisted or replayed.

from: str
incarnation: str
kind: str
payload: dict[str, typing.Any]
revision: int
to: str
class PresencePayloadCursor(typing.TypedDict):
92class PresencePayloadCursor(TypedDict, total=False):
93    position: Required[int]
94    "Zero-based Unicode code-point position."
95    selection_end: int | None
96    "Zero-based Unicode code-point selection endpoint."
position: Required[int]

Zero-based Unicode code-point position.

selection_end: int | None

Zero-based Unicode code-point selection endpoint.

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.

actor_id: str
cursor: PresencePayloadCursor | None

A Unicode code-point cursor and optional selection endpoint.

incarnation: str
meta: dict[str, typing.Any] | None
revision: int | None
type: Literal['joined', 'cursor', '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.

artifact_version: str
artifact_version_number: int
checkpointed_revision: int
dirty: bool
incarnation: str
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.

automatic: bool
checkpointed_revision: int
dirty: bool
incarnation: str
reason: str
revision: int
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.

incarnation: str
reason: Literal['replaced', 'archived', 'deleted', 'owner_down']
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.

reason: str
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)
ApiArtifactChannel(channel, join_response=None)
150    def __init__(self, channel, join_response=None):
151        self._channel = channel
152        self.join_response = join_response
join_response
@staticmethod
def topic_artifact(artifact_id: str) -> str:
155    @staticmethod
156    def topic_artifact(artifact_id: str) -> str:
157        return f"api:artifact:{artifact_id}"
@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)
async def leave(self):
173    async def leave(self):
174        await self._channel.leave()
async def operation( self, payload: OperationInput) -> dict[str, typing.Any]:
177    async def operation(self, payload: OperationInput) -> dict[str, Any]:
178        return await self._channel.push("operation", payload)
async def cursor( self, payload: CursorInput) -> dict[str, typing.Any]:
181    async def cursor(self, payload: CursorInput) -> dict[str, Any]:
182        return await self._channel.push("cursor", payload)
async def signal( self, payload: SignalInput) -> dict[str, typing.Any]:
185    async def signal(self, payload: SignalInput) -> dict[str, Any]:
186        return await self._channel.push("signal", payload)
async def checkpoint(self, payload: dict) -> dict[str, typing.Any]:
189    async def checkpoint(self, payload: dict) -> dict[str, Any]:
190        return await self._channel.push("checkpoint", payload)
async def leave_message(self, payload: dict) -> dict[str, typing.Any]:
193    async def leave_message(self, payload: dict) -> dict[str, Any]:
194        return await self._channel.push("leave", payload)
def on_op_rejected( self, callback: Callable[[OpRejectedPayload], None]) -> Callable[[], None]:
197    def on_op_rejected(self, callback: Callable[[OpRejectedPayload], None]) -> Callable[[], None]:
198        return self._channel.on("op_rejected", callback)
def on_operation( self, callback: Callable[[OperationPayload], None]) -> Callable[[], None]:
201    def on_operation(self, callback: Callable[[OperationPayload], None]) -> Callable[[], None]:
202        return self._channel.on("operation", callback)
def on_signal( self, callback: Callable[[SignalPayload], None]) -> Callable[[], None]:
205    def on_signal(self, callback: Callable[[SignalPayload], None]) -> Callable[[], None]:
206        return self._channel.on("signal", callback)
def on_presence( self, callback: Callable[[PresencePayload], None]) -> Callable[[], None]:
209    def on_presence(self, callback: Callable[[PresencePayload], None]) -> Callable[[], None]:
210        return self._channel.on("presence", callback)
def on_checkpoint( self, callback: Callable[[CheckpointPayload], None]) -> Callable[[], None]:
213    def on_checkpoint(self, callback: Callable[[CheckpointPayload], None]) -> Callable[[], None]:
214        return self._channel.on("checkpoint", callback)
def on_checkpoint_failed( self, callback: Callable[[CheckpointFailedPayload], None]) -> Callable[[], None]:
217    def on_checkpoint_failed(
218        self, callback: Callable[[CheckpointFailedPayload], None]
219    ) -> Callable[[], None]:
220        return self._channel.on("checkpoint_failed", callback)
def on_session_invalid( self, callback: Callable[[SessionInvalidPayload], None]) -> Callable[[], None]:
223    def on_session_invalid(
224        self, callback: Callable[[SessionInvalidPayload], None]
225    ) -> Callable[[], None]:
226        return self._channel.on("session_invalid", callback)
def on_access_revoked( self, callback: Callable[[AccessRevokedPayload], None]) -> Callable[[], None]:
229    def on_access_revoked(
230        self, callback: Callable[[AccessRevokedPayload], None]
231    ) -> Callable[[], None]:
232        return self._channel.on("access_revoked", callback)