fix(market): resolve stall_id from a-tag when content omits it
NIP-15 lists stall_id inside the JSON content of kind-30018 product
events, but some publishers (older nostrmarket builds, third-party
clients) omit the field and only emit the parent reference via the
a-tag of the form ["a", "30017:<merchantPubkey>:<stallId>"].
Adds resolveStallId(event, productData) which:
1. Reads productData.stall_id when present (the spec-canonical path)
2. Falls back to the a-tag prefixed "30017:" when content omits it
3. Returns 'unknown' as a sentinel that won't match any real stall
Both code paths in useMarket.ts (loadProducts batch and
handleProductEvent live-update) now use it. Combined with the
addStall sweep from eb3393f, products eventually link to their
parent stall regardless of order or which form the publisher used.
This DOES NOT fix orphan products whose referenced stall genuinely
isn't on the relay — those still render "Unknown Stall" because no
stall exists to link to. Investigating that separately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
181698c057
commit
628c13c644
1 changed files with 28 additions and 2 deletions
|
|
@ -14,6 +14,32 @@ const MARKET_EVENT_KINDS = {
|
|||
PRODUCT: 30018
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Resolve a product's parent stall id from the event.
|
||||
*
|
||||
* NIP-15 lists `stall_id` inside the JSON `content`, but some publishers
|
||||
* (older nostrmarket builds, third-party clients) only emit the parent
|
||||
* reference via an `a` tag of the form
|
||||
* ["a", "30017:<merchantPubkey>:<stallId>"]
|
||||
*
|
||||
* Read content first, then fall back to the tag, then a sentinel that won't
|
||||
* match any real stall. Returning the tag form prevents "Unknown Stall"
|
||||
* from sticking when the JSON omits the field.
|
||||
*/
|
||||
function resolveStallId(event: any, productData: any): string {
|
||||
if (productData?.stall_id && typeof productData.stall_id === 'string') {
|
||||
return productData.stall_id
|
||||
}
|
||||
const aTag = event.tags?.find(
|
||||
(t: any) => Array.isArray(t) && t[0] === 'a' && typeof t[1] === 'string' && t[1].startsWith(`${MARKET_EVENT_KINDS.STALL}:`)
|
||||
)
|
||||
if (aTag) {
|
||||
const parts = aTag[1].split(':')
|
||||
if (parts[2]) return parts[2]
|
||||
}
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
export function useMarket() {
|
||||
const marketStore = useMarketStore()
|
||||
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB) as any
|
||||
|
|
@ -315,7 +341,7 @@ export function useMarket() {
|
|||
|
||||
try {
|
||||
const productData = JSON.parse(latestEvent.content)
|
||||
const stallId = productData.stall_id || 'unknown'
|
||||
const stallId = resolveStallId(latestEvent, productData)
|
||||
|
||||
// Extract categories from Nostr event tags (standard approach)
|
||||
const categories = latestEvent.tags
|
||||
|
|
@ -515,7 +541,7 @@ export function useMarket() {
|
|||
const productId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
|
||||
if (productId) {
|
||||
const productData = JSON.parse(event.content)
|
||||
const stallId = productData.stall_id || 'unknown'
|
||||
const stallId = resolveStallId(event, productData)
|
||||
|
||||
// Extract categories from Nostr event tags (standard approach)
|
||||
const categories = event.tags
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue