60edd473c7
- Updates CLAUDE.md tech stack to current versions (Compose 1.10.3, Kotlin 2.3.20). - Reframes kotlin-multiplatform iOS as mature; adds secp256k1-kmp 0.23.0 references. - Updates desktop-expert Main.kt references (code grew from ~270 to 1341 lines and NavigationRail moved to ui/deck/SinglePaneLayout.kt); replaces obsolete "hardcoded ctrl = true" anti-pattern note with accurate isMacOS branching. - Removes compose-desktop.md (superseded by desktop-expert/). - Adds nostr-expert references: nip19-bech32, event-factory, crypto-and-encryption, large-cache. Adds kotlin-expert/common-utilities, compose-expert/rich-text-parsing, android-expert/image-loading. - New skills: account-state (Account + LocalCache), relay-client (subscriptions, filter assemblers, preloaders), feed-patterns (FeedFilter + FeedViewModel family), auth-signers (NostrSigner across internal / NIP-46 / NIP-55).
69 lines
3.4 KiB
Markdown
69 lines
3.4 KiB
Markdown
# EventFactory: Parsing JSON into Typed Events
|
|
|
|
`quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt` is the single dispatch point that turns a parsed `(id, pubKey, createdAt, kind, tags, content, sig)` tuple into the correct `Event` subclass.
|
|
|
|
## What It Does
|
|
|
|
EventFactory is a giant `when` over `kind` that maps integer kind values to concrete event classes. If a kind isn't recognized, it falls back to the generic base `Event` (so unknown kinds still round-trip). Every NIP that defines a new kind registers its class here.
|
|
|
|
Typical shape:
|
|
|
|
```kotlin
|
|
object EventFactory {
|
|
fun create(
|
|
id: HexKey,
|
|
pubKey: HexKey,
|
|
createdAt: Long,
|
|
kind: Int,
|
|
tags: TagArray,
|
|
content: String,
|
|
sig: HexKey,
|
|
): Event = when (kind) {
|
|
MetadataEvent.KIND -> MetadataEvent(id, pubKey, createdAt, tags, content, sig)
|
|
TextNoteEvent.KIND -> TextNoteEvent(id, pubKey, createdAt, tags, content, sig)
|
|
ContactListEvent.KIND -> ContactListEvent(id, pubKey, createdAt, tags, content, sig)
|
|
ReactionEvent.KIND -> ReactionEvent(id, pubKey, createdAt, tags, content, sig)
|
|
// …hundreds more…
|
|
else -> Event(id, pubKey, createdAt, kind, tags, content, sig)
|
|
}
|
|
}
|
|
```
|
|
|
|
Callers are normally upstream of this: `Event.fromJson(...)` / `EventMapper.fromJson(...)` / the relay client's message parser. You rarely call EventFactory directly — you consume typed events it produces.
|
|
|
|
## Registering a New Event Kind
|
|
|
|
Adding a NIP is roughly:
|
|
|
|
1. Create the event class under `quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipXX…/` alongside the NIP package.
|
|
2. Subclass the right base:
|
|
- `Event` — regular events (stored forever).
|
|
- `BaseReplaceableEvent` — kinds `10000-19999`, `0`, `3`.
|
|
- `BaseAddressableEvent` — kinds `30000-39999` (identified by `kind:pubkey:d-tag`).
|
|
- Ephemeral events extend `Event` but have kind `20000-29999`.
|
|
3. Define `companion object { const val KIND = <n> }`.
|
|
4. If the event has tag builders, define a `TagArrayBuilder<YourEvent>` DSL in a `TagArrayBuilder` extension — see `nostr-expert/references/tag-patterns.md`.
|
|
5. Add a branch to `EventFactory.create(...)` so JSON parsing produces your typed class.
|
|
6. If the event is addressable, ensure it exposes a stable `dTag()` and `address()`.
|
|
7. Add tests under `quartz/src/commonTest/...`.
|
|
|
|
## Why a Monolithic when?
|
|
|
|
- **Zero overhead**: compiled to a dense lookup. No reflection, no registry map.
|
|
- **Exhaustive browsing**: every known kind lives at one search location. `grep KIND = 1234 quartz/...` finds everything.
|
|
- **Obvious migration path**: adding a kind means adding a case; removing a kind is a grep-and-delete.
|
|
|
|
The tradeoff is the file is large and every new kind edits the same file — expect merge conflicts in PRs that touch it, and resolve by keeping both branches.
|
|
|
|
## Supporting Utilities
|
|
|
|
- `EventAssembler.kt` (crypto/) — higher-level helper that takes a signer and a `kind + tags + content` and produces a fully signed event (id + sig populated).
|
|
- `EventTemplate.kt` (signers/) — unsigned-event holder, useful in signer flows.
|
|
- `Event.fromJson(...)` / `Event.toJson()` — JSON round-trip using `OptimizedJsonMapper` (Jackson on jvmAndroid).
|
|
|
|
## Related References
|
|
|
|
- `event-hierarchy.md` — class hierarchy, Kind ranges
|
|
- `nip-catalog.md` — which kind maps to which NIP
|
|
- `tag-patterns.md` — `TagArrayBuilder` DSL for writing tags cleanly
|