fix(quartz): accept legacy nostrnests tag names on kind-30312 read

The first-party nostrnests web client (NestsUI-v2) emits kind-30312
events using NIP-53 *streaming-event* tag names rather than the
kind-30312 names defined by NIP-53 itself. Confirmed against
`nostrnests/nests/NestsUI-v2/src/components/EditRoomDialog.tsx` and
`useRoomList.ts`:

  - room name: `title`     (NIP-53 spec for 30312: `room`)
  - MoQ relay: `streaming` (NIP-53 spec for 30312: `endpoint`)
  - moq-auth:  `auth`      (NIP-53 spec for 30312: `service`)
  - status:    `live`      (NIP-53 spec for 30312: `open` / `private`
                            / `closed` / `planned`)

Our parsers followed the NIP-53 spec, so events from the production
nostrnests web app fell through to status=null, which `checkStatus`
then surfaced as "Ended" in the live-rooms UI. Add legacy-alias
acceptance to all four parsers — read-side only; we still emit the
canonical NIP-53 forms, matching EGG-01.

Per-tag changes:
  StatusTag:      "live" → OPEN, "ended" → CLOSED
  RoomNameTag:    "title" alias → room
  EndpointUrlTag: "streaming" alias → endpoint
  ServiceUrlTag:  "auth" alias → service

No emit-side changes; no spec change.

https://claude.ai/code/session_01RDpuki4t8StSg1CZcXnV5b
This commit is contained in:
Claude
2026-04-27 14:12:23 +00:00
parent eae28ab943
commit addb2a4abb
4 changed files with 39 additions and 3 deletions
@@ -27,9 +27,17 @@ class EndpointUrlTag {
companion object Companion {
const val TAG_NAME = "endpoint"
/**
* Legacy alias used by first-generation nostrnests web clients,
* which reused the NIP-53 streaming-event tag name for the
* kind-30312 MoQ relay URL. Accepted on read; we always emit
* the canonical [TAG_NAME].
*/
const val LEGACY_TAG_NAME = "streaming"
fun parse(tag: Array<String>): String? {
ensure(tag.has(1)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
ensure(tag[0] == TAG_NAME || tag[0] == LEGACY_TAG_NAME) { return null }
ensure(tag[1].isNotEmpty()) { return null }
return tag[1]
}
@@ -27,9 +27,17 @@ class RoomNameTag {
companion object Companion {
const val TAG_NAME = "room"
/**
* Legacy alias used by first-generation nostrnests web clients,
* which reused the NIP-53 streaming-event `title` tag for the
* kind-30312 room name. Accepted on read; we always emit the
* canonical [TAG_NAME].
*/
const val LEGACY_TAG_NAME = "title"
fun parse(tag: Array<String>): String? {
ensure(tag.has(1)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
ensure(tag[0] == TAG_NAME || tag[0] == LEGACY_TAG_NAME) { return null }
ensure(tag[1].isNotEmpty()) { return null }
return tag[1]
}
@@ -27,9 +27,16 @@ class ServiceUrlTag {
companion object Companion {
const val TAG_NAME = "service"
/**
* Legacy alias used by first-generation nostrnests web clients
* for the moq-auth sidecar URL. Accepted on read; we always emit
* the canonical [TAG_NAME].
*/
const val LEGACY_TAG_NAME = "auth"
fun parse(tag: Array<String>): String? {
ensure(tag.has(1)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
ensure(tag[0] == TAG_NAME || tag[0] == LEGACY_TAG_NAME) { return null }
ensure(tag[1].isNotEmpty()) { return null }
return tag[1]
}
@@ -40,9 +40,22 @@ class StatusTag {
fun parse(code: String): STATUS? =
when (code) {
PLANNED.code -> PLANNED
OPEN.code -> OPEN
PRIVATE.code -> PRIVATE
CLOSED.code -> CLOSED
// Legacy aliases used by first-generation nostrnests
// web clients that reused NIP-53 streaming-event
// status values for kind-30312 meeting spaces.
// Accept on read to preserve interop; we always emit
// the canonical EGG-01 codes.
"live" -> OPEN
"ended" -> CLOSED
else -> null
}
}