Files
amethyst/.claude/skills/nostr-expert/references/event-factory.md
Vitor PamplonaandClaude Opus 5.5 395af4dc9c chore(skills): consolidate 33 skills into 14, verified against the tree
The 33 descriptions (~16k chars, ~19k with paths) overran Codex's skill-list
budget (2% of the context window, or 8,000 chars when unknown), and a review
found most bodies stale: paths from before the commons/commonsUI moves, the
deleted legacy desktop app, a callback signer API that no longer exists, and
example APIs that were never in the tree.

Kept, rewritten and checked against the code (every path, class and command):
account-state (+feeds), amy-expert, android-expert, auth-signers,
compose-expert (+API style, Navigation 3 back stacks), desktop-expert
(+run/package), event-store-semantics (+NIP-50 search), find-missing-
translations, kotlin-coroutines (+structured concurrency, flow modeling),
kotlin-multiplatform (+Gradle, composable extraction), ngit-pr,
nip85-trusted-assertions, nostr-expert (+NIP lookup, generated NIP catalog),
relay-client.

Dropped: textbook Compose/Kotlin technique skills, kotlin-expert,
kotlin-types-value-class, gradle-expert, quartz-integration (external-facing;
see the Quartz docs commit), find-non-lambda-logs (audit finished; the rule is
now in AGENTS.md Kotlin Style), and the /nip, /desktop-run, /extract commands.
The skill list is now ~4k chars. Also drops .claude/core-skills-plan.md
(stale history) and repoints SearchableEvent's KDoc to event-store-semantics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:21:01 -04:00

2.4 KiB

EventFactory and registering a new kind

quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt turns a parsed (id, pubKey, createdAt, kind, tags, content, sig) into the typed Event subclass. Callers normally reach it through Event.fromJson(...) or the relay message parser.

Shape (verbatim structure):

class EventFactory {
    companion object {
        val factories: MutableMap<Int, EventBuilder> = mutableMapOf()   // runtime registrations

        fun <T : Event> create(id, pubKey, createdAt, kind, tags, content, sig): T =
            when (kind) {
                AcceptedBadgeSetEvent.KIND -> AcceptedBadgeSetEvent(id, pubKey, createdAt, tags, content, sig)
                …
                else -> factories[kind]?.build(id, pubKey, createdAt, tags, content, sig)
                    ?: Event(id, pubKey, createdAt, kind, tags, content, sig)
            }

        fun isKnownKind(kind: Int): Boolean   // typed class exists?
        fun probe(kind: Int): Event           // a tagless instance, used by the stores' searchable checks
    }
}

Some kinds pick their class from tags (kinds 38000 and 30301 have nested whens that fall back to UnrecognizedKind…Event). Unknown kinds round-trip as plain Event.

Adding a kind — three registrations

  1. The class, in its nipXX…/ package (or experimental/…): subclass Event, BaseReplaceableEvent or BaseAddressableEvent (see event-hierarchy.md), add companion object { const val KIND = n; fun build(...) }, tag codecs and builder extensions (see tag-patterns.md).
  2. EventFactory.create — a branch, or the kind parses as plain Event.
  3. LocalCache dispatch — justConsumeInnerInner in commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/EventCache.kt (LocalCache is object LocalCache : EventCache()). Without a branch the event hits the else and is dropped with only a Log.w("Event Not Supported") — including the account's own freshly signed copy. Add it next to a sibling of the same shape.

Then, if relevant: make it SearchableEvent (see the event-store-semantics skill), add it to the subscription filter that should fetch it, and add a test in quartz/src/commonTest/.... Regenerate nip-catalog.md with scripts/nip-catalog.py.

EventFactory.kt is one large file every new kind edits — expect merge conflicts and keep both sides.