add Nostr publishing and bidirectional sync

- nostr/ vendors NostrEvent + the nostrclient WebSocket bridge from
  the events extension, retagged [TASKS] / subscription-id "tasks-*".
- nostr_publisher builds kind 31922 with the `event-type: task` tag
  (per aiolabs/webapp#25 — disambiguates from kind-31922 activities on
  shared relays), kind 31925 with task-status / occurrence /
  completed_at, and kind 5 deletions for both.
- nostr_hooks bridges task/completion mutations to the publisher and
  persists the resulting nostr_event_id back onto the local row.
- nostr_sync subscribes to {31922, 31925, 5/#k} and filters 31922
  client-side on `event-type: task` because most relays don't index
  custom single-letter tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-13 11:38:42 +02:00
commit 24acbe6674
6 changed files with 755 additions and 0 deletions

26
nostr/event.py Normal file
View file

@ -0,0 +1,26 @@
import hashlib
import json
from pydantic import BaseModel
class NostrEvent(BaseModel):
id: str = ""
pubkey: str
created_at: int
kind: int
tags: list[list[str]] = []
content: str = ""
sig: str | None = None
def serialize(self) -> list:
return [0, self.pubkey, self.created_at, self.kind, self.tags, self.content]
def serialize_json(self) -> str:
e = self.serialize()
return json.dumps(e, separators=(",", ":"), ensure_ascii=False)
@property
def event_id(self) -> str:
data = self.serialize_json()
return hashlib.sha256(data.encode()).hexdigest()