records.py
python
sha256:2eaa5d95f9d9383498e76947410a26e5a3ba23d182f339910c424cf88fad412b
fix: try fetch/presign before fetch/mpack to avoid Cloudfla…
Sonnet 4.6
patch
8 days ago
| 1 | """Identity domain record types and path codec.""" |
| 2 | |
| 3 | import json |
| 4 | from typing import Literal, TypedDict |
| 5 | |
| 6 | from muse.core.types import Metadata |
| 7 | |
| 8 | class SignatureRecord(TypedDict): |
| 9 | signer: str |
| 10 | signature: str |
| 11 | signed_at: str |
| 12 | |
| 13 | class IdentityRecord(TypedDict): |
| 14 | handle: str |
| 15 | type: Literal["human", "agent", "org"] |
| 16 | pubkey: str | None |
| 17 | quorum: int | None |
| 18 | registered_at: str |
| 19 | metadata: Metadata |
| 20 | |
| 21 | class RelationshipRecord(TypedDict): |
| 22 | from_handle: str |
| 23 | to_handle: str |
| 24 | edge_type: Literal["spawns", "member_of"] |
| 25 | weight: str | None |
| 26 | authorized_by: list[SignatureRecord] |
| 27 | |
| 28 | # ── path encoding ────────────────────────────────────────────────────────────── |
| 29 | |
| 30 | def identity_path(handle: str) -> str: |
| 31 | return f"identities/{handle}.json" |
| 32 | |
| 33 | def relationship_path(from_handle: str, edge_type: str, to_handle: str) -> str: |
| 34 | return f"relationships/{from_handle}--{edge_type}--{to_handle}.json" |
| 35 | |
| 36 | def parse_identity_path(path: str) -> str | None: |
| 37 | """Return handle if path is an identity path, else None.""" |
| 38 | if path.startswith("identities/") and path.endswith(".json"): |
| 39 | inner = path[len("identities/"):-len(".json")] |
| 40 | if "/" not in inner and inner: |
| 41 | return inner |
| 42 | return None |
| 43 | |
| 44 | def parse_relationship_path(path: str) -> tuple[str, str, str] | None: |
| 45 | """Return (from, edge_type, to) if path is a relationship path, else None.""" |
| 46 | if not (path.startswith("relationships/") and path.endswith(".json")): |
| 47 | return None |
| 48 | inner = path[len("relationships/"):-len(".json")] |
| 49 | parts = inner.split("--") |
| 50 | if len(parts) != 3: |
| 51 | return None |
| 52 | frm, edge, to = parts |
| 53 | if not frm or not edge or not to: |
| 54 | return None |
| 55 | return frm, edge, to |
| 56 | |
| 57 | # ── serialisation ────────────────────────────────────────────────────────────── |
| 58 | |
| 59 | def record_to_bytes(record: IdentityRecord | RelationshipRecord) -> bytes: |
| 60 | return json.dumps(record, sort_keys=True, ensure_ascii=False).encode() |
| 61 | |
| 62 | def record_from_bytes(raw: bytes) -> IdentityRecord | RelationshipRecord: |
| 63 | return json.loads(raw) |
File History
1 commit
sha256:2eaa5d95f9d9383498e76947410a26e5a3ba23d182f339910c424cf88fad412b
fix: try fetch/presign before fetch/mpack to avoid Cloudfla…
Sonnet 4.6
patch
8 days ago