Commit graph

3 commits

Author SHA1 Message Date
b6ca1b0e02 feat: NIP-17 gift-wrapped check-in DM on confirmation (#5)
On settlement, send the guest their private check-in details as a NIP-59
gift-wrapped DM (nostr/giftwrap.py, built from lnbits core primitives — no
vendored crypto):

- rumor (kind 14) -> seal (kind 13, operator-encrypted + operator-signed via
  the signer abstraction) -> gift wrap (kind 1059, ephemeral-key encrypted +
  signed locally via core nip44_encrypt + sign_event). created_at randomised
  into the past per NIP-59.
- service.send_checkin_dm builds the message (room.checkin_instructions +
  settings times/policy) and publishes via nostrclient (_publish_signed,
  extracted from _sign_and_publish).
- tasks.on_invoice_paid calls it best-effort — a DM failure never undoes a
  confirmed, paid booking.

Encrypted layer (seal) soft-fails on a LocalSigner until bunker/server-
signing (lnbits#18), same as the reservation event; the ephemeral wrap layer
always works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 20:34:12 +02:00
cf9f8699da feat: relay publish + availability subscription via nostrclient (#2)
Wire the Nostr layer through the nostrclient extension's relay manager
in-process (spirekeeper pattern), replacing the sketch stubs:

- _sign_and_publish: sign as operator (resolve_signer), optional NIP-44
  encrypt, publish via nostr_client.relay_manager.publish_message. Soft-
  fails (logs, returns None) if no operator onboarded, nostrclient absent,
  or signer can't encrypt — never crashes the booking flow.
- publish_listing (30402) + publish_block_calendar (31923): public, work
  today (sign_event only).
- publish_reservation (30078): NIP-44 encrypted to guest; soft-fails on a
  LocalSigner until a bunker/server-signing signer lands (lnbits#18).
- subscribe_inbound: permanent task answering kind:22000 availability
  queries with kind:22001 (plaintext — availability is public info), the
  client-agnostic availability path parallel to the RPC.

events.py: drop the _plaintext scaffolding (service.py encrypts content in
place) and a broken {operator_pubkey} calendar tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 18:09:35 +02:00
900b682986 feat: nostr event layer (builders + sign/publish service)
Implements ADR-0001. kinds.py pins the allocations; events.py has pure
builders (30402 listing, 30078 encrypted reservation, 31923 blocked-range
calendar, 22001 availability response); service.py signs/encrypts via
resolve_signer (spirekeeper hybrid pattern — no nsec at rest) and sketches
publish + inbound subscription. Relay plumbing marked TODO(relay).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 00:16:39 +02:00