Quartz now lives in github.com/vitorpamplona/quartz, split into quartz-core, quartz-social, quartz-relay-client and the other quartz-* libraries, with history kept. Amethyst depends on the `quartz` umbrella artifact at a released version (1.20.0) instead of the :quartz project. - Remove the quartz/ module, jitpack.yml and the Quartz CI, release and pre-push steps; tools/unicode-nfkc moved with it. - Point every module at libs.quartz. - Move the device-test fixtures the benchmark and relayBench still read to testdata/. - NostrConnectLoginUseCase parses bunker messages with BunkerJson, which now owns NIP-46 JSON. - Repoint docs and skills at the Quartz repository; the nostr-expert scripts read a Quartz checkout (QUARTZ_REPO, default ../quartz). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014ZR5ZBfhFzRiXubJc5Evyv
3.0 KiB
EventFactory and registering a new kind
EventFactory
(in quartz-core) 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.
It is a registry, not a when: every Quartz artifact ships an EventKindProvider
(SocialEventKinds, PaymentEventKinds, MarmotEventKinds, ...) that registers its
classes, and EventFactory loads the providers of the artifacts on the classpath
(by class name on JVM/Android, at binary load on native). Amethyst depends on the quartz
umbrella, so every kind is registered here.
object SocialEventKinds : EventKindProvider {
override fun registerKinds(registry: EventKindRegistry) {
registry.register(TextNoteEvent.KIND, ::TextNoteEvent)
…
}
}
EventFactory.create<T>(id, pubKey, createdAt, kind, tags, content, sig)
EventFactory.isKnownKind(kind) // typed class exists?
EventFactory.probe(kind) // a tagless instance, used by the stores' searchable checks
EventFactory.factories[kind] = EventBuilder { … } // app-side runtime registrations
Kinds that unrelated apps share pick their class from tags: the kind's home module
registers a default class (often an UnrecognizedKind…Event), each app's class adds a
registry.variant(kind, priority, matches = …), and registry.probeAs(kind, …) names the
class probe answers with (kinds 38000, 30301, 30302, 38384-38386, 31986, 39005, 20001).
Unknown kinds round-trip as plain Event.
Adding a kind
Steps 1 and 2 happen in the Quartz repository, and
Amethyst picks them up when it bumps quartz in gradle/libs.versions.toml.
- The class, in its
nipXX…/package (orexperimental/…) in the right Quartz module: subclassEvent,BaseReplaceableEventorBaseAddressableEvent(seeevent-hierarchy.md), addcompanion object { const val KIND = n; fun build(...) }, tag codecs and builder extensions (seetag-patterns.md). - The module's
EventKindProvider:registry.register(MyEvent.KIND, ::MyEvent), or the kind parses as plainEvent. LocalCachedispatch (here, in Amethyst):justConsumeInnerInnerincommons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/EventCache.kt(LocalCacheisobject LocalCache : EventCache()). Without a branch the event hits theelseand is dropped with only aLog.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 and override indexableFields() (see the
event-store-semantics skill), add it to the subscription filter that should fetch it, and
add a test beside the class in Quartz. Regenerate nip-catalog.md with scripts/nip-catalog.py.