Chat surface package (packages/chat/) with conversation list, message thread, compose bar, participant sidebar, create conversation dialog, typing indicators, read receipts, message editing, and message deletion. Built on chat-core library with realtime event subscriptions. Fix stale token login deadlock: REST client auth endpoints excluded from 401 retry loop, 8s defensive boot timeout on auth.boot(). Fix bundled package permissions: auto-grant with NULL granted_by and set status active on install. Switch docker-compose to named volume for remote Docker host compat. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
40 lines
1.1 KiB
Plaintext
40 lines
1.1 KiB
Plaintext
# Chat Surface — Starlark Backend (v0.1.0)
|
|
#
|
|
# Thin surface layer on top of chat-core library.
|
|
# Only handles typing indicator broadcast — all CRUD is
|
|
# delegated to chat-core's own API routes.
|
|
#
|
|
# Modules: json, realtime
|
|
|
|
def _resp(status, data):
|
|
return {"status": status, "body": json.encode(data), "headers": {"Content-Type": "application/json"}}
|
|
|
|
|
|
def on_request(req):
|
|
path = req["path"]
|
|
method = req["method"]
|
|
user_id = req.get("user_id", "")
|
|
|
|
# POST /typing/:conversation_id — broadcast typing indicator
|
|
if method == "POST" and path.startswith("/typing/"):
|
|
cid = path[len("/typing/"):]
|
|
if not cid:
|
|
return _resp(400, {"error": "conversation_id required"})
|
|
|
|
body = json.decode(req.get("body", "{}"))
|
|
display_name = str(body.get("display_name", ""))
|
|
|
|
realtime.publish(
|
|
"conversation:" + cid,
|
|
"typing",
|
|
{
|
|
"participant_id": user_id,
|
|
"display_name": display_name,
|
|
"conversation_id": cid,
|
|
},
|
|
)
|
|
|
|
return _resp(200, {"ok": True})
|
|
|
|
return _resp(404, {"error": "not found"})
|