Auto-create + publish default stall, republish stall on product publish
Two complementary fixes for the "Unknown Stall" bug, where a customer sees a product on the relay but the parent stall is missing. 1. _auto_create_merchant() now creates a default "<username>'s Store" stall and publishes its kind 30017 event before returning. New users land with a fully-published merchant identity, so the very first product they create has a known parent stall on relays. 2. POST /api/v1/product (api_create_product) now republishes the parent stall before publishing the product. NIP-33 parameterized replaceable events make this idempotent, but it self-heals every existing case where the stall publish failed or never happened (transient relay issues, accounts that pre-date the auto-publish flow, manual stall creation that didn't reach all relays). This complements the LNbits-side fix in core/services/users.py (_create_default_merchant publishes the stall on signup) and the webapp self-heal in useMarketStallSelfHeal.ts. With all three layers, "Unknown Stall" should disappear from the customer view. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3cc798aab2
commit
e481c9179d
1 changed files with 49 additions and 9 deletions
48
views_api.py
48
views_api.py
|
|
@ -101,6 +101,10 @@ async def _auto_create_merchant(
|
|||
"""
|
||||
Provision a merchant record from the user's account keypair.
|
||||
Called automatically on first GET or explicitly via POST.
|
||||
|
||||
Also creates a default "Online" shipping zone and a default stall named
|
||||
after the user, then publishes the stall to relays so that any product
|
||||
the user creates references a stall the customer-facing client can find.
|
||||
"""
|
||||
account = await get_account(wallet.wallet.user)
|
||||
assert account, "User account not found"
|
||||
|
|
@ -127,15 +131,36 @@ async def _auto_create_merchant(
|
|||
|
||||
merchant = await create_merchant(wallet.wallet.user, partial_merchant)
|
||||
|
||||
await create_zone(
|
||||
merchant.id,
|
||||
Zone(
|
||||
online_zone = Zone(
|
||||
id=f"online-{merchant.public_key}",
|
||||
name="Online",
|
||||
currency="sat",
|
||||
cost=0,
|
||||
countries=["Free (digital)"],
|
||||
),
|
||||
)
|
||||
await create_zone(merchant.id, online_zone)
|
||||
|
||||
# Create + publish a default stall so products created through the UI
|
||||
# always have a published parent. Without this, a product publish lands
|
||||
# on relays referencing a stall_id that no relay has seen, and the
|
||||
# customer client renders "Unknown Stall".
|
||||
display_name = account.username or "My"
|
||||
default_stall = Stall(
|
||||
wallet=wallet.wallet.id,
|
||||
name=f"{display_name}'s Store",
|
||||
currency="sat",
|
||||
shipping_zones=[online_zone],
|
||||
)
|
||||
default_stall = await create_stall(merchant.id, default_stall)
|
||||
try:
|
||||
stall_event = await sign_and_send_to_nostr(merchant, default_stall)
|
||||
default_stall.event_id = stall_event.id
|
||||
await update_stall(merchant.id, default_stall)
|
||||
except Exception as ex:
|
||||
# Non-fatal: merchant is usable; a product publish (or self-heal)
|
||||
# will republish the stall later.
|
||||
logger.warning(
|
||||
f"[NOSTRMARKET] Failed to publish default stall for {merchant.id}: {ex}"
|
||||
)
|
||||
|
||||
await resubscribe_to_all_merchants()
|
||||
|
|
@ -767,6 +792,21 @@ async def api_create_product(
|
|||
assert stall, "Stall missing for product"
|
||||
data.config.currency = stall.currency
|
||||
|
||||
# Re-publish the parent stall before publishing the product. NIP-33
|
||||
# parameterized replaceable events make this idempotent on relays.
|
||||
# This guarantees the customer client never sees a product whose
|
||||
# parent stall isn't on the relay (e.g., when the original stall
|
||||
# publish failed transiently or never ran).
|
||||
try:
|
||||
stall_event = await sign_and_send_to_nostr(merchant, stall)
|
||||
stall.event_id = stall_event.id
|
||||
await update_stall(merchant.id, stall)
|
||||
except Exception as ex:
|
||||
logger.warning(
|
||||
f"[NOSTRMARKET] Failed to refresh stall {stall.id} "
|
||||
f"before product publish: {ex}"
|
||||
)
|
||||
|
||||
product = await create_product(merchant.id, data=data)
|
||||
|
||||
event = await sign_and_send_to_nostr(merchant, product)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue