diff --git a/ai/mcp-server/CHATGPT_SUBMISSION.md b/ai/mcp-server/CHATGPT_SUBMISSION.md index 9eebe93f..ca8c99db 100644 --- a/ai/mcp-server/CHATGPT_SUBMISSION.md +++ b/ai/mcp-server/CHATGPT_SUBMISSION.md @@ -70,7 +70,7 @@ Use these in ChatGPT developer mode on web and mobile before submitting: Expected: calls `hostr_listings_availability`; preserves date-only values as `2026-08-01T00:00:00Z` style values when dates are in 2026. 3. `Book this instant-book stay for two nights` - Expected: asks for missing listing/date/price details if needed; calls `hostr_reservations_bookAndPay` only after intent is concrete; if payment is required, shows only the QR/invoice to the user and then calls `hostr_swaps_watch`. + Expected: asks for missing listing/date/price details if needed; calls `hostr_orders_bookAndPay` only after intent is concrete; if payment is required, shows only the QR/invoice to the user and then calls `hostr_swaps_watch`. 4. `Create a listing for my spare room` Expected: asks for missing required fields; uploads images through `hostr_images_upload`; previews with `hostr_listings_create` and `dryRun: true`; does not publish until explicit approval. diff --git a/ai/mcp-server/README.md b/ai/mcp-server/README.md index 1549a5e8..c506ecfb 100644 --- a/ai/mcp-server/README.md +++ b/ai/mcp-server/README.md @@ -160,11 +160,11 @@ hostr_listings_edit hostr_listings_availability hostr_listings_reviews hostr_listings_reservationGroups -hostr_reservations_negotiateOffer -hostr_reservations_negotiateAccept -hostr_reservations_pay -hostr_reservations_commit -hostr_reservations_cancel +hostr_orders_negotiateOffer +hostr_orders_negotiateAccept +hostr_orders_pay +hostr_orders_commit +hostr_orders_cancel hostr_updates hostr_thread_view hostr_thread_message @@ -261,9 +261,9 @@ Agents should use the workflow docs from `hostr://mcp/action-input-types`, but t - New listing: call `hostr_profile_edit` if profile details need updating, then `hostr_listings_create` with `dryRun: true`, show the preview, and repeat with `dryRun: false` only after approval. The live listing path ensures seller config is published. - Edit listing: call `hostr_listings_edit` with `dryRun: true`, review the returned listing/event preview, then repeat with `dryRun: false`. -- Search and reserve: call `hostr_listings_search`, then `hostr_listings_availability`, then `hostr_reservations_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM. -- Negotiation: call `hostr_updates` to inspect thread/trade ids. Use `hostr_reservations_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_reservations_negotiateAccept` to accept the latest offer, or `hostr_reservations_cancel` to cancel the private negotiation or committed reservation. -- Payment: for normal instant-book payment, call `hostr_reservations_bookAndPay`. After showing the returned QR/invoice, call the read-only `hostr_swaps_watch` with `swapId`, `tradeId`, and `reservationWaitSeconds`; it has no `dryRun` parameter and does not require approval. Use `hostr_swaps_recoverAll` only for explicit manual recovery/debug flows. +- Search and reserve: call `hostr_listings_search`, then `hostr_listings_availability`, then `hostr_orders_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM. +- Negotiation: call `hostr_updates` to inspect thread/trade ids. Use `hostr_orders_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_orders_negotiateAccept` to accept the latest offer, or `hostr_orders_cancel` to cancel the private negotiation or committed reservation. +- Payment: for normal instant-book payment, call `hostr_orders_bookAndPay`. After showing the returned QR/invoice, call the read-only `hostr_swaps_watch` with `swapId`, `tradeId`, and `reservationWaitSeconds`; it has no `dryRun` parameter and does not require approval. Use `hostr_swaps_recoverAll` only for explicit manual recovery/debug flows. - Messaging: call `hostr_updates`, choose recipient pubkeys from the thread/trade, call `hostr_thread_message` with `dryRun: true`, then repeat with `dryRun: false`. - Listing management/profile/trips/bookings: call `hostr_listings_list` to inspect listing inventory, `hostr_profile_show` to inspect the current profile, `hostr_profile_edit` to preview/publish profile changes, `hostr_trips_list` for guest-side reservations, and `hostr_bookings_list` for reservations on listings authored by the authenticated user. - Escrow compatibility: call `hostr_escrow_methods` with a seller pubkey before payment when the agent needs to explain compatible escrow services or ask the user to choose a non-default service. diff --git a/ai/mcp-server/chatgpt-app-submission.json b/ai/mcp-server/chatgpt-app-submission.json index 598857da..389d6e15 100644 --- a/ai/mcp-server/chatgpt-app-submission.json +++ b/ai/mcp-server/chatgpt-app-submission.json @@ -344,7 +344,7 @@ "destructive_justification": "Does not delete, overwrite, revoke access, send irreversible messages, or perform irreversible transactions." } }, - "hostr_reservations_bookAndPay": { + "hostr_orders_bookAndPay": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -356,7 +356,7 @@ "destructive_justification": "Starts a booking handoff and payment prompt but does not delete, overwrite, revoke access, or settle funds by itself." } }, - "hostr_reservations_cancel": { + "hostr_orders_cancel": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -368,7 +368,7 @@ "destructive_justification": "Cancels a private negotiation or committed reservation after approval." } }, - "hostr_reservations_commit": { + "hostr_orders_commit": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -380,7 +380,7 @@ "destructive_justification": "Publishes a committed paid reservation after a payment proof is available." } }, - "hostr_reservations_negotiateAccept": { + "hostr_orders_negotiateAccept": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -392,7 +392,7 @@ "destructive_justification": "Sends private reservation negotiation events that cannot be unsent after live execution." } }, - "hostr_reservations_negotiateOffer": { + "hostr_orders_negotiateOffer": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -404,7 +404,7 @@ "destructive_justification": "Sends private reservation negotiation events that cannot be unsent after live execution." } }, - "hostr_reservations_pay": { + "hostr_orders_pay": { "annotations": { "readOnlyHint": false, "openWorldHint": true, @@ -416,7 +416,7 @@ "destructive_justification": "Creates manual escrow funding state for a reservation trade after approval." } }, - "hostr_reservations_review": { + "hostr_orders_review": { "annotations": { "readOnlyHint": false, "openWorldHint": true, diff --git a/ai/mcp-server/scripts/codex-ai-e2e.mjs b/ai/mcp-server/scripts/codex-ai-e2e.mjs index 6ff8d880..bcb7ec9c 100644 --- a/ai/mcp-server/scripts/codex-ai-e2e.mjs +++ b/ai/mcp-server/scripts/codex-ai-e2e.mjs @@ -498,7 +498,7 @@ function buildPhases(runMode) { { prompt: "Please draft that five-star Hostr trip review now and show me the preview. If it cannot be published yet, the preview is enough.", - when: missingTool("hostr_reservations_review"), + when: missingTool("hostr_orders_review"), }, ], }, @@ -525,34 +525,34 @@ function buildPhases(runMode) { prompt: "For the reservation offer examples, use the same $20 stay total. Preview sending that counteroffer and preview accepting the latest offer; don't send or pay anything.", when: missingAnyTool( - "hostr_reservations_negotiateOffer", - "hostr_reservations_negotiateAccept", + "hostr_orders_negotiateOffer", + "hostr_orders_negotiateAccept", ), }, { prompt: "Please retry the reservation offer preview with the same $20 total; don't send it.", - when: failedTool("hostr_reservations_negotiateOffer"), + when: failedTool("hostr_orders_negotiateOffer"), }, { prompt: "Please retry the latest-offer acceptance preview; don't accept it live.", - when: failedTool("hostr_reservations_negotiateAccept"), + when: failedTool("hostr_orders_negotiateAccept"), }, { prompt: "Please switch back to my guest account and preview the negotiated payment check for this reservation; don't pay anything.", - when: failedTool("hostr_reservations_pay"), + when: failedTool("hostr_orders_pay"), }, { prompt: "Please also preview the final reservation publication check from a saved paid proof or payment record; don't publish anything.", - when: missingTool("hostr_reservations_commit"), + when: missingTool("hostr_orders_commit"), }, { prompt: "Please try the final reservation publication preview anyway; if the proof is missing, let Hostr return that as the preview result. Don't publish anything.", - when: missingTool("hostr_reservations_commit"), + when: missingTool("hostr_orders_commit"), }, ], }, @@ -878,7 +878,7 @@ async function handleCodexLine(line) { const observedTradeId = findStringByKey(item.result, "tradeId"); if ( observedTradeId && - ["hostr_reservations_bookAndPay", "hostr_swaps_watch"].includes(item.tool) + ["hostr_orders_bookAndPay", "hostr_swaps_watch"].includes(item.tool) ) { latestTradeId = observedTradeId; } @@ -1238,7 +1238,7 @@ function noHostrToolCalls(phaseStart) { function missingSwapWatchAfterBooking(phaseStart) { const calls = phaseToolCalls(phaseStart); return ( - calls.some((call) => call.tool === "hostr_reservations_bookAndPay") && + calls.some((call) => call.tool === "hostr_orders_bookAndPay") && calls.every((call) => call.tool !== "hostr_swaps_watch") ); } @@ -1286,13 +1286,13 @@ function validatePhase(label, phase, phaseStart, result) { function roleActionWasSatisfied(role, calls) { if (role === "guest") { - return calls.some((call) => call.tool === "hostr_reservations_bookAndPay"); + return calls.some((call) => call.tool === "hostr_orders_bookAndPay"); } if (role === "host") { return ( calls.some((call) => call.tool === "hostr_bookings_list") && calls.some((call) => - ["hostr_thread_message", "hostr_reservations_cancel"].includes(call.tool), + ["hostr_thread_message", "hostr_orders_cancel"].includes(call.tool), ) ); } @@ -1304,7 +1304,7 @@ function roleActionWasSatisfied(role, calls) { function needsBookingConfirmation(phaseStart) { const calls = phaseToolCalls(phaseStart); - if (calls.some((call) => call.tool === "hostr_reservations_bookAndPay")) { + if (calls.some((call) => call.tool === "hostr_orders_bookAndPay")) { return false; } const lastMessage = phaseAgentMessages(phaseStart).at(-1) ?? ""; @@ -1315,7 +1315,7 @@ function needsBookingConfirmation(phaseStart) { function needsGuestLogin(phaseStart) { const calls = phaseToolCalls(phaseStart); - if (calls.some((call) => call.tool === "hostr_reservations_bookAndPay")) { + if (calls.some((call) => call.tool === "hostr_orders_bookAndPay")) { return false; } const connectedGuest = calls.some( @@ -1332,7 +1332,7 @@ function needsStayClarification(phaseStart) { const calls = phaseToolCalls(phaseStart); if ( calls.some((call) => - ["hostr_listings_search", "hostr_reservations_bookAndPay"].includes( + ["hostr_listings_search", "hostr_orders_bookAndPay"].includes( call.tool, ), ) @@ -1349,7 +1349,7 @@ function needsGuestPreferences(phaseStart) { const calls = phaseToolCalls(phaseStart); if ( calls.some((call) => - ["hostr_listings_search", "hostr_reservations_bookAndPay"].includes( + ["hostr_listings_search", "hostr_orders_bookAndPay"].includes( call.tool, ), ) @@ -1374,7 +1374,7 @@ function needsAddressClarification(phaseStart) { function needsPaymentConfirmation(phaseStart) { const calls = phaseToolCalls(phaseStart); const hasInvoice = calls.some((call) => { - if (call.tool !== "hostr_reservations_bookAndPay" || call.status !== "completed") { + if (call.tool !== "hostr_orders_bookAndPay" || call.status !== "completed") { return false; } return Boolean( @@ -1431,12 +1431,12 @@ function evaluate({ exitCode }) { "hostr_listings_availability", "hostr_listings_reviews", "hostr_listings_reservationGroups", - "hostr_reservations_bookAndPay", - "hostr_reservations_negotiateOffer", - "hostr_reservations_negotiateAccept", - "hostr_reservations_pay", - "hostr_reservations_commit", - "hostr_reservations_review", + "hostr_orders_bookAndPay", + "hostr_orders_negotiateOffer", + "hostr_orders_negotiateAccept", + "hostr_orders_pay", + "hostr_orders_commit", + "hostr_orders_review", "hostr_swaps_watch", "hostr_swaps_list", "hostr_swaps_recoverAll", @@ -1446,7 +1446,7 @@ function evaluate({ exitCode }) { "hostr_bookings_list", "hostr_thread_message", "hostr_escrow_involve", - "hostr_reservations_cancel", + "hostr_orders_cancel", "hostr_profile_show", "hostr_profile_lookup", "hostr_profile_edit", @@ -1563,7 +1563,7 @@ function toolFailureWasRecovered(index, failedCall) { function observedBookAndPayInvoice() { for (const call of toolCalls) { - if (call.tool !== "hostr_reservations_bookAndPay" || call.status !== "completed") { + if (call.tool !== "hostr_orders_bookAndPay" || call.status !== "completed") { continue; } const invoice = findString(call.result, (value) => @@ -1591,7 +1591,7 @@ function aiDisplayedPaymentQr(messages) { function toolDisplayedLightningInvoice(invoice) { return toolCalls.some((call) => { - if (call.tool !== "hostr_reservations_bookAndPay" || call.status !== "completed") { + if (call.tool !== "hostr_orders_bookAndPay" || call.status !== "completed") { return false; } const text = summarizeToolResult(call.result); @@ -1601,7 +1601,7 @@ function toolDisplayedLightningInvoice(invoice) { function toolDisplayedPaymentQr() { return toolCalls.some((call) => { - if (call.tool !== "hostr_reservations_bookAndPay" || call.status !== "completed") { + if (call.tool !== "hostr_orders_bookAndPay" || call.status !== "completed") { return false; } return /!\[[^\]]*(qr|payment|invoice|lightning)[^\]]*\]\([^)]+\)|payment-qr|qr code|scan|create-qr-code/i.test( diff --git a/ai/mcp-server/src/generated/hostr-actions.ts b/ai/mcp-server/src/generated/hostr-actions.ts index a99a6c8e..d6ac5af1 100644 --- a/ai/mcp-server/src/generated/hostr-actions.ts +++ b/ai/mcp-server/src/generated/hostr-actions.ts @@ -217,7 +217,7 @@ export interface HostrListingsAnchorsInput { limit?: number; } -export interface HostrReservationBookAndPayInput { +export interface HostrOrderBookAndPayInput { /** Listing naddr/a-tag anchor to instant-book. */ listingAnchor: string; /** Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */ @@ -243,7 +243,7 @@ export interface HostrAmountInput { decimals?: number; } -export interface HostrReservationsOfferInput { +export interface HostrOrdersOfferInput { /** Listing naddr/a-tag anchor for a first offer. */ listingAnchor?: string; /** Single listing anchor alternative to listingAnchor. */ @@ -261,7 +261,7 @@ export interface HostrReservationsOfferInput { timeoutSeconds?: number; } -export interface HostrReservationTradeInput { +export interface HostrOrderTradeInput { tradeId: string; amount?: HostrAmountInput; reason?: string; @@ -269,7 +269,7 @@ export interface HostrReservationTradeInput { timeoutSeconds?: number; } -export interface HostrReservationPayInput { +export interface HostrOrderPayInput { /** Reservation trade id from negotiation updates. */ tradeId: string; /** Optional escrow service id/pubkey/contract address. */ @@ -278,14 +278,14 @@ export interface HostrReservationPayInput { timeoutSeconds?: number; } -export interface HostrReservationCommitInput { - /** Boltz swap id returned by hostr_reservations_pay. */ +export interface HostrOrderCommitInput { + /** Boltz swap id returned by hostr_orders_pay. */ swapId: string; dryRun?: boolean; timeoutSeconds?: number; } -export interface HostrReservationReviewInput { +export interface HostrOrderReviewInput { /** Reservation trade id for the trip to review. */ tradeId: string; /** Guest rating from 1 to 5. */ @@ -355,7 +355,7 @@ export interface HostrProfileEditInput { dryRun?: boolean; } -export interface HostrReservationCollectionInput { +export interface HostrOrderCollectionInput { limit?: number; tradeId?: string; waitSeconds?: number; @@ -586,7 +586,7 @@ export const HostrListingsAnchorsInputSchema = z.object({ "limit": z.number().int().min(1).max(200).default(50).optional() }).strict(); -export const HostrReservationBookAndPayInputSchema = z.object({ +export const HostrOrderBookAndPayInputSchema = z.object({ "listingAnchor": z.string().describe("Listing naddr/a-tag anchor to instant-book."), "start": z.string().datetime().describe("Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time."), "end": z.string().datetime().describe("Reservation end calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time."), @@ -600,7 +600,7 @@ export const HostrReservationBookAndPayInputSchema = z.object({ "proofTimeoutSeconds": z.number().int().min(30).max(3600).describe("Seconds to wait for the global reservation stream to emit the committed reservation after swap completion.").default(300).optional() }).strict(); -export const HostrReservationsOfferInputSchema = z.object({ +export const HostrOrdersOfferInputSchema = z.object({ "listingAnchor": z.string().describe("Listing naddr/a-tag anchor for a first offer.").optional(), "anchor": z.string().describe("Single listing anchor alternative to listingAnchor.").optional(), "tradeId": z.string().describe("Existing reservation trade id for a follow-up offer.").optional(), @@ -616,7 +616,7 @@ export const HostrReservationsOfferInputSchema = z.object({ "timeoutSeconds": z.number().int().min(1).max(60).default(12).optional() }).strict(); -export const HostrReservationTradeInputSchema = z.object({ +export const HostrOrderTradeInputSchema = z.object({ "tradeId": z.string(), "amount": z.object({ "value": z.string().describe("Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC."), @@ -629,20 +629,20 @@ export const HostrReservationTradeInputSchema = z.object({ "timeoutSeconds": z.number().int().min(1).max(60).default(12).optional() }).strict(); -export const HostrReservationPayInputSchema = z.object({ +export const HostrOrderPayInputSchema = z.object({ "tradeId": z.string().describe("Reservation trade id from negotiation updates."), "escrowServiceId": z.string().describe("Optional escrow service id/pubkey/contract address. Omit to use the first compatible mutual escrow.").optional(), "dryRun": z.boolean().default(true).optional(), "timeoutSeconds": z.number().int().min(1).max(60).default(12).optional() }).strict(); -export const HostrReservationCommitInputSchema = z.object({ - "swapId": z.string().describe("Boltz swap id returned by hostr_reservations_pay."), +export const HostrOrderCommitInputSchema = z.object({ + "swapId": z.string().describe("Boltz swap id returned by hostr_orders_pay."), "dryRun": z.boolean().default(true).optional(), "timeoutSeconds": z.number().int().min(1).max(60).default(12).optional() }).strict(); -export const HostrReservationReviewInputSchema = z.object({ +export const HostrOrderReviewInputSchema = z.object({ "tradeId": z.string().describe("Reservation trade id for the trip to review."), "rating": z.number().int().min(1).max(5).describe("Guest rating from 1 to 5."), "content": z.string().describe("Public review text to publish."), @@ -706,7 +706,7 @@ export const HostrProfileEditInputSchema = z.object({ "dryRun": z.boolean().default(true).optional() }).strict(); -export const HostrReservationCollectionInputSchema = z.object({ +export const HostrOrderCollectionInputSchema = z.object({ "limit": z.number().int().min(1).max(200).default(50).optional(), "tradeId": z.string().describe("Optional reservation trade id to look up directly after payment/proof completion.").optional(), "waitSeconds": z.number().int().min(0).max(300).describe("How long to poll for a committed public reservation when tradeId is provided.").default(15).optional() @@ -811,7 +811,7 @@ export const HostrSwapsListInputSchema = z.object({ "namespace": z.string().default("all").optional() }).strict(); -export const hostrActionDocumentation = "# Hostr MCP action inputs\n\nAll Hostr MCP tools are backed by typed Dart daemon actions. The MCP access token selects a server-side MCP session; hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout manage the active Hostr account/pubkey for that session. For natural role wording such as guest, host, or escrow, inspect connected accounts, switch to a matching connected account, or connect a new account when needed. Do not assume the currently active account satisfies a requested role merely because it is already authenticated.\n\nDo not run routine preflight session/profile checks before sensitive tools. Call the intended Hostr tool first. If it returns auth_required, call hostr_session_connect, complete sign-in, then retry the original action. If it returns profile_required, collect the missing profile fields, call hostr_profile_edit, publish after approval, then retry the original action.\n\nHostr is also the intended tool surface for Hostr-related Nostr network work: Nostr Connect/NIP-46 sign-in, signer/bunker recovery, NIP events, relays, pubkeys/npubs, naddrs, gift-wrapped messages, inbox threads, and Hostr marketplace events. Do not use general web search for these Hostr/Nostr/NIP state workflows unless the user explicitly asks for public web documentation.\n\nHostr reservation privacy: when Hostr creates or completes a reservation, the public committed reservation, escrow trade, and trade thread may be under Hostr-created per-trade temporary pubkeys rather than the active logged-in account pubkey. This is expected privacy-preserving behavior. Do not tell the user this is an identity mismatch, do not warn that the reservation is not under their pubkey, and do not treat the temporary trade pubkey as a separate logged-in account.\n\nIf the user asks how Hostr works or what happens when they send money, explain that Hostr swaps the payment over Lightning into a smart-contract escrow. The escrow service cannot freely take custody of the money; it can only settle the contract by forwarding payment to the host or reversing it according to the trade outcome.\n\nMost write tools default to preview mode. Only set `dryRun: false` after the user has explicitly approved the preview returned by the same tool. `hostr_reservations_bookAndPay` is the correct foreground handoff tool when the user asks to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. If it returns external Lightning payment details, the assistant MUST leave only the invoice string and QR image visibly in the user-facing output; tradeId and swapId are internal follow-up arguments. The next assistant action after rendering the QR and invoice must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. `reservationWaitSeconds` is capped below MCP client timeouts. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\n## Reservation date semantics\n\nReservation `start` and `end` inputs are calendar dates, not timezone-sensitive instants. Preserve the date the user requested and encode it as `YYYY-MM-DDT00:00:00Z`; the trailing `Z` is storage syntax only. Do not convert from user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\n## Workflow playbooks\n\n### New listing workflow\n\nCall `hostr_profile_edit` if profile details need updating, then call `hostr_listings_create` with `dryRun: true`, show the preview, and only call it again with `dryRun: false` after explicit approval. The publish call must reuse the exact `dTag` from the preview result (`structuredContent.nextInput.dTag` or `structuredContent.dTag`) so preview, publish, and retry target the same replaceable listing. The live action ensures seller config is published.\n\n### Edit listing workflow\n\nCall `hostr_listings_edit` with `dryRun: true`, review the returned listing/event preview, then repeat with `dryRun: false` after approval.\n\n### Search and reserve workflow\n\nCall `hostr_listings_search`, then `hostr_listings_availability`. For user phrasing such as \"book\", \"reserve\", \"make me a reservation\", or \"create a reservation\" on an instant-book stay where the amount is at or above the listing price, call `hostr_reservations_bookAndPay`. If it returns external Lightning payment details, show only the invoice string and QR image immediately and keep them visible in the output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator. Do not stop after `hostr_reservations_negotiateOffer` for this intent. For explicit negotiation-only requests, call `hostr_reservations_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM.\n\n### Negotiation workflow\n\nCall `hostr_updates` to inspect thread/trade ids. Use `hostr_reservations_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_reservations_negotiateAccept` to accept the latest offer, or `hostr_reservations_cancel` to cancel the private negotiation or committed reservation.\n\n### Payment workflow\n\nFor normal AI-initiated instant-book payment, use `hostr_reservations_bookAndPay`. When the tool returns external Lightning payment details, the AI must leave only the invoice text and QR image visible to the user first. The next assistant action must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion while the daemon continues the book-and-pay operation in the background; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; payment proof publication is owned by the global Hostr payment proof orchestrator. Keep `hostr_reservations_pay`, `hostr_reservations_commit`, and `hostr_swaps_recoverAll` for manual recovery/debug paths.\n\n### Messaging workflow\n\nCall `hostr_updates`, choose the thread/trade recipient pubkeys, call `hostr_thread_message` with `dryRun: true`, then `dryRun: false` after approval.\n\n### Review workflow\n\nWhen a guest asks to review a trip, identify the trade with `hostr_trips_list`, call `hostr_reservations_review` with `dryRun: true`, show the preview, then repeat with `dryRun: false` only after explicit approval. If no committed reservation can be found, skip the review action and explain that the trip is not reviewable yet.\n\n### Swaps workflow\n\nCall `hostr_swaps_list`, then `hostr_swaps_watch` for a specific swap id, and `hostr_swaps_recoverAll` when stale operations need recovery.\n\n## `hostr_session_status`\n\nInspect the active Hostr account for this MCP session.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks whether they are logged in, when debugging auth, or after a Hostr action returns an auth/profile/signature error. Do not call this as a routine preflight before every write; failed tools return structured recovery instructions.\n\nAction id: `hostr.session.status`\n\n```ts\nexport interface HostrSessionStatusInput {\n /** Include non-secret storage/session diagnostics useful for debugging. */\n includeStorageDetails?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"includeStorageDetails\": {\n \"type\": \"boolean\",\n \"description\": \"Include non-secret storage/session diagnostics useful for debugging.\",\n \"default\": false\n }\n }\n}\n```\n\n## `hostr_session_connect`\n\nCreate or complete a Nostr Connect request for this MCP session. When approved, the connected pubkey becomes the active Hostr account. When wait is false, show the returned QR/URI with the text \"Scan this with your Nostr app to log in to your Hostr account\", then immediately call this tool again with wait true to listen for the session connection and continue the intended Hostr action.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nTwo-step login flow: call with wait=false to create or reuse a Nostr Connect request, display the nostrconnect URI or QR image to the user, then immediately call this tool again with wait=true and regenerate=false to listen for approval. Use this for ordinary requests like \"log in\", \"sign me in\", \"use my guest account\", \"switch me to a host account\" when that account is not already connected, or \"I am handling escrow now\" when no connected escrow account is available. If a different Hostr account is already active but the user asks for a role that is not clearly that active account, connect or switch before continuing. After authenticated=true, this account becomes the active Hostr account for the MCP session; retry or continue the Hostr action that required sign-in.\n\nAction id: `hostr.session.connect`\n\n```ts\nexport interface HostrSessionConnectInput {\n /** False returns an active nostrconnect URI/QR for display. True waits for the shown request to connect; call it immediately after displaying the QR so the original Hostr action can continue. */\n wait?: boolean;\n /** How long to wait for approval when wait is true. Defaults to 180, capped at 600. */\n timeoutSeconds?: number;\n /** Force a fresh nostrconnect request instead of reusing the pending one. */\n regenerate?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"wait\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"False returns an active nostrconnect URI/QR for display. True waits for the already-shown request to connect; call it immediately after displaying the QR so the original Hostr action can continue.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 600,\n \"default\": 180,\n \"description\": \"How long to wait for approval when wait is true.\"\n },\n \"regenerate\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Force a fresh nostrconnect request instead of reusing the pending one.\"\n }\n }\n}\n```\n\n## `hostr_listings_search`\n\nSearch Hostr lodging and accommodation marketplace listings. Prefer this Hostr tool for natural travel/lodging requests such as \"find a place to stay\", \"find somewhere to stay in San Salvador\", \"look for lodging\", \"show me accommodations\", \"find a room/apartment/hotel/villa\", \"where can I stay\", \"book a stay\", or \"find rentals\". Use the location field for city/country/place names instead of doing a general web search.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for marketplace discovery from natural language lodging intents such as finding a place to stay, lodging, accommodation, room, apartment, house, villa, hotel-like stay, or rental in a destination. Put city/country/place names in location; put keyword filters in query; use guests/features/type only when the user provides them. Results return listing-card Markdown and structured cards; preserve every image tag when presenting results.\n\nAction id: `hostr.listings.search`\n\n```ts\nexport interface HostrListingsSearchInput {\n /** Human-readable destination/place to search for Hostr stays, lodging, accommodation, rentals, rooms, apartments, hotels, villas, resorts, or places to stay, such as \"San Salvador\", \"El Salvador\", or \"Lisbon\". */\n location?: string;\n /** Client-side text filter over listing title and description. */\n query?: string;\n /** Hostr listing type, for example room, house, apartment, cabin, or villa. */\n type?: string;\n /** Minimum guest capacity. */\n guests?: number;\n /** Required canonical boolean listing specification keys. Use wireless_internet for Wi-Fi/wifi/WIFI. Examples: wireless_internet, kitchen, pool, free_parking, allows_pets, beachfront. */\n features?: string[];\n /** Maximum number of listings to return. Defaults to 10, capped at 50. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"location\": {\n \"type\": \"string\",\n \"description\": \"Human-readable destination/place to search for Hostr stays, lodging, accommodation, rentals, rooms, apartments, hotels, villas, resorts, or places to stay, such as \\\"San Salvador\\\", \\\"El Salvador\\\", or \\\"Lisbon\\\".\"\n },\n \"query\": {\n \"type\": \"string\",\n \"description\": \"Client-side text filter over listing title and description.\"\n },\n \"type\": {\n \"type\": \"string\",\n \"description\": \"Hostr listing type, for example room, house, apartment, cabin, or villa.\"\n },\n \"guests\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Minimum guest capacity.\"\n },\n \"features\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Required canonical boolean listing specification keys. Use wireless_internet for Wi-Fi/wifi/WIFI. Examples: wireless_internet, kitchen, pool, free_parking, allows_pets, beachfront.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 50,\n \"default\": 10,\n \"description\": \"Maximum number of listings to return.\"\n }\n }\n}\n```\n\n## `hostr_listings_list`\n\nList Hostr listings, optionally restricted to the authenticated user or a supplied author pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for inventory/management views: \"my listings\", \"what am I hosting\", \"show my stays\", or listings by a known author pubkey. Use mine=true for the authenticated user. Use author only when the user provides or selected a specific pubkey.\n\nAction id: `hostr.listings.list`\n\n```ts\nexport interface HostrListingsListInput {\n mine?: boolean;\n author?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"mine\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Only list listings authored by the authenticated user.\"\n },\n \"author\": {\n \"type\": \"string\",\n \"description\": \"Only list listings authored by this pubkey.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_listings_create`\n\nCreate a Hostr listing for the active Hostr account. Listing images must be passed as images[].url. For user-uploaded files, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST the original image bytes to /mcp/uploads/images on the same Hostr MCP origin using multipart/form-data field name file, then pass the returned upload.url as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the active account Blossom upload path before falling back to direct upload. Do not base64-encode user-uploaded images into this MCP tool call, do not serve temporary localhost URLs, and do not pass /mnt/data or file:// paths to images[].url. Set dryRun false only after explicit user approval to publish the listing event, and reuse the dryRun preview dTag so retries update the same replaceable listing.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the authenticated user wants to create, publish, list, rent out, or host a room/place/stay. Collect title, description, address, at least one image URL, and at least one price before calling. The first image is the card/hero image. This MCP tool accepts image URLs only. For ChatGPT web/mobile, local development clients, or any remote MCP client with uploaded files, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST the original image bytes to /mcp/uploads/images on the same Hostr MCP origin using multipart/form-data field name file, then pass the returned upload.url as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the logged-in session Blossom upload path before falling back to direct upload. Do not base64-encode the uploaded image into this MCP tool call. Do not serve a temporary localhost URL for Hostr to fetch; localhost refers to the wrong machine/container. If neither upload route can be used, stop and ask for a public image URL or for the client to expose an upload capability. Do not resize, downscale, crop, recompress, transcode, or make thumbnails unless the user explicitly requests it. Never pass a local or mounted sandbox path such as /mnt/data, /mnt/shared, file://, or a ChatGPT file mount to images[].url. Use dryRun=true to upload/stage media and return the visual listing preview. When publishing the approved preview, call this tool again with dryRun=false and reuse the exact dTag from structuredContent.nextInput or structuredContent.dTag so preview, publish, and any retry update the same replaceable listing. The live path also ensures seller configuration is published.\n\nAction id: `hostr.listings.create`\n\n```ts\nexport interface HostrAmountInput {\n /** Payment amount as a decimal string. If unit is sats, this is a satoshi count: 1 sat = 1/100,000,000 BTC. */\n value: string;\n /** Currency or denomination, such as USD or BTC. For sats, use BTC. */\n currency: string;\n /** Optional display/base unit. sats means satoshis: 1 sat = 1/100,000,000 BTC. */\n unit?: string;\n /** Optional decimal precision. For sats, use 0. */\n decimals?: number;\n}\n\nexport interface HostrListingImageInput {\n /** Required image URL. For user-uploaded files, use the upload.url returned by POST /mcp/uploads/images on the same Hostr MCP origin. */\n url: string;\n /** Optional original filename used for MIME detection and upload diagnostics. */\n filename?: string;\n /** Alt text for the image. */\n alt?: string;\n /** Optional MIME type override. */\n mime?: string;\n}\n\nexport interface HostrListingPriceInput {\n amount: HostrAmountInput;\n /** daily, weekly, monthly, yearly, or fixed. Defaults to daily. */\n frequency?: string;\n}\n\nexport interface HostrListingSpecificationsInput {\n /** Maximum guests. Prefer max_guests inside specifications; top-level guests is also accepted on create/edit and maps to max_guests. */\n max_guests?: number;\n beds?: number;\n bedrooms?: number;\n bathrooms?: number;\n bathtub?: number;\n tv?: number;\n airconditioning?: boolean;\n allows_pets?: boolean;\n crib?: boolean;\n tumble_dryer?: boolean;\n washer?: boolean;\n elevator?: boolean;\n free_parking?: boolean;\n gym?: boolean;\n hair_dryer?: boolean;\n heating?: boolean;\n high_chair?: boolean;\n /** Wi-Fi/wifi/WIFI must use this canonical key. */\n wireless_internet?: boolean;\n iron?: boolean;\n jacuzzi?: boolean;\n kitchen?: boolean;\n outlet_covers?: boolean;\n pool?: boolean;\n private_entrance?: boolean;\n smoking_allowed?: boolean;\n breakfast?: boolean;\n fireplace?: boolean;\n smoke_detector?: boolean;\n essentials?: boolean;\n shampoo?: boolean;\n infants_allowed?: boolean;\n children_allowed?: boolean;\n hangers?: boolean;\n flat_smooth_pathway_to_front_door?: boolean;\n grab_rails_in_shower_and_toilet?: boolean;\n oven?: boolean;\n bbq?: boolean;\n balcony?: boolean;\n patio?: boolean;\n dishwasher?: boolean;\n refrigerator?: boolean;\n garden_or_backyard?: boolean;\n microwave?: boolean;\n coffee_maker?: boolean;\n dishes_and_silverware?: boolean;\n stove?: boolean;\n fire_extinguisher?: boolean;\n carbon_monoxide_detector?: boolean;\n luggage_dropoff_allowed?: boolean;\n beach_essentials?: boolean;\n beachfront?: boolean;\n baby_monitor?: boolean;\n babysitter_recommendations?: boolean;\n childrens_books_and_toys?: boolean;\n game_console?: boolean;\n street_parking?: boolean;\n paid_parking?: boolean;\n hot_water?: boolean;\n lake_access?: boolean;\n single_level_home?: boolean;\n waterfront?: boolean;\n first_aid_kit?: boolean;\n handheld_shower_head?: boolean;\n home_step_free_access?: boolean;\n lock_on_bedroom_door?: boolean;\n mobile_hoist?: boolean;\n path_to_entrance_lit_at_night?: boolean;\n pool_hoist?: boolean;\n ev_charger?: boolean;\n rollin_shower?: boolean;\n shower_chair?: boolean;\n tub_with_shower_bench?: boolean;\n wide_clearance_to_bed?: boolean;\n wide_clearance_to_shower_and_toilet?: boolean;\n wide_hallway_clearance?: boolean;\n baby_bath?: boolean;\n changing_table?: boolean;\n room_darkening_shades?: boolean;\n stair_gates?: boolean;\n table_corner_guards?: boolean;\n extra_pillows_and_blankets?: boolean;\n ski_in_ski_out?: boolean;\n window_guards?: boolean;\n disabled_parking_spot?: boolean;\n grab_rails_in_toilet?: boolean;\n events_allowed?: boolean;\n common_spaces_shared?: boolean;\n bathroom_shared?: boolean;\n security_cameras?: boolean;\n}\n\nexport interface HostrListingsCreateInput {\n title: string;\n description: string;\n /** Precise address used for H3 tag generation. */\n address: string;\n images: HostrListingImageInput[];\n prices: HostrListingPriceInput[];\n type?: string;\n /** Canonical listing specifications/amenities map. Use wireless_internet for Wi-Fi/wifi/WIFI; do not use wifi or WIFI. */\n specifications?: HostrListingSpecificationsInput;\n guests?: number;\n beds?: number;\n bedrooms?: number;\n bathrooms?: number;\n active?: boolean;\n negotiable?: boolean;\n instantBook?: boolean;\n minStay?: number;\n checkIn?: string;\n checkOut?: string;\n quantity?: number;\n securityDeposit?: HostrAmountInput;\n minPaymentAmount?: HostrAmountInput;\n h3Tags?: string[];\n h3FinestResolution?: number;\n h3MaxTags?: number;\n /** Stable Nostr d tag for this listing draft. Reuse the dryRun preview dTag when publishing so retries update the same replaceable listing. */\n dTag?: string;\n /** True uploads local images to Blossom and previews only. Set false to publish after explicit user approval, reusing the preview dTag. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"title\",\n \"description\",\n \"address\",\n \"images\",\n \"prices\"\n ],\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"description\": \"Public listing title.\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Public listing description.\"\n },\n \"address\": {\n \"type\": \"string\",\n \"description\": \"Private-ish precise address used by Hostr to generate H3 tags.\"\n },\n \"type\": {\n \"type\": \"string\",\n \"description\": \"Listing type, such as room, apartment, house, or villa.\"\n },\n \"images\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"description\": \"Listing images. This MCP tool accepts image URLs only. Mandatory flow for user-uploaded files: first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url here as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST each original file bytes payload to /mcp/uploads/images on this same MCP server origin using multipart/form-data field name file, then pass the returned upload.url here as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the logged-in session Blossom upload path before falling back to direct upload. Do not base64-encode uploaded images into this tool call. Do not start or serve a temporary localhost URL for the MCP server to fetch; localhost refers to the wrong machine/container. Do not resize, downscale, crop, recompress, transcode, or make thumbnails unless the user explicitly requests it. If neither upload route can be used, stop and ask for a public image URL or for the client to expose an upload capability. Never pass client-local or mounted file paths like /mnt/data, /mnt/shared, file://, or ChatGPT file mounts to images[].url.\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"url\"\n ],\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"description\": \"Required image URL. For user-uploaded files, this must be structuredContent.usage.image.url returned by hostr_images_upload, or upload.url returned by POST /mcp/uploads/images on the same Hostr MCP origin. Public HTTP(S) source URLs are also accepted; Hostr downloads non-Blossom URLs and uploads them to Blossom before publishing.\"\n },\n \"filename\": {\n \"type\": \"string\",\n \"description\": \"Optional original filename used for MIME detection and upload diagnostics.\"\n },\n \"alt\": {\n \"type\": \"string\",\n \"description\": \"Image alt text.\"\n },\n \"mime\": {\n \"type\": \"string\",\n \"description\": \"Optional MIME type, for example image/jpeg or image/png.\"\n }\n }\n }\n },\n \"prices\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"description\": \"Listing prices. All monetary fields must use the same currency. If a user mentions sats, they mean satoshis: 1 sat = 1/100,000,000 BTC. Represent bitcoin satoshi prices as amount.value equal to the satoshi count, amount.currency BTC, amount.unit sats, and amount.decimals 0.\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"amount\"\n ],\n \"properties\": {\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"frequency\": {\n \"type\": \"string\",\n \"description\": \"daily, weekly, monthly, yearly, or fixed.\"\n }\n }\n }\n },\n \"specifications\": {\n \"type\": \"object\",\n \"description\": \"Listing specifications/amenities map for hostr_listings_create and patch.specifications on hostr_listings_edit. Use canonical snake_case keys, not display labels or arbitrary amenity names. Wi-Fi/wifi/WIFI must be sent as wireless_internet. Boolean keys use true when present; false/null values are ignored by listing tag serialization. Numeric keys use positive integers. Numeric keys: max_guests, beds, bedrooms, bathrooms, bathtub, tv. Boolean keys: airconditioning, allows_pets, crib, tumble_dryer, washer, elevator, free_parking, gym, hair_dryer, heating, high_chair, wireless_internet, iron, jacuzzi, kitchen, outlet_covers, pool, private_entrance, smoking_allowed, breakfast, fireplace, smoke_detector, essentials, shampoo, infants_allowed, children_allowed, hangers, flat_smooth_pathway_to_front_door, grab_rails_in_shower_and_toilet, oven, bbq, balcony, patio, dishwasher, refrigerator, garden_or_backyard, microwave, coffee_maker, dishes_and_silverware, stove, fire_extinguisher, carbon_monoxide_detector, luggage_dropoff_allowed, beach_essentials, beachfront, baby_monitor, babysitter_recommendations, childrens_books_and_toys, game_console, street_parking, paid_parking, hot_water, lake_access, single_level_home, waterfront, first_aid_kit, handheld_shower_head, home_step_free_access, lock_on_bedroom_door, mobile_hoist, path_to_entrance_lit_at_night, pool_hoist, ev_charger, rollin_shower, shower_chair, tub_with_shower_bench, wide_clearance_to_bed, wide_clearance_to_shower_and_toilet, wide_hallway_clearance, baby_bath, changing_table, room_darkening_shades, stair_gates, table_corner_guards, extra_pillows_and_blankets, ski_in_ski_out, window_guards, disabled_parking_spot, grab_rails_in_toilet, events_allowed, common_spaces_shared, bathroom_shared, security_cameras.\"\n },\n \"guests\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"beds\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"bedrooms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"bathrooms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"active\": {\n \"type\": \"boolean\"\n },\n \"negotiable\": {\n \"type\": \"boolean\"\n },\n \"instantBook\": {\n \"type\": \"boolean\"\n },\n \"minStay\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"checkIn\": {\n \"type\": \"string\"\n },\n \"checkOut\": {\n \"type\": \"string\"\n },\n \"quantity\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"securityDeposit\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"minPaymentAmount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"h3Tags\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Optional precomputed H3 tags. If omitted, address is geocoded.\"\n },\n \"h3FinestResolution\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"h3MaxTags\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"dTag\": {\n \"type\": \"string\",\n \"description\": \"Stable Nostr d tag for this listing draft. When publishing an approved dryRun preview, reuse the dTag returned in structuredContent.nextInput.dTag or structuredContent.dTag so retries update the same replaceable listing instead of creating duplicates.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True uploads local images to Blossom and previews the listing card only. Set false to publish after explicit approval, reusing the preview dTag.\"\n }\n }\n}\n```\n\n## `hostr_listings_edit`\n\nPreview or publish a patch to an existing listing authored by the authenticated user. The live path also ensures seller configuration is published before signing the listing.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the authenticated author wants to update an existing listing. If the user has not named a concrete listing anchor, first call hostr_listings_list with mine=true and ask/choose from the returned listings. Patch only fields the user intends to change; preview with dryRun=true and publish with dryRun=false only after approval.\n\nAction id: `hostr.listings.edit`\n\n```ts\nexport interface HostrListingsEditInput {\n /** Listing naddr/a-tag anchor. */\n anchor: string;\n /** Listing fields to change. */\n patch?: Partial;\n /** True previews only. Set false to publish after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"anchor\"\n ],\n \"properties\": {\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor.\"\n },\n \"patch\": {\n \"type\": \"object\",\n \"description\": \"Listing fields to change. Supports title, description, address, type, images, prices, specifications, guests, beds, bedrooms, bathrooms, active, negotiable, instantBook, quantity, securityDeposit, and minPaymentAmount. patch.specifications uses the same canonical listing specifications/amenities map as hostr_listings_create; use wireless_internet for Wi-Fi/wifi/WIFI.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True previews only. Set false to publish after explicit approval.\"\n }\n }\n}\n```\n\n## `hostr_listings_availability`\n\nCheck whether one or more listings are available for a requested reservation date range. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nUse after a user has selected one or more listings and supplied dates, before booking or explaining date conflicts. Pass listing anchors from search/list results. If dates are missing, ask for them instead of guessing.\n\nAction id: `hostr.listings.availability`\n\n```ts\nexport interface HostrListingsAvailabilityInput {\n /** Listing anchors to check. */\n anchors?: string[];\n /** Single listing anchor alternative. */\n anchor?: string;\n /** Requested start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start: string;\n /** Requested end calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"start\",\n \"end\"\n ],\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors to check.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor alternative to anchors.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Requested start calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Requested end calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n }\n }\n}\n```\n\n## `hostr_listings_reviews`\n\nFetch review events attached to one or more listings.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks about reviews, reputation, prior guest feedback, or trust signals for one or more listings. Pass listing anchors from search/list results.\n\nAction id: `hostr.listings.reviews`\n\n```ts\nexport interface HostrListingsAnchorsInput {\n anchors?: string[];\n anchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_listings_reservationGroups`\n\nFetch public reservation groups for one or more listings. Use this before availability-sensitive reservation workflows when the agent needs to explain conflicts.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks why dates are unavailable, wants booking history/conflicts for a listing, or needs reservation context before changing availability-sensitive plans.\n\nAction id: `hostr.listings.reservationGroups`\n\n```ts\nexport interface HostrListingsAnchorsInput {\n anchors?: string[];\n anchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_reservations_bookAndPay`\n\nUse this foreground handoff tool whenever the user says to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. It creates the private reservation offer and escrow funding swap. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time. Reservation privacy: Hostr intentionally publishes committed reservations and escrow trades under Hostr-created per-trade temporary pubkeys rather than the active account pubkey. This is normal and preserves user privacy; never present a different reservation buyer pubkey as an identity mismatch. If external Lightning payment is required, it returns the invoice string, QR image, internal trade id, internal swap id, and continuesInBackground=true while the daemon keeps the book-and-pay operation alive. CRITICAL UI REQUIREMENT: leave only the QR image and invoice text visibly in the answer to the user; do not show internal trade id or swap id in the payment prompt, and do not replace the payment prompt with a summary. The next assistant action after rendering that visible payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. The returned `reservationWaitSeconds` is short and capped below MCP client timeouts; do not substitute a longer proof timeout. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, query `hostr_trips_list` with `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nPrimary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_reservations_commit for this normal path; proof publication is owned by the global payment proof orchestrator.\n\nAction id: `hostr.reservations.bookAndPay`\n\n```ts\nexport interface HostrReservationBookAndPayInput {\n /** Listing naddr/a-tag anchor to instant-book. */\n listingAnchor: string;\n /** Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start: string;\n /** Reservation end calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end: string;\n /** Optional reservation amount override. Must be at or above the listing price. */\n amount?: HostrAmountInput;\n /** Optional escrow service id/pubkey/contract address. */\n escrowServiceId?: string;\n /** Seconds to wait for the global reservation stream to emit the committed reservation. */\n proofTimeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"listingAnchor\",\n \"start\",\n \"end\"\n ],\n \"properties\": {\n \"listingAnchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor to instant-book.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation end calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n },\n \"description\": \"Optional reservation amount override. Must be at or above the listing price.\"\n },\n \"escrowServiceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service id/pubkey/contract address. Omit to use the first compatible mutual escrow.\"\n },\n \"proofTimeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 30,\n \"maximum\": 3600,\n \"default\": 300,\n \"description\": \"Seconds to wait for the global reservation stream to emit the committed reservation after swap completion.\"\n }\n }\n}\n```\n\n## `hostr_reservations_negotiateOffer`\n\nCreate only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like \"book\", \"reserve\", \"make a reservation\", or instant-book at the listed price; those must use hostr_reservations_bookAndPay instead.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nNegotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward \"book/reserve\" intents on instant-book listings; use hostr_reservations_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.\n\nAction id: `hostr.reservations.negotiateOffer`\n\n```ts\nexport interface HostrAmountInput {\n /** Payment amount as a decimal string. If unit is sats, this is a satoshi count: 1 sat = 1/100,000,000 BTC. */\n value: string;\n /** Currency or denomination, such as USD or BTC. For sats, use BTC. */\n currency: string;\n /** Optional display/base unit. sats means satoshis: 1 sat = 1/100,000,000 BTC. */\n unit?: string;\n /** Optional decimal precision. For sats, use 0. */\n decimals?: number;\n}\n\nexport interface HostrReservationsOfferInput {\n /** Listing naddr/a-tag anchor for a first offer. */\n listingAnchor?: string;\n /** Single listing anchor alternative to listingAnchor. */\n anchor?: string;\n /** Existing reservation trade id for a follow-up offer. */\n tradeId?: string;\n /** Reservation start calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start?: string;\n /** Reservation end calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end?: string;\n /** Optional reservation amount override. Omit to use listing price rules. */\n amount?: HostrAmountInput;\n /** True previews only. Set false to send the gift-wrapped offer after user approval. */\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"listingAnchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor for a first offer.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor alternative to listingAnchor.\"\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Existing reservation trade id for a follow-up offer.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation start calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation end calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n },\n \"description\": \"Optional reservation amount override. Omit to use listing price rules.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True only builds the offer and returns the event preview. Set false to send the gift-wrapped offer after explicit approval.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_reservations_negotiateAccept`\n\nAccept the latest private negotiate-stage reservation offer in a trade thread by replying with a matching negotiate-stage event.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user wants to accept the latest private negotiated offer in a known trade thread. If tradeId is unknown, call hostr_updates, hostr_thread_view, hostr_trips_list, or hostr_bookings_list first to identify the trade.\n\nAction id: `hostr.reservations.negotiateAccept`\n\n```ts\nexport interface HostrReservationTradeInput {\n tradeId: string;\n amount?: HostrAmountInput;\n reason?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_reservations_pay`\n\nPreview or create the escrow funding swap for a payable reservation trade. The live action sends the escrow selection into the private thread as an unsigned child event, prepares the escrow fund calls, creates the Boltz swap invoice, and persists the payment context for commit.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_reservations_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.\n\nAction id: `hostr.reservations.pay`\n\n```ts\nexport interface HostrReservationPayInput {\n /** Reservation trade id from negotiation updates. */\n tradeId: string;\n /** Optional escrow service id/pubkey/contract address. */\n escrowServiceId?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Reservation trade id from negotiation updates.\"\n },\n \"escrowServiceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service id/pubkey/contract address. Omit to use the first compatible mutual escrow.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_reservations_commit`\n\nPreview or publish the public commit-stage reservation after the escrow funding swap has completed and produced a claim transaction proof.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug commit flow only. Do not use after hostr_reservations_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.\n\nAction id: `hostr.reservations.commit`\n\n```ts\nexport interface HostrReservationCommitInput {\n /** Boltz swap id returned by hostr_reservations_pay. */\n swapId: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"swapId\"\n ],\n \"properties\": {\n \"swapId\": {\n \"type\": \"string\",\n \"description\": \"Boltz swap id returned by hostr_reservations_pay.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_reservations_cancel`\n\nCancel either the private negotiate-stage reservation for a trade, or the committed public reservation if one exists.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse to cancel a private negotiation or committed reservation for a concrete trade. If tradeId is unclear, inspect updates, trips, bookings, or thread view first. Preview the cancellation and send with dryRun=false only after explicit approval.\n\nAction id: `hostr.reservations.cancel`\n\n```ts\nexport interface HostrReservationTradeInput {\n tradeId: string;\n amount?: HostrAmountInput;\n reason?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_reservations_review`\n\nPreview or publish a guest review for a committed Hostr reservation. This creates a Nostr review event with a participation proof for the reservation trade; preview first and only publish after explicit approval.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the guest wants to leave a rating/review for a completed or confirmed Hostr trip. If tradeId is unclear, inspect hostr_trips_list first. Preview with dryRun=true, then publish with dryRun=false only after explicit approval. Skip this action if no committed reservation can be found for the trade.\n\nAction id: `hostr.reservations.review`\n\n```ts\nexport interface HostrReservationReviewInput {\n /** Reservation trade id for the trip to review. */\n tradeId: string;\n /** Guest rating from 1 to 5. */\n rating: number;\n /** Public review text to publish. */\n content: string;\n /** True previews only. Set false to publish the review after user approval. */\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\",\n \"rating\",\n \"content\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Reservation trade id for the trip to review.\"\n },\n \"rating\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 5,\n \"description\": \"Guest rating from 1 to 5.\"\n },\n \"content\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Public review text to publish.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True builds and verifies the review preview. Set false only after explicit approval.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 15\n }\n }\n}\n```\n\n## `hostr_updates`\n\nFetch the authenticated inbox, process gift-wrapped thread events, and summarize new offers and messages for the agent.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse as the inbox/home-state tool when the user asks for messages, offers, notifications, reviews, trips, bookings, reservation references, latest activity, \"what are my updates\", \"my host has not replied\", or what needs attention. It processes gift-wrapped inbox events and returns thread cards, reviews left on the user's listings, trips the user booked, and hosting reservations. Present displayMarkdown, not raw event JSON.\n\nAction id: `hostr.updates`\n\n```ts\nexport interface HostrUpdatesInput {\n /** Maximum inbox events to fetch. */\n limit?: number;\n /** Seconds to wait for relay history before returning partial results. */\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 50,\n \"default\": 10\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_thread_view`\n\nLoad a Hostr conversation and return a fixed thread-view contract with message history. Use this when the user asks whether a host or escrow has messaged them, asks to see a conversation, or references a trip/booking thread.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks to see a conversation, asks whether someone messaged them, references a trip/booking thread, or you need message history before replying. Prefer tradeId when the conversation is tied to a reservation; otherwise pass a known thread/conversation anchor from updates.\n\nAction id: `hostr.thread.view`\n\n```ts\nexport interface HostrThreadViewInput {\n threadAnchor?: string;\n anchor?: string;\n conversation?: string;\n tradeId?: string;\n recipientPubkeys?: string[];\n recipientPubkey?: string;\n limit?: number;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"threadAnchor\": {\n \"type\": \"string\"\n },\n \"anchor\": {\n \"type\": \"string\"\n },\n \"conversation\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"recipientPubkeys\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_thread_message`\n\nPreview or send a text message in a Hostr conversation, then return the fixed thread-view contract. Use this when the user asks to message a host, guest, buyer, seller, or an existing thread. If the user references a trade/trip, pass tradeId; use recipientRole when they say host, guest, buyer, seller, or escrow. Escrow messaging always requires a concrete tradeId and must include the trade buyer, seller, and escrow participants in one thread.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user asks to message a host, guest, buyer, seller, escrow, or existing Hostr thread. If they reference a trip/booking/trade, pass tradeId. Use recipientRole for natural roles like host, guest, buyer, seller, or escrow. Escrow messages require a concrete tradeId and must include buyer, seller, and escrow in one shared trade thread.\n\nAction id: `hostr.thread.message`\n\n```ts\nexport interface HostrThreadMessageInput {\n content: string;\n threadAnchor?: string;\n anchor?: string;\n conversation?: string;\n tradeId?: string;\n recipientRole?: \"host\" | \"seller\" | \"guest\" | \"buyer\" | \"escrow\";\n role?: string;\n recipientPubkeys?: string[];\n recipientPubkey?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"content\"\n ],\n \"properties\": {\n \"content\": {\n \"type\": \"string\"\n },\n \"threadAnchor\": {\n \"type\": \"string\"\n },\n \"anchor\": {\n \"type\": \"string\"\n },\n \"conversation\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"recipientRole\": {\n \"type\": \"string\",\n \"enum\": [\n \"host\",\n \"seller\",\n \"guest\",\n \"buyer\",\n \"escrow\"\n ]\n },\n \"role\": {\n \"type\": \"string\"\n },\n \"recipientPubkeys\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_escrow_involve`\n\nOpen or message the escrow conversation for a specific reservation trade, then return the fixed thread-view contract. This action always requires tradeId and always resolves the trade buyer, seller, and escrow participants into one shared trade thread; it must not create an escrow-only side conversation. If content is omitted, show the escrow trade thread and ask the user what to message the escrow. If content is provided, preview by default and send only with dryRun false.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user explicitly asks to involve/message escrow for a specific reservation trade. Always pass tradeId. This opens the shared buyer/seller/escrow trade thread; never create an escrow-only side conversation. If no message content is provided, show the thread and ask what to send.\n\nAction id: `hostr.escrow.involve`\n\n```ts\nexport interface HostrEscrowInvolveInput {\n tradeId: string;\n content?: string;\n message?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Required reservation trade id. Escrow messages cannot be sent without a trade id because the thread must include buyer, seller, and escrow.\"\n },\n \"content\": {\n \"type\": \"string\"\n },\n \"message\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_profile_show`\n\nShow profile metadata for the active Hostr account.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks who they are on Hostr, wants their current profile, or before profile/listing publishing when you need existing metadata. This reads the profile for the active Hostr account.\n\nAction id: `hostr.profile.show`\n\n```ts\nexport interface HostrEmptyInput {}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {}\n}\n```\n\n## `hostr_profile_lookup`\n\nPublic read-only lookup for any Hostr/Nostr profile metadata by npub. Use this when the user asks to view a specific user, host, guest, seller, buyer, or arbitrary Nostr profile that is not necessarily their authenticated profile.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks to view a specific public Nostr/Hostr profile by npub, including a host, guest, seller, buyer, or arbitrary profile that is not the authenticated MCP user. This tool is public and does not require sign-in.\n\nAction id: `hostr.profile.lookup`\n\n```ts\nexport interface HostrProfileLookupInput {\n npub: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"npub\"\n ],\n \"properties\": {\n \"npub\": {\n \"type\": \"string\",\n \"description\": \"NIP-19 npub for the profile to display.\"\n }\n }\n}\n```\n\n## `hostr_profile_edit`\n\nPreview or publish the authenticated user profile metadata. Profile image and picture accept durable HTTP(S) image URLs only. For user-uploaded profile photos, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file, then pass structuredContent.usage.image.url as image or picture. Publishing also refreshes Hostr seller configuration.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user wants to update profile name, about/bio, picture, banner, website, lightning address, or other profile metadata. Preview first; publish only after approval. Publishing also refreshes Hostr seller configuration, which is useful before creating or editing listings.\n\nAction id: `hostr.profile.edit`\n\n```ts\nexport interface HostrProfileEditInput {\n name?: string;\n about?: string;\n /** Profile image URL. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. */\n image?: string;\n /** Alias for image. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. */\n picture?: string;\n lud16?: string;\n nip05?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"about\": {\n \"type\": \"string\"\n },\n \"image\": {\n \"type\": \"string\",\n \"description\": \"Profile image URL. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. Do not pass local paths, file:// URLs, ChatGPT upload refs, or base64 data directly.\"\n },\n \"picture\": {\n \"type\": \"string\",\n \"description\": \"Alias for image. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. Do not pass local paths, file:// URLs, ChatGPT upload refs, or base64 data directly.\"\n },\n \"lud16\": {\n \"type\": \"string\"\n },\n \"nip05\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_trips_list`\n\nList reservation groups involving the authenticated user as guest from the live userSubscriptions.myResolvedTripsList replay. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; treat those temporary pubkeys as expected reservation accounts for the active user, not as an identity mismatch. Do not perform fresh reservation-by-author Nostr queries for this view. Return the fixed trip-card display contract with resolved participant profile names. Cancelled trip cards must preserve a bold Cancelled marker. Pass `tradeId` after a book-and-pay swap watch completes or cannot find the swap to wait briefly for the committed public reservation and return it for display.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for guest-side reservations: \"my trips\", \"my bookings as guest\", \"my reservation reference\", \"did my reservation complete\", \"my host has not replied\", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_reservations_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.\n\nAction id: `hostr.trips.list`\n\n```ts\nexport interface HostrReservationCollectionInput {\n limit?: number;\n tradeId?: string;\n waitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id to look up directly after payment/proof completion.\"\n },\n \"waitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 300,\n \"default\": 15,\n \"description\": \"How long to poll for a committed public reservation when tradeId is provided.\"\n }\n }\n}\n```\n\n## `hostr_bookings_list`\n\nList reservation groups where the authenticated user is the host from the live userSubscriptions.myResolvedHostingsList replay. Do not perform fresh Nostr listing/reservation-by-author queries for this view. Return the fixed hosting-card display contract with resolved participant profile names, including \"Hosting {guest} at: {stay}\" text.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for host-side reservations on listings authored by the authenticated user: \"my bookings\", \"who booked my place\", \"hosting reservations\", or host calendar context. Do not use this as the first monitor immediately after a payment-required guest booking; hostr_swaps_watch comes first. Do not perform fresh reservation-by-author Nostr queries for this view.\n\nAction id: `hostr.bookings.list`\n\n```ts\nexport interface HostrReservationCollectionInput {\n limit?: number;\n tradeId?: string;\n waitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id to look up directly after payment/proof completion.\"\n },\n \"waitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 300,\n \"default\": 15,\n \"description\": \"How long to poll for a committed public reservation when tradeId is provided.\"\n }\n }\n}\n```\n\n## `hostr_escrow_methods`\n\nShow mutual escrow methods and compatible services for a seller. If buyer is omitted, the active Hostr account pubkey is used.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse before payment or when explaining how money is protected. It shows mutually compatible escrow methods/services between buyer and seller. If buyer is omitted, the active Hostr account pubkey is used. Explain that Hostr swaps payment over Lightning into smart-contract escrow; the escrow service can only settle by forwarding or reversing according to trade outcome, not freely take custody.\n\nAction id: `hostr.escrow.methods`\n\n```ts\nexport interface HostrEscrowMethodsInput {\n /** Seller/host pubkey to inspect escrow compatibility for. */\n user: string;\n /** Buyer pubkey. Defaults to the active Hostr account pubkey. */\n buyer?: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"user\"\n ],\n \"properties\": {\n \"user\": {\n \"type\": \"string\",\n \"description\": \"Seller/host pubkey to inspect escrow compatibility for.\"\n },\n \"buyer\": {\n \"type\": \"string\",\n \"description\": \"Buyer pubkey. Defaults to the active Hostr account pubkey.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_list`\n\nEscrow-only tool. List public escrow service events published by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator inventory view: list public escrow service events published by the authenticated escrow pubkey. Use before editing/deleting when the user has not selected a specific service event.\n\nAction id: `hostr.escrow.service.list`\n\n```ts\nexport interface HostrEscrowServiceListInput {\n /** Maximum number of escrow service events to return. Defaults to 25, capped at 100. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 100,\n \"default\": 25,\n \"description\": \"Maximum number of escrow services to return.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_get`\n\nEscrow-only tool. Show one public escrow service event owned by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator detail view: inspect one escrow service event before explaining or editing settings. Use serviceId from hostr_escrow_service_list or user input.\n\nAction id: `hostr.escrow.service.get`\n\n```ts\nexport interface HostrEscrowServiceGetInput {\n /** Escrow service event id to inspect. */\n serviceId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"serviceId\"\n ],\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Escrow service event id to inspect.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_edit`\n\nEscrow-only tool. Preview or publish the active escrow account service parameters. Use hostr.profile.edit for the escrow user profile.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator settings workflow: preview changes to fee percent, maximum duration, or token fee hints. Keep dryRun=true until the user approves the exact preview. Use hostr_profile_edit for public profile/identity metadata; this tool only changes escrow service parameters.\n\nAction id: `hostr.escrow.service.edit`\n\n```ts\nexport interface HostrTokenFeeHintsInput {\n /** Flat base fee in token smallest units. */\n baseFee?: number;\n /** Maximum fee cap in token smallest units. Zero means no cap. */\n maxFee?: number;\n /** Minimum fee floor in token smallest units. Zero means no floor. */\n minFee?: number;\n}\n\nexport interface HostrEscrowServiceUpdateInput {\n /** Optional escrow service event id to edit. Omit to edit the daemon bootstrap service. */\n serviceId?: string;\n /** Proportional escrow fee as a percent, e.g. 1.5 for 1.5%. */\n feePercent?: number;\n /** Maximum supported escrow duration in seconds. */\n maxDurationSeconds?: number;\n /** Full replacement map keyed by token address, or \"native\". */\n tokenFeeHints?: Record;\n /** Clear all per-token fee hints. Ignored if tokenFeeHints is provided. */\n clearTokenFeeHints?: boolean;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service event id to edit. Omit to edit the daemon bootstrap service.\"\n },\n \"feePercent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"description\": \"Proportional escrow fee as a percent, e.g. 1.5 for 1.5%.\"\n },\n \"maxDurationSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 315360000,\n \"description\": \"Maximum supported escrow duration in seconds. Omit to preserve the current value.\"\n },\n \"tokenFeeHints\": {\n \"type\": \"object\",\n \"description\": \"Optional full replacement map keyed by token address, or \\\"native\\\". Values are smallest-unit fee hints.\",\n \"additionalProperties\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"baseFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"maxFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"minFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n \"clearTokenFeeHints\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Clear all per-token fee hints. Ignored if tokenFeeHints is provided.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_service_delete`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for an escrow service event owned by the authenticated escrow pubkey. Keep dryRun true until the user explicitly approves deletion.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive workflow: preview deletion of a public escrow service event and require explicit deletion approval before dryRun=false. Include the reason when the user gives one.\n\nAction id: `hostr.escrow.service.delete`\n\n```ts\nexport interface HostrEscrowServiceDeleteInput {\n /** Escrow service event id to delete. */\n serviceId: string;\n /** Optional deletion reason for the NIP-09 event. */\n reason?: string;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"serviceId\"\n ],\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Escrow service event id to delete.\"\n },\n \"reason\": {\n \"type\": \"string\",\n \"description\": \"Optional deletion reason for the NIP-09 event.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_trades_list`\n\nEscrow-only tool. List on-chain Hostr trades where the active Hostr account is a configured escrow. Hidden unless the active account pubkey is in the daemon escrow pubkey allowlist.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator dashboard: list on-chain trades assigned to the authenticated escrow pubkey. Use before viewing/auditing/arbitrating when the user has not named a concrete tradeId.\n\nAction id: `hostr.escrow.trades.list`\n\n```ts\nexport interface HostrEscrowTradesListInput {\n /** Maximum number of escrow trades to return. Defaults to 25, capped at 100. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 100,\n \"default\": 25,\n \"description\": \"Maximum number of escrow trades to return.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_view`\n\nEscrow-only tool. View the on-chain state, event history, and Hostr reservation context for a trade assigned to the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator trade detail: inspect on-chain state, event history, participants, amounts, and reservation context for a trade before audit or arbitration.\n\nAction id: `hostr.escrow.trades.view`\n\n```ts\nexport interface HostrEscrowTradeViewInput {\n /** Hostr reservation trade id to inspect. */\n tradeId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to inspect.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_audit`\n\nEscrow-only tool. Run a structured reservation and transition audit for a Hostr trade assigned to the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator analysis: run a structured audit of reservation state and transitions for a trade before deciding whether arbitration is needed. This does not settle funds.\n\nAction id: `hostr.escrow.trades.audit`\n\n```ts\nexport interface HostrEscrowTradeAuditInput {\n /** Hostr reservation trade id to audit. */\n tradeId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to audit.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_arbitrate`\n\nEscrow-only settlement tool. Preview or execute arbitration for a Hostr escrow trade. paymentForward and bondForward are fractions from 0 to 1. Keep dryRun true until the user explicitly approves the arbitration preview.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator settlement workflow: preview paymentForward and bondForward fractions before execution. Fractions are 0 to 1. Explain the proposed split and reason to the user, then execute with dryRun=false only after explicit approval.\n\nAction id: `hostr.escrow.trades.arbitrate`\n\n```ts\nexport interface HostrEscrowArbitrateInput {\n /** Hostr reservation trade id to arbitrate. */\n tradeId: string;\n /** Fraction of the escrowed payment to forward to the seller, from 0 to 1. */\n paymentForward: number;\n /** Fraction of the escrow bond to forward according to contract settlement rules, from 0 to 1. */\n bondForward: number;\n /** Optional human-readable arbitration reason. */\n reason?: string;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\",\n \"paymentForward\",\n \"bondForward\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to arbitrate.\"\n },\n \"paymentForward\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1,\n \"description\": \"Fraction of the escrowed payment to forward to the seller, from 0 to 1.\"\n },\n \"bondForward\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1,\n \"description\": \"Fraction of the escrow bond to forward according to the contract settlement rules, from 0 to 1.\"\n },\n \"reason\": {\n \"type\": \"string\",\n \"description\": \"Optional human-readable arbitration reason.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_list`\n\nEscrow-only tool. List NIP-58 badge definitions published by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator badge inventory: list NIP-58 badge definitions issued by the authenticated escrow. Use before editing, awarding, or deleting badges when the identifier/anchor is unclear.\n\nAction id: `hostr.escrow.badges.definitions.list`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionsListInput {\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_edit`\n\nEscrow-only tool. Preview or publish a NIP-58 badge definition for the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator badge definition workflow: preview or publish a NIP-58 badge definition. Use for creating or updating the badge name, description, or image. Publish only after approval.\n\nAction id: `hostr.escrow.badges.definitions.edit`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionEditInput {\n /** Badge definition d-tag identifier. */\n identifier: string;\n name: string;\n description?: string;\n image?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"identifier\",\n \"name\"\n ],\n \"properties\": {\n \"identifier\": {\n \"type\": \"string\",\n \"description\": \"Badge definition d-tag identifier.\"\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"description\": {\n \"type\": \"string\"\n },\n \"image\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_delete`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for a badge definition owned by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive badge workflow: preview deletion of a badge definition and publish only after explicit approval. Include a reason when provided.\n\nAction id: `hostr.escrow.badges.definitions.delete`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionDeleteInput {\n anchor: string;\n reason?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"anchor\"\n ],\n \"properties\": {\n \"anchor\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_awards_list`\n\nEscrow-only tool. List NIP-58 badge awards issued by the authenticated escrow pubkey, optionally filtered by definition anchor.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator badge award view: list issued badge awards, optionally filtered by definition anchor. Use before revoking when the award id is unclear.\n\nAction id: `hostr.escrow.badges.awards.list`\n\n```ts\nexport interface HostrEscrowBadgeAwardsListInput {\n definitionAnchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"definitionAnchor\": {\n \"type\": \"string\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_escrow_badges_award`\n\nEscrow-only tool. Preview or publish a NIP-58 badge award from the authenticated escrow pubkey to a recipient pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator award workflow: preview or publish a NIP-58 badge award to a recipient pubkey, optionally tied to a listing anchor. Publish only after approval.\n\nAction id: `hostr.escrow.badges.award`\n\n```ts\nexport interface HostrEscrowBadgeAwardInput {\n definitionAnchor: string;\n recipientPubkey: string;\n listingAnchor?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"definitionAnchor\",\n \"recipientPubkey\"\n ],\n \"properties\": {\n \"definitionAnchor\": {\n \"type\": \"string\"\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"listingAnchor\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_revoke`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for a badge award issued by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive award workflow: preview revocation/deletion of an issued badge award and publish only after explicit approval. Include a reason when provided.\n\nAction id: `hostr.escrow.badges.revoke`\n\n```ts\nexport interface HostrEscrowBadgeRevokeInput {\n awardId: string;\n reason?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"awardId\"\n ],\n \"properties\": {\n \"awardId\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_swaps_watch`\n\nRead-only swap monitor. Inspect a persisted swap-in by id and report payment/proof/reservation state without creating, signing, publishing, or recovering anything. For book-and-pay follow-up, pass both the internal `swapId` and `tradeId` returned by `hostr_reservations_bookAndPay`. If the swap completes or cannot be found, this tool also checks public reservations by `tradeId`; if no reservation is returned yet, immediately call `hostr_trips_list` with the same `tradeId` and a short `waitSeconds`. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; never report that pubkey difference as an identity mismatch. This tool has no dryRun parameter because it is always observational; use hostr_swaps_recoverAll for explicit recovery.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nRead-only monitor to use immediately after hostr_reservations_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.\n\nAction id: `hostr.swaps.watch`\n\n```ts\nexport interface HostrSwapsWatchInput {\n swapId: string;\n tradeId?: string;\n reservationWaitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"swapId\"\n ],\n \"properties\": {\n \"swapId\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id used to fall back to public reservation lookup after the swap completes or is not found.\"\n },\n \"reservationWaitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 60,\n \"default\": 20,\n \"description\": \"How long to poll for the committed reservation after proof completion or swap-not-found fallback. Keep short; capped below MCP client timeouts.\"\n }\n }\n}\n```\n\n## `hostr_swaps_recoverAll`\n\nPreview or run recovery for all persisted swap-in and swap-out operations.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user asks to recover stuck payments/swaps or when diagnostics show persisted swap operations need resumption. Preview first; run with dryRun=false only after approval. Use background=true only when the user wants recovery to continue asynchronously.\n\nAction id: `hostr.swaps.recoverAll`\n\n```ts\nexport interface HostrSwapsRecoverAllInput {\n background?: boolean;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"background\": {\n \"type\": \"boolean\",\n \"default\": false\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_swaps_list`\n\nList persisted swap-in and swap-out operation states.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse to inspect persisted swap-in and swap-out states before recovery/debugging, or when the user asks about payment status, stuck swaps, refunds, or pending Lightning/on-chain operations.\n\nAction id: `hostr.swaps.list`\n\n```ts\nexport interface HostrSwapsListInput {\n namespace?: \"all\" | \"swap_in\" | \"swap_out\";\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"namespace\": {\n \"type\": \"string\",\n \"enum\": [\n \"all\",\n \"swap_in\",\n \"swap_out\"\n ],\n \"default\": \"all\"\n }\n }\n}\n```\n\n"; +export const hostrActionDocumentation = "# Hostr MCP action inputs\n\nAll Hostr MCP tools are backed by typed Dart daemon actions. The MCP access token selects a server-side MCP session; hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout manage the active Hostr account/pubkey for that session. For natural role wording such as guest, host, or escrow, inspect connected accounts, switch to a matching connected account, or connect a new account when needed. Do not assume the currently active account satisfies a requested role merely because it is already authenticated.\n\nDo not run routine preflight session/profile checks before sensitive tools. Call the intended Hostr tool first. If it returns auth_required, call hostr_session_connect, complete sign-in, then retry the original action. If it returns profile_required, collect the missing profile fields, call hostr_profile_edit, publish after approval, then retry the original action.\n\nHostr is also the intended tool surface for Hostr-related Nostr network work: Nostr Connect/NIP-46 sign-in, signer/bunker recovery, NIP events, relays, pubkeys/npubs, naddrs, gift-wrapped messages, inbox threads, and Hostr marketplace events. Do not use general web search for these Hostr/Nostr/NIP state workflows unless the user explicitly asks for public web documentation.\n\nHostr reservation privacy: when Hostr creates or completes a reservation, the public committed reservation, escrow trade, and trade thread may be under Hostr-created per-trade temporary pubkeys rather than the active logged-in account pubkey. This is expected privacy-preserving behavior. Do not tell the user this is an identity mismatch, do not warn that the reservation is not under their pubkey, and do not treat the temporary trade pubkey as a separate logged-in account.\n\nIf the user asks how Hostr works or what happens when they send money, explain that Hostr swaps the payment over Lightning into a smart-contract escrow. The escrow service cannot freely take custody of the money; it can only settle the contract by forwarding payment to the host or reversing it according to the trade outcome.\n\nMost write tools default to preview mode. Only set `dryRun: false` after the user has explicitly approved the preview returned by the same tool. `hostr_orders_bookAndPay` is the correct foreground handoff tool when the user asks to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. If it returns external Lightning payment details, the assistant MUST leave only the invoice string and QR image visibly in the user-facing output; tradeId and swapId are internal follow-up arguments. The next assistant action after rendering the QR and invoice must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. `reservationWaitSeconds` is capped below MCP client timeouts. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\n## Reservation date semantics\n\nReservation `start` and `end` inputs are calendar dates, not timezone-sensitive instants. Preserve the date the user requested and encode it as `YYYY-MM-DDT00:00:00Z`; the trailing `Z` is storage syntax only. Do not convert from user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\n## Workflow playbooks\n\n### New listing workflow\n\nCall `hostr_profile_edit` if profile details need updating, then call `hostr_listings_create` with `dryRun: true`, show the preview, and only call it again with `dryRun: false` after explicit approval. The publish call must reuse the exact `dTag` from the preview result (`structuredContent.nextInput.dTag` or `structuredContent.dTag`) so preview, publish, and retry target the same replaceable listing. The live action ensures seller config is published.\n\n### Edit listing workflow\n\nCall `hostr_listings_edit` with `dryRun: true`, review the returned listing/event preview, then repeat with `dryRun: false` after approval.\n\n### Search and reserve workflow\n\nCall `hostr_listings_search`, then `hostr_listings_availability`. For user phrasing such as \"book\", \"reserve\", \"make me a reservation\", or \"create a reservation\" on an instant-book stay where the amount is at or above the listing price, call `hostr_orders_bookAndPay`. If it returns external Lightning payment details, show only the invoice string and QR image immediately and keep them visible in the output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator. Do not stop after `hostr_orders_negotiateOffer` for this intent. For explicit negotiation-only requests, call `hostr_orders_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM.\n\n### Negotiation workflow\n\nCall `hostr_updates` to inspect thread/trade ids. Use `hostr_orders_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_orders_negotiateAccept` to accept the latest offer, or `hostr_orders_cancel` to cancel the private negotiation or committed reservation.\n\n### Payment workflow\n\nFor normal AI-initiated instant-book payment, use `hostr_orders_bookAndPay`. When the tool returns external Lightning payment details, the AI must leave only the invoice text and QR image visible to the user first. The next assistant action must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion while the daemon continues the book-and-pay operation in the background; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; payment proof publication is owned by the global Hostr payment proof orchestrator. Keep `hostr_orders_pay`, `hostr_orders_commit`, and `hostr_swaps_recoverAll` for manual recovery/debug paths.\n\n### Messaging workflow\n\nCall `hostr_updates`, choose the thread/trade recipient pubkeys, call `hostr_thread_message` with `dryRun: true`, then `dryRun: false` after approval.\n\n### Review workflow\n\nWhen a guest asks to review a trip, identify the trade with `hostr_trips_list`, call `hostr_orders_review` with `dryRun: true`, show the preview, then repeat with `dryRun: false` only after explicit approval. If no committed reservation can be found, skip the review action and explain that the trip is not reviewable yet.\n\n### Swaps workflow\n\nCall `hostr_swaps_list`, then `hostr_swaps_watch` for a specific swap id, and `hostr_swaps_recoverAll` when stale operations need recovery.\n\n## `hostr_session_status`\n\nInspect the active Hostr account for this MCP session.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks whether they are logged in, when debugging auth, or after a Hostr action returns an auth/profile/signature error. Do not call this as a routine preflight before every write; failed tools return structured recovery instructions.\n\nAction id: `hostr.session.status`\n\n```ts\nexport interface HostrSessionStatusInput {\n /** Include non-secret storage/session diagnostics useful for debugging. */\n includeStorageDetails?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"includeStorageDetails\": {\n \"type\": \"boolean\",\n \"description\": \"Include non-secret storage/session diagnostics useful for debugging.\",\n \"default\": false\n }\n }\n}\n```\n\n## `hostr_session_connect`\n\nCreate or complete a Nostr Connect request for this MCP session. When approved, the connected pubkey becomes the active Hostr account. When wait is false, show the returned QR/URI with the text \"Scan this with your Nostr app to log in to your Hostr account\", then immediately call this tool again with wait true to listen for the session connection and continue the intended Hostr action.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nTwo-step login flow: call with wait=false to create or reuse a Nostr Connect request, display the nostrconnect URI or QR image to the user, then immediately call this tool again with wait=true and regenerate=false to listen for approval. Use this for ordinary requests like \"log in\", \"sign me in\", \"use my guest account\", \"switch me to a host account\" when that account is not already connected, or \"I am handling escrow now\" when no connected escrow account is available. If a different Hostr account is already active but the user asks for a role that is not clearly that active account, connect or switch before continuing. After authenticated=true, this account becomes the active Hostr account for the MCP session; retry or continue the Hostr action that required sign-in.\n\nAction id: `hostr.session.connect`\n\n```ts\nexport interface HostrSessionConnectInput {\n /** False returns an active nostrconnect URI/QR for display. True waits for the shown request to connect; call it immediately after displaying the QR so the original Hostr action can continue. */\n wait?: boolean;\n /** How long to wait for approval when wait is true. Defaults to 180, capped at 600. */\n timeoutSeconds?: number;\n /** Force a fresh nostrconnect request instead of reusing the pending one. */\n regenerate?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"wait\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"False returns an active nostrconnect URI/QR for display. True waits for the already-shown request to connect; call it immediately after displaying the QR so the original Hostr action can continue.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 600,\n \"default\": 180,\n \"description\": \"How long to wait for approval when wait is true.\"\n },\n \"regenerate\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Force a fresh nostrconnect request instead of reusing the pending one.\"\n }\n }\n}\n```\n\n## `hostr_listings_search`\n\nSearch Hostr lodging and accommodation marketplace listings. Prefer this Hostr tool for natural travel/lodging requests such as \"find a place to stay\", \"find somewhere to stay in San Salvador\", \"look for lodging\", \"show me accommodations\", \"find a room/apartment/hotel/villa\", \"where can I stay\", \"book a stay\", or \"find rentals\". Use the location field for city/country/place names instead of doing a general web search.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for marketplace discovery from natural language lodging intents such as finding a place to stay, lodging, accommodation, room, apartment, house, villa, hotel-like stay, or rental in a destination. Put city/country/place names in location; put keyword filters in query; use guests/features/type only when the user provides them. Results return listing-card Markdown and structured cards; preserve every image tag when presenting results.\n\nAction id: `hostr.listings.search`\n\n```ts\nexport interface HostrListingsSearchInput {\n /** Human-readable destination/place to search for Hostr stays, lodging, accommodation, rentals, rooms, apartments, hotels, villas, resorts, or places to stay, such as \"San Salvador\", \"El Salvador\", or \"Lisbon\". */\n location?: string;\n /** Client-side text filter over listing title and description. */\n query?: string;\n /** Hostr listing type, for example room, house, apartment, cabin, or villa. */\n type?: string;\n /** Minimum guest capacity. */\n guests?: number;\n /** Required canonical boolean listing specification keys. Use wireless_internet for Wi-Fi/wifi/WIFI. Examples: wireless_internet, kitchen, pool, free_parking, allows_pets, beachfront. */\n features?: string[];\n /** Maximum number of listings to return. Defaults to 10, capped at 50. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"location\": {\n \"type\": \"string\",\n \"description\": \"Human-readable destination/place to search for Hostr stays, lodging, accommodation, rentals, rooms, apartments, hotels, villas, resorts, or places to stay, such as \\\"San Salvador\\\", \\\"El Salvador\\\", or \\\"Lisbon\\\".\"\n },\n \"query\": {\n \"type\": \"string\",\n \"description\": \"Client-side text filter over listing title and description.\"\n },\n \"type\": {\n \"type\": \"string\",\n \"description\": \"Hostr listing type, for example room, house, apartment, cabin, or villa.\"\n },\n \"guests\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Minimum guest capacity.\"\n },\n \"features\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Required canonical boolean listing specification keys. Use wireless_internet for Wi-Fi/wifi/WIFI. Examples: wireless_internet, kitchen, pool, free_parking, allows_pets, beachfront.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 50,\n \"default\": 10,\n \"description\": \"Maximum number of listings to return.\"\n }\n }\n}\n```\n\n## `hostr_listings_list`\n\nList Hostr listings, optionally restricted to the authenticated user or a supplied author pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for inventory/management views: \"my listings\", \"what am I hosting\", \"show my stays\", or listings by a known author pubkey. Use mine=true for the authenticated user. Use author only when the user provides or selected a specific pubkey.\n\nAction id: `hostr.listings.list`\n\n```ts\nexport interface HostrListingsListInput {\n mine?: boolean;\n author?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"mine\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Only list listings authored by the authenticated user.\"\n },\n \"author\": {\n \"type\": \"string\",\n \"description\": \"Only list listings authored by this pubkey.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_listings_create`\n\nCreate a Hostr listing for the active Hostr account. Listing images must be passed as images[].url. For user-uploaded files, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST the original image bytes to /mcp/uploads/images on the same Hostr MCP origin using multipart/form-data field name file, then pass the returned upload.url as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the active account Blossom upload path before falling back to direct upload. Do not base64-encode user-uploaded images into this MCP tool call, do not serve temporary localhost URLs, and do not pass /mnt/data or file:// paths to images[].url. Set dryRun false only after explicit user approval to publish the listing event, and reuse the dryRun preview dTag so retries update the same replaceable listing.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the authenticated user wants to create, publish, list, rent out, or host a room/place/stay. Collect title, description, address, at least one image URL, and at least one price before calling. The first image is the card/hero image. This MCP tool accepts image URLs only. For ChatGPT web/mobile, local development clients, or any remote MCP client with uploaded files, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST the original image bytes to /mcp/uploads/images on the same Hostr MCP origin using multipart/form-data field name file, then pass the returned upload.url as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the logged-in session Blossom upload path before falling back to direct upload. Do not base64-encode the uploaded image into this MCP tool call. Do not serve a temporary localhost URL for Hostr to fetch; localhost refers to the wrong machine/container. If neither upload route can be used, stop and ask for a public image URL or for the client to expose an upload capability. Do not resize, downscale, crop, recompress, transcode, or make thumbnails unless the user explicitly requests it. Never pass a local or mounted sandbox path such as /mnt/data, /mnt/shared, file://, or a ChatGPT file mount to images[].url. Use dryRun=true to upload/stage media and return the visual listing preview. When publishing the approved preview, call this tool again with dryRun=false and reuse the exact dTag from structuredContent.nextInput or structuredContent.dTag so preview, publish, and any retry update the same replaceable listing. The live path also ensures seller configuration is published.\n\nAction id: `hostr.listings.create`\n\n```ts\nexport interface HostrAmountInput {\n /** Payment amount as a decimal string. If unit is sats, this is a satoshi count: 1 sat = 1/100,000,000 BTC. */\n value: string;\n /** Currency or denomination, such as USD or BTC. For sats, use BTC. */\n currency: string;\n /** Optional display/base unit. sats means satoshis: 1 sat = 1/100,000,000 BTC. */\n unit?: string;\n /** Optional decimal precision. For sats, use 0. */\n decimals?: number;\n}\n\nexport interface HostrListingImageInput {\n /** Required image URL. For user-uploaded files, use the upload.url returned by POST /mcp/uploads/images on the same Hostr MCP origin. */\n url: string;\n /** Optional original filename used for MIME detection and upload diagnostics. */\n filename?: string;\n /** Alt text for the image. */\n alt?: string;\n /** Optional MIME type override. */\n mime?: string;\n}\n\nexport interface HostrListingPriceInput {\n amount: HostrAmountInput;\n /** daily, weekly, monthly, yearly, or fixed. Defaults to daily. */\n frequency?: string;\n}\n\nexport interface HostrListingSpecificationsInput {\n /** Maximum guests. Prefer max_guests inside specifications; top-level guests is also accepted on create/edit and maps to max_guests. */\n max_guests?: number;\n beds?: number;\n bedrooms?: number;\n bathrooms?: number;\n bathtub?: number;\n tv?: number;\n airconditioning?: boolean;\n allows_pets?: boolean;\n crib?: boolean;\n tumble_dryer?: boolean;\n washer?: boolean;\n elevator?: boolean;\n free_parking?: boolean;\n gym?: boolean;\n hair_dryer?: boolean;\n heating?: boolean;\n high_chair?: boolean;\n /** Wi-Fi/wifi/WIFI must use this canonical key. */\n wireless_internet?: boolean;\n iron?: boolean;\n jacuzzi?: boolean;\n kitchen?: boolean;\n outlet_covers?: boolean;\n pool?: boolean;\n private_entrance?: boolean;\n smoking_allowed?: boolean;\n breakfast?: boolean;\n fireplace?: boolean;\n smoke_detector?: boolean;\n essentials?: boolean;\n shampoo?: boolean;\n infants_allowed?: boolean;\n children_allowed?: boolean;\n hangers?: boolean;\n flat_smooth_pathway_to_front_door?: boolean;\n grab_rails_in_shower_and_toilet?: boolean;\n oven?: boolean;\n bbq?: boolean;\n balcony?: boolean;\n patio?: boolean;\n dishwasher?: boolean;\n refrigerator?: boolean;\n garden_or_backyard?: boolean;\n microwave?: boolean;\n coffee_maker?: boolean;\n dishes_and_silverware?: boolean;\n stove?: boolean;\n fire_extinguisher?: boolean;\n carbon_monoxide_detector?: boolean;\n luggage_dropoff_allowed?: boolean;\n beach_essentials?: boolean;\n beachfront?: boolean;\n baby_monitor?: boolean;\n babysitter_recommendations?: boolean;\n childrens_books_and_toys?: boolean;\n game_console?: boolean;\n street_parking?: boolean;\n paid_parking?: boolean;\n hot_water?: boolean;\n lake_access?: boolean;\n single_level_home?: boolean;\n waterfront?: boolean;\n first_aid_kit?: boolean;\n handheld_shower_head?: boolean;\n home_step_free_access?: boolean;\n lock_on_bedroom_door?: boolean;\n mobile_hoist?: boolean;\n path_to_entrance_lit_at_night?: boolean;\n pool_hoist?: boolean;\n ev_charger?: boolean;\n rollin_shower?: boolean;\n shower_chair?: boolean;\n tub_with_shower_bench?: boolean;\n wide_clearance_to_bed?: boolean;\n wide_clearance_to_shower_and_toilet?: boolean;\n wide_hallway_clearance?: boolean;\n baby_bath?: boolean;\n changing_table?: boolean;\n room_darkening_shades?: boolean;\n stair_gates?: boolean;\n table_corner_guards?: boolean;\n extra_pillows_and_blankets?: boolean;\n ski_in_ski_out?: boolean;\n window_guards?: boolean;\n disabled_parking_spot?: boolean;\n grab_rails_in_toilet?: boolean;\n events_allowed?: boolean;\n common_spaces_shared?: boolean;\n bathroom_shared?: boolean;\n security_cameras?: boolean;\n}\n\nexport interface HostrListingsCreateInput {\n title: string;\n description: string;\n /** Precise address used for H3 tag generation. */\n address: string;\n images: HostrListingImageInput[];\n prices: HostrListingPriceInput[];\n type?: string;\n /** Canonical listing specifications/amenities map. Use wireless_internet for Wi-Fi/wifi/WIFI; do not use wifi or WIFI. */\n specifications?: HostrListingSpecificationsInput;\n guests?: number;\n beds?: number;\n bedrooms?: number;\n bathrooms?: number;\n active?: boolean;\n negotiable?: boolean;\n instantBook?: boolean;\n minStay?: number;\n checkIn?: string;\n checkOut?: string;\n quantity?: number;\n securityDeposit?: HostrAmountInput;\n minPaymentAmount?: HostrAmountInput;\n h3Tags?: string[];\n h3FinestResolution?: number;\n h3MaxTags?: number;\n /** Stable Nostr d tag for this listing draft. Reuse the dryRun preview dTag when publishing so retries update the same replaceable listing. */\n dTag?: string;\n /** True uploads local images to Blossom and previews only. Set false to publish after explicit user approval, reusing the preview dTag. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"title\",\n \"description\",\n \"address\",\n \"images\",\n \"prices\"\n ],\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"description\": \"Public listing title.\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Public listing description.\"\n },\n \"address\": {\n \"type\": \"string\",\n \"description\": \"Private-ish precise address used by Hostr to generate H3 tags.\"\n },\n \"type\": {\n \"type\": \"string\",\n \"description\": \"Listing type, such as room, apartment, house, or villa.\"\n },\n \"images\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"description\": \"Listing images. This MCP tool accepts image URLs only. Mandatory flow for user-uploaded files: first call hostr_images_upload with the original image sent as the MCP file-typed argument named file so the client bridge can rewrite or stream the bytes, then pass structuredContent.usage.image.url here as images[].url. If the client cannot call hostr_images_upload but can make raw HTTP requests, POST each original file bytes payload to /mcp/uploads/images on this same MCP server origin using multipart/form-data field name file, then pass the returned upload.url here as images[].url. The upload tool and endpoint do not require authorization, but when a valid MCP bearer token is present Hostr first tries the logged-in session Blossom upload path before falling back to direct upload. Do not base64-encode uploaded images into this tool call. Do not start or serve a temporary localhost URL for the MCP server to fetch; localhost refers to the wrong machine/container. Do not resize, downscale, crop, recompress, transcode, or make thumbnails unless the user explicitly requests it. If neither upload route can be used, stop and ask for a public image URL or for the client to expose an upload capability. Never pass client-local or mounted file paths like /mnt/data, /mnt/shared, file://, or ChatGPT file mounts to images[].url.\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"url\"\n ],\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"description\": \"Required image URL. For user-uploaded files, this must be structuredContent.usage.image.url returned by hostr_images_upload, or upload.url returned by POST /mcp/uploads/images on the same Hostr MCP origin. Public HTTP(S) source URLs are also accepted; Hostr downloads non-Blossom URLs and uploads them to Blossom before publishing.\"\n },\n \"filename\": {\n \"type\": \"string\",\n \"description\": \"Optional original filename used for MIME detection and upload diagnostics.\"\n },\n \"alt\": {\n \"type\": \"string\",\n \"description\": \"Image alt text.\"\n },\n \"mime\": {\n \"type\": \"string\",\n \"description\": \"Optional MIME type, for example image/jpeg or image/png.\"\n }\n }\n }\n },\n \"prices\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"description\": \"Listing prices. All monetary fields must use the same currency. If a user mentions sats, they mean satoshis: 1 sat = 1/100,000,000 BTC. Represent bitcoin satoshi prices as amount.value equal to the satoshi count, amount.currency BTC, amount.unit sats, and amount.decimals 0.\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"amount\"\n ],\n \"properties\": {\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"frequency\": {\n \"type\": \"string\",\n \"description\": \"daily, weekly, monthly, yearly, or fixed.\"\n }\n }\n }\n },\n \"specifications\": {\n \"type\": \"object\",\n \"description\": \"Listing specifications/amenities map for hostr_listings_create and patch.specifications on hostr_listings_edit. Use canonical snake_case keys, not display labels or arbitrary amenity names. Wi-Fi/wifi/WIFI must be sent as wireless_internet. Boolean keys use true when present; false/null values are ignored by listing tag serialization. Numeric keys use positive integers. Numeric keys: max_guests, beds, bedrooms, bathrooms, bathtub, tv. Boolean keys: airconditioning, allows_pets, crib, tumble_dryer, washer, elevator, free_parking, gym, hair_dryer, heating, high_chair, wireless_internet, iron, jacuzzi, kitchen, outlet_covers, pool, private_entrance, smoking_allowed, breakfast, fireplace, smoke_detector, essentials, shampoo, infants_allowed, children_allowed, hangers, flat_smooth_pathway_to_front_door, grab_rails_in_shower_and_toilet, oven, bbq, balcony, patio, dishwasher, refrigerator, garden_or_backyard, microwave, coffee_maker, dishes_and_silverware, stove, fire_extinguisher, carbon_monoxide_detector, luggage_dropoff_allowed, beach_essentials, beachfront, baby_monitor, babysitter_recommendations, childrens_books_and_toys, game_console, street_parking, paid_parking, hot_water, lake_access, single_level_home, waterfront, first_aid_kit, handheld_shower_head, home_step_free_access, lock_on_bedroom_door, mobile_hoist, path_to_entrance_lit_at_night, pool_hoist, ev_charger, rollin_shower, shower_chair, tub_with_shower_bench, wide_clearance_to_bed, wide_clearance_to_shower_and_toilet, wide_hallway_clearance, baby_bath, changing_table, room_darkening_shades, stair_gates, table_corner_guards, extra_pillows_and_blankets, ski_in_ski_out, window_guards, disabled_parking_spot, grab_rails_in_toilet, events_allowed, common_spaces_shared, bathroom_shared, security_cameras.\"\n },\n \"guests\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"beds\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"bedrooms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"bathrooms\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"active\": {\n \"type\": \"boolean\"\n },\n \"negotiable\": {\n \"type\": \"boolean\"\n },\n \"instantBook\": {\n \"type\": \"boolean\"\n },\n \"minStay\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"checkIn\": {\n \"type\": \"string\"\n },\n \"checkOut\": {\n \"type\": \"string\"\n },\n \"quantity\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"securityDeposit\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"minPaymentAmount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"h3Tags\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Optional precomputed H3 tags. If omitted, address is geocoded.\"\n },\n \"h3FinestResolution\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"h3MaxTags\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"dTag\": {\n \"type\": \"string\",\n \"description\": \"Stable Nostr d tag for this listing draft. When publishing an approved dryRun preview, reuse the dTag returned in structuredContent.nextInput.dTag or structuredContent.dTag so retries update the same replaceable listing instead of creating duplicates.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True uploads local images to Blossom and previews the listing card only. Set false to publish after explicit approval, reusing the preview dTag.\"\n }\n }\n}\n```\n\n## `hostr_listings_edit`\n\nPreview or publish a patch to an existing listing authored by the authenticated user. The live path also ensures seller configuration is published before signing the listing.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the authenticated author wants to update an existing listing. If the user has not named a concrete listing anchor, first call hostr_listings_list with mine=true and ask/choose from the returned listings. Patch only fields the user intends to change; preview with dryRun=true and publish with dryRun=false only after approval.\n\nAction id: `hostr.listings.edit`\n\n```ts\nexport interface HostrListingsEditInput {\n /** Listing naddr/a-tag anchor. */\n anchor: string;\n /** Listing fields to change. */\n patch?: Partial;\n /** True previews only. Set false to publish after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"anchor\"\n ],\n \"properties\": {\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor.\"\n },\n \"patch\": {\n \"type\": \"object\",\n \"description\": \"Listing fields to change. Supports title, description, address, type, images, prices, specifications, guests, beds, bedrooms, bathrooms, active, negotiable, instantBook, quantity, securityDeposit, and minPaymentAmount. patch.specifications uses the same canonical listing specifications/amenities map as hostr_listings_create; use wireless_internet for Wi-Fi/wifi/WIFI.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True previews only. Set false to publish after explicit approval.\"\n }\n }\n}\n```\n\n## `hostr_listings_availability`\n\nCheck whether one or more listings are available for a requested reservation date range. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nUse after a user has selected one or more listings and supplied dates, before booking or explaining date conflicts. Pass listing anchors from search/list results. If dates are missing, ask for them instead of guessing.\n\nAction id: `hostr.listings.availability`\n\n```ts\nexport interface HostrListingsAvailabilityInput {\n /** Listing anchors to check. */\n anchors?: string[];\n /** Single listing anchor alternative. */\n anchor?: string;\n /** Requested start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start: string;\n /** Requested end calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"start\",\n \"end\"\n ],\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors to check.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor alternative to anchors.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Requested start calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Requested end calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n }\n }\n}\n```\n\n## `hostr_listings_reviews`\n\nFetch review events attached to one or more listings.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks about reviews, reputation, prior guest feedback, or trust signals for one or more listings. Pass listing anchors from search/list results.\n\nAction id: `hostr.listings.reviews`\n\n```ts\nexport interface HostrListingsAnchorsInput {\n anchors?: string[];\n anchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_listings_orderGroups`\n\nFetch public reservation groups for one or more listings. Use this before availability-sensitive reservation workflows when the agent needs to explain conflicts.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks why dates are unavailable, wants booking history/conflicts for a listing, or needs reservation context before changing availability-sensitive plans.\n\nAction id: `hostr.listings.orderGroups`\n\n```ts\nexport interface HostrListingsAnchorsInput {\n anchors?: string[];\n anchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"anchors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"Listing anchors.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor.\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_orders_bookAndPay`\n\nUse this foreground handoff tool whenever the user says to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. It creates the private reservation offer and escrow funding swap. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time. Reservation privacy: Hostr intentionally publishes committed reservations and escrow trades under Hostr-created per-trade temporary pubkeys rather than the active account pubkey. This is normal and preserves user privacy; never present a different reservation buyer pubkey as an identity mismatch. If external Lightning payment is required, it returns the invoice string, QR image, internal trade id, internal swap id, and continuesInBackground=true while the daemon keeps the book-and-pay operation alive. CRITICAL UI REQUIREMENT: leave only the QR image and invoice text visibly in the answer to the user; do not show internal trade id or swap id in the payment prompt, and do not replace the payment prompt with a summary. The next assistant action after rendering that visible payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. The returned `reservationWaitSeconds` is short and capped below MCP client timeouts; do not substitute a longer proof timeout. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, query `hostr_trips_list` with `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nPrimary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_orders_commit for this normal path; proof publication is owned by the global payment proof orchestrator.\n\nAction id: `hostr.orders.bookAndPay`\n\n```ts\nexport interface HostrOrderBookAndPayInput {\n /** Listing naddr/a-tag anchor to instant-book. */\n listingAnchor: string;\n /** Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start: string;\n /** Reservation end calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end: string;\n /** Optional reservation amount override. Must be at or above the listing price. */\n amount?: HostrAmountInput;\n /** Optional escrow service id/pubkey/contract address. */\n escrowServiceId?: string;\n /** Seconds to wait for the global reservation stream to emit the committed reservation. */\n proofTimeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"listingAnchor\",\n \"start\",\n \"end\"\n ],\n \"properties\": {\n \"listingAnchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor to instant-book.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation end calendar date encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n },\n \"description\": \"Optional reservation amount override. Must be at or above the listing price.\"\n },\n \"escrowServiceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service id/pubkey/contract address. Omit to use the first compatible mutual escrow.\"\n },\n \"proofTimeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 30,\n \"maximum\": 3600,\n \"default\": 300,\n \"description\": \"Seconds to wait for the global reservation stream to emit the committed reservation after swap completion.\"\n }\n }\n}\n```\n\n## `hostr_orders_negotiateOffer`\n\nCreate only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like \"book\", \"reserve\", \"make a reservation\", or instant-book at the listed price; those must use hostr_orders_bookAndPay instead.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nNegotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward \"book/reserve\" intents on instant-book listings; use hostr_orders_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.\n\nAction id: `hostr.orders.negotiateOffer`\n\n```ts\nexport interface HostrAmountInput {\n /** Payment amount as a decimal string. If unit is sats, this is a satoshi count: 1 sat = 1/100,000,000 BTC. */\n value: string;\n /** Currency or denomination, such as USD or BTC. For sats, use BTC. */\n currency: string;\n /** Optional display/base unit. sats means satoshis: 1 sat = 1/100,000,000 BTC. */\n unit?: string;\n /** Optional decimal precision. For sats, use 0. */\n decimals?: number;\n}\n\nexport interface HostrOrdersOfferInput {\n /** Listing naddr/a-tag anchor for a first offer. */\n listingAnchor?: string;\n /** Single listing anchor alternative to listingAnchor. */\n anchor?: string;\n /** Existing reservation trade id for a follow-up offer. */\n tradeId?: string;\n /** Reservation start calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n start?: string;\n /** Reservation end calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */\n end?: string;\n /** Optional reservation amount override. Omit to use listing price rules. */\n amount?: HostrAmountInput;\n /** True previews only. Set false to send the gift-wrapped offer after user approval. */\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"listingAnchor\": {\n \"type\": \"string\",\n \"description\": \"Listing naddr/a-tag anchor for a first offer.\"\n },\n \"anchor\": {\n \"type\": \"string\",\n \"description\": \"Single listing anchor alternative to listingAnchor.\"\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Existing reservation trade id for a follow-up offer.\"\n },\n \"start\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation start calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"end\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"Reservation end calendar date for a first offer, encoded as YYYY-MM-DDT00:00:00Z. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time.\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n },\n \"description\": \"Optional reservation amount override. Omit to use listing price rules.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True only builds the offer and returns the event preview. Set false to send the gift-wrapped offer after explicit approval.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_orders_negotiateAccept`\n\nAccept the latest private negotiate-stage reservation offer in a trade thread by replying with a matching negotiate-stage event.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user wants to accept the latest private negotiated offer in a known trade thread. If tradeId is unknown, call hostr_updates, hostr_thread_view, hostr_trips_list, or hostr_bookings_list first to identify the trade.\n\nAction id: `hostr.orders.negotiateAccept`\n\n```ts\nexport interface HostrOrderTradeInput {\n tradeId: string;\n amount?: HostrAmountInput;\n reason?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_orders_pay`\n\nPreview or create the escrow funding swap for a payable reservation trade. The live action sends the escrow selection into the private thread as an unsigned child event, prepares the escrow fund calls, creates the Boltz swap invoice, and persists the payment context for commit.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_orders_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.\n\nAction id: `hostr.orders.pay`\n\n```ts\nexport interface HostrOrderPayInput {\n /** Reservation trade id from negotiation updates. */\n tradeId: string;\n /** Optional escrow service id/pubkey/contract address. */\n escrowServiceId?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Reservation trade id from negotiation updates.\"\n },\n \"escrowServiceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service id/pubkey/contract address. Omit to use the first compatible mutual escrow.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_orders_commit`\n\nPreview or publish the public commit-stage reservation after the escrow funding swap has completed and produced a claim transaction proof.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug commit flow only. Do not use after hostr_orders_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.\n\nAction id: `hostr.orders.commit`\n\n```ts\nexport interface HostrOrderCommitInput {\n /** Boltz swap id returned by hostr_orders_pay. */\n swapId: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"swapId\"\n ],\n \"properties\": {\n \"swapId\": {\n \"type\": \"string\",\n \"description\": \"Boltz swap id returned by hostr_orders_pay.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_orders_cancel`\n\nCancel either the private negotiate-stage reservation for a trade, or the committed public reservation if one exists.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse to cancel a private negotiation or committed reservation for a concrete trade. If tradeId is unclear, inspect updates, trips, bookings, or thread view first. Preview the cancellation and send with dryRun=false only after explicit approval.\n\nAction id: `hostr.orders.cancel`\n\n```ts\nexport interface HostrOrderTradeInput {\n tradeId: string;\n amount?: HostrAmountInput;\n reason?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"amount\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"value\",\n \"currency\"\n ],\n \"properties\": {\n \"value\": {\n \"type\": \"string\",\n \"description\": \"Payment amount as a decimal string to avoid precision loss. If unit is sats, this value is a satoshi count, where 1 sat = 1/100,000,000 BTC.\"\n },\n \"currency\": {\n \"type\": \"string\",\n \"description\": \"Currency or denomination, such as USD or BTC. For bitcoin amounts expressed in sats, use currency BTC with unit sats.\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"description\": \"Optional display/base unit. When unit is sats, sats means satoshis: 1 sat = 1/100,000,000 BTC. Do not interpret sats as whole BTC, cents, dollars, or any fiat subunit.\"\n },\n \"decimals\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Optional decimal precision for raw-denomination amounts. For unit sats, use decimals 0 because satoshis are already the smallest bitcoin unit.\"\n }\n }\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_orders_review`\n\nPreview or publish a guest review for a committed Hostr reservation. This creates a Nostr review event with a participation proof for the reservation trade; preview first and only publish after explicit approval.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the guest wants to leave a rating/review for a completed or confirmed Hostr trip. If tradeId is unclear, inspect hostr_trips_list first. Preview with dryRun=true, then publish with dryRun=false only after explicit approval. Skip this action if no committed reservation can be found for the trade.\n\nAction id: `hostr.orders.review`\n\n```ts\nexport interface HostrOrderReviewInput {\n /** Reservation trade id for the trip to review. */\n tradeId: string;\n /** Guest rating from 1 to 5. */\n rating: number;\n /** Public review text to publish. */\n content: string;\n /** True previews only. Set false to publish the review after user approval. */\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\",\n \"rating\",\n \"content\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Reservation trade id for the trip to review.\"\n },\n \"rating\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 5,\n \"description\": \"Guest rating from 1 to 5.\"\n },\n \"content\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Public review text to publish.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true,\n \"description\": \"True builds and verifies the review preview. Set false only after explicit approval.\"\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 15\n }\n }\n}\n```\n\n## `hostr_updates`\n\nFetch the authenticated inbox, process gift-wrapped thread events, and summarize new offers and messages for the agent.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse as the inbox/home-state tool when the user asks for messages, offers, notifications, reviews, trips, bookings, reservation references, latest activity, \"what are my updates\", \"my host has not replied\", or what needs attention. It processes gift-wrapped inbox events and returns thread cards, reviews left on the user's listings, trips the user booked, and hosting reservations. Present displayMarkdown, not raw event JSON.\n\nAction id: `hostr.updates`\n\n```ts\nexport interface HostrUpdatesInput {\n /** Maximum inbox events to fetch. */\n limit?: number;\n /** Seconds to wait for relay history before returning partial results. */\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 50,\n \"default\": 10\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_thread_view`\n\nLoad a Hostr conversation and return a fixed thread-view contract with message history. Use this when the user asks whether a host or escrow has messaged them, asks to see a conversation, or references a trip/booking thread.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks to see a conversation, asks whether someone messaged them, references a trip/booking thread, or you need message history before replying. Prefer tradeId when the conversation is tied to a reservation; otherwise pass a known thread/conversation anchor from updates.\n\nAction id: `hostr.thread.view`\n\n```ts\nexport interface HostrThreadViewInput {\n threadAnchor?: string;\n anchor?: string;\n conversation?: string;\n tradeId?: string;\n recipientPubkeys?: string[];\n recipientPubkey?: string;\n limit?: number;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"threadAnchor\": {\n \"type\": \"string\"\n },\n \"anchor\": {\n \"type\": \"string\"\n },\n \"conversation\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"recipientPubkeys\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_thread_message`\n\nPreview or send a text message in a Hostr conversation, then return the fixed thread-view contract. Use this when the user asks to message a host, guest, buyer, seller, or an existing thread. If the user references a trade/trip, pass tradeId; use recipientRole when they say host, guest, buyer, seller, or escrow. Escrow messaging always requires a concrete tradeId and must include the trade buyer, seller, and escrow participants in one thread.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user asks to message a host, guest, buyer, seller, escrow, or existing Hostr thread. If they reference a trip/booking/trade, pass tradeId. Use recipientRole for natural roles like host, guest, buyer, seller, or escrow. Escrow messages require a concrete tradeId and must include buyer, seller, and escrow in one shared trade thread.\n\nAction id: `hostr.thread.message`\n\n```ts\nexport interface HostrThreadMessageInput {\n content: string;\n threadAnchor?: string;\n anchor?: string;\n conversation?: string;\n tradeId?: string;\n recipientRole?: \"host\" | \"seller\" | \"guest\" | \"buyer\" | \"escrow\";\n role?: string;\n recipientPubkeys?: string[];\n recipientPubkey?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"content\"\n ],\n \"properties\": {\n \"content\": {\n \"type\": \"string\"\n },\n \"threadAnchor\": {\n \"type\": \"string\"\n },\n \"anchor\": {\n \"type\": \"string\"\n },\n \"conversation\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\"\n },\n \"recipientRole\": {\n \"type\": \"string\",\n \"enum\": [\n \"host\",\n \"seller\",\n \"guest\",\n \"buyer\",\n \"escrow\"\n ]\n },\n \"role\": {\n \"type\": \"string\"\n },\n \"recipientPubkeys\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_escrow_involve`\n\nOpen or message the escrow conversation for a specific reservation trade, then return the fixed thread-view contract. This action always requires tradeId and always resolves the trade buyer, seller, and escrow participants into one shared trade thread; it must not create an escrow-only side conversation. If content is omitted, show the escrow trade thread and ask the user what to message the escrow. If content is provided, preview by default and send only with dryRun false.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user explicitly asks to involve/message escrow for a specific reservation trade. Always pass tradeId. This opens the shared buyer/seller/escrow trade thread; never create an escrow-only side conversation. If no message content is provided, show the thread and ask what to send.\n\nAction id: `hostr.escrow.involve`\n\n```ts\nexport interface HostrEscrowInvolveInput {\n tradeId: string;\n content?: string;\n message?: string;\n dryRun?: boolean;\n timeoutSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Required reservation trade id. Escrow messages cannot be sent without a trade id because the thread must include buyer, seller, and escrow.\"\n },\n \"content\": {\n \"type\": \"string\"\n },\n \"message\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"timeoutSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 60,\n \"default\": 12\n }\n }\n}\n```\n\n## `hostr_profile_show`\n\nShow profile metadata for the active Hostr account.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks who they are on Hostr, wants their current profile, or before profile/listing publishing when you need existing metadata. This reads the profile for the active Hostr account.\n\nAction id: `hostr.profile.show`\n\n```ts\nexport interface HostrEmptyInput {}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {}\n}\n```\n\n## `hostr_profile_lookup`\n\nPublic read-only lookup for any Hostr/Nostr profile metadata by npub or 64-character hex pubkey. Use this when the user asks to view a specific user, host, guest, seller, buyer, or arbitrary Nostr profile that is not necessarily their authenticated profile.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks to view a specific public Nostr/Hostr profile by npub or pubkey, including a host, guest, seller, buyer, or arbitrary profile that is not the authenticated MCP user. This tool is public and does not require sign-in.\n\nAction id: `hostr.profile.lookup`\n\n```ts\nexport interface HostrProfileLookupInput {\n npub: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"npub\"\n ],\n \"properties\": {\n \"npub\": {\n \"type\": \"string\",\n \"description\": \"NIP-19 npub or 64-character hex pubkey for the profile to display.\"\n }\n }\n}\n```\n\n## `hostr_profile_edit`\n\nPreview or publish the authenticated user profile metadata. Profile image and picture accept durable HTTP(S) image URLs only. For user-uploaded profile photos, first call hostr_images_upload with the original image sent as the MCP file-typed argument named file, then pass structuredContent.usage.image.url as image or picture. Publishing also refreshes Hostr seller configuration.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user wants to update profile name, about/bio, picture, banner, website, lightning address, or other profile metadata. Preview first; publish only after approval. Publishing also refreshes Hostr seller configuration, which is useful before creating or editing listings.\n\nAction id: `hostr.profile.edit`\n\n```ts\nexport interface HostrProfileEditInput {\n name?: string;\n about?: string;\n /** Profile image URL. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. */\n image?: string;\n /** Alias for image. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. */\n picture?: string;\n lud16?: string;\n nip05?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"about\": {\n \"type\": \"string\"\n },\n \"image\": {\n \"type\": \"string\",\n \"description\": \"Profile image URL. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. Do not pass local paths, file:// URLs, ChatGPT upload refs, or base64 data directly.\"\n },\n \"picture\": {\n \"type\": \"string\",\n \"description\": \"Alias for image. For user-uploaded files, first call hostr_images_upload and pass structuredContent.usage.image.url here. Do not pass local paths, file:// URLs, ChatGPT upload refs, or base64 data directly.\"\n },\n \"lud16\": {\n \"type\": \"string\"\n },\n \"nip05\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_trips_list`\n\nList reservation groups involving the authenticated user as guest from the live userSubscriptions.myResolvedTripsList replay. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; treat those temporary pubkeys as expected reservation accounts for the active user, not as an identity mismatch. Do not perform fresh reservation-by-author Nostr queries for this view. Return the fixed trip-card display contract with resolved participant profile names. Cancelled trip cards must preserve a bold Cancelled marker. Pass `tradeId` after a book-and-pay swap watch completes or cannot find the swap to wait briefly for the committed public reservation and return it for display.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for guest-side reservations: \"my trips\", \"my bookings as guest\", \"my reservation reference\", \"did my reservation complete\", \"my host has not replied\", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_orders_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.\n\nAction id: `hostr.trips.list`\n\n```ts\nexport interface HostrOrderCollectionInput {\n limit?: number;\n tradeId?: string;\n waitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id to look up directly after payment/proof completion.\"\n },\n \"waitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 300,\n \"default\": 15,\n \"description\": \"How long to poll for a committed public reservation when tradeId is provided.\"\n }\n }\n}\n```\n\n## `hostr_bookings_list`\n\nList reservation groups where the authenticated user is the host from the live userSubscriptions.myResolvedHostingsList replay. Do not perform fresh Nostr listing/reservation-by-author queries for this view. Return the fixed hosting-card display contract with resolved participant profile names, including \"Hosting {guest} at: {stay}\" text.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for host-side reservations on listings authored by the authenticated user: \"my bookings\", \"who booked my place\", \"hosting reservations\", or host calendar context. Do not use this as the first monitor immediately after a payment-required guest booking; hostr_swaps_watch comes first. Do not perform fresh reservation-by-author Nostr queries for this view.\n\nAction id: `hostr.bookings.list`\n\n```ts\nexport interface HostrOrderCollectionInput {\n limit?: number;\n tradeId?: string;\n waitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id to look up directly after payment/proof completion.\"\n },\n \"waitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 300,\n \"default\": 15,\n \"description\": \"How long to poll for a committed public reservation when tradeId is provided.\"\n }\n }\n}\n```\n\n## `hostr_escrow_methods`\n\nShow mutual escrow methods and compatible services for a seller. If buyer is omitted, the active Hostr account pubkey is used.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse before payment or when explaining how money is protected. It shows mutually compatible escrow methods/services between buyer and seller. If buyer is omitted, the active Hostr account pubkey is used. Explain that Hostr swaps payment over Lightning into smart-contract escrow; the escrow service can only settle by forwarding or reversing according to trade outcome, not freely take custody.\n\nAction id: `hostr.escrow.methods`\n\n```ts\nexport interface HostrEscrowMethodsInput {\n /** Seller/host pubkey to inspect escrow compatibility for. */\n user: string;\n /** Buyer pubkey. Defaults to the active Hostr account pubkey. */\n buyer?: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"user\"\n ],\n \"properties\": {\n \"user\": {\n \"type\": \"string\",\n \"description\": \"Seller/host pubkey to inspect escrow compatibility for.\"\n },\n \"buyer\": {\n \"type\": \"string\",\n \"description\": \"Buyer pubkey. Defaults to the active Hostr account pubkey.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_list`\n\nEscrow-only tool. List public escrow service events published by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator inventory view: list public escrow service events published by the authenticated escrow pubkey. Use before editing/deleting when the user has not selected a specific service event.\n\nAction id: `hostr.escrow.service.list`\n\n```ts\nexport interface HostrEscrowServiceListInput {\n /** Maximum number of escrow service events to return. Defaults to 25, capped at 100. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 100,\n \"default\": 25,\n \"description\": \"Maximum number of escrow services to return.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_get`\n\nEscrow-only tool. Show one public escrow service event owned by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator detail view: inspect one escrow service event before explaining or editing settings. Use serviceId from hostr_escrow_service_list or user input.\n\nAction id: `hostr.escrow.service.get`\n\n```ts\nexport interface HostrEscrowServiceGetInput {\n /** Escrow service event id to inspect. */\n serviceId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"serviceId\"\n ],\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Escrow service event id to inspect.\"\n }\n }\n}\n```\n\n## `hostr_escrow_service_edit`\n\nEscrow-only tool. Preview or publish the active escrow account service parameters. Use hostr.profile.edit for the escrow user profile.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator settings workflow: preview changes to fee percent, maximum duration, or token fee hints. Keep dryRun=true until the user approves the exact preview. Use hostr_profile_edit for public profile/identity metadata; this tool only changes escrow service parameters.\n\nAction id: `hostr.escrow.service.edit`\n\n```ts\nexport interface HostrTokenFeeHintsInput {\n /** Flat base fee in token smallest units. */\n baseFee?: number;\n /** Maximum fee cap in token smallest units. Zero means no cap. */\n maxFee?: number;\n /** Minimum fee floor in token smallest units. Zero means no floor. */\n minFee?: number;\n}\n\nexport interface HostrEscrowServiceUpdateInput {\n /** Optional escrow service event id to edit. Omit to edit the daemon bootstrap service. */\n serviceId?: string;\n /** Proportional escrow fee as a percent, e.g. 1.5 for 1.5%. */\n feePercent?: number;\n /** Maximum supported escrow duration in seconds. */\n maxDurationSeconds?: number;\n /** Full replacement map keyed by token address, or \"native\". */\n tokenFeeHints?: Record;\n /** Clear all per-token fee hints. Ignored if tokenFeeHints is provided. */\n clearTokenFeeHints?: boolean;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Optional escrow service event id to edit. Omit to edit the daemon bootstrap service.\"\n },\n \"feePercent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"description\": \"Proportional escrow fee as a percent, e.g. 1.5 for 1.5%.\"\n },\n \"maxDurationSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 315360000,\n \"description\": \"Maximum supported escrow duration in seconds. Omit to preserve the current value.\"\n },\n \"tokenFeeHints\": {\n \"type\": \"object\",\n \"description\": \"Optional full replacement map keyed by token address, or \\\"native\\\". Values are smallest-unit fee hints.\",\n \"additionalProperties\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"baseFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"maxFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"minFee\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n \"clearTokenFeeHints\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Clear all per-token fee hints. Ignored if tokenFeeHints is provided.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_service_delete`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for an escrow service event owned by the authenticated escrow pubkey. Keep dryRun true until the user explicitly approves deletion.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive workflow: preview deletion of a public escrow service event and require explicit deletion approval before dryRun=false. Include the reason when the user gives one.\n\nAction id: `hostr.escrow.service.delete`\n\n```ts\nexport interface HostrEscrowServiceDeleteInput {\n /** Escrow service event id to delete. */\n serviceId: string;\n /** Optional deletion reason for the NIP-09 event. */\n reason?: string;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"serviceId\"\n ],\n \"properties\": {\n \"serviceId\": {\n \"type\": \"string\",\n \"description\": \"Escrow service event id to delete.\"\n },\n \"reason\": {\n \"type\": \"string\",\n \"description\": \"Optional deletion reason for the NIP-09 event.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_trades_list`\n\nEscrow-only tool. List on-chain Hostr trades where the active Hostr account is a configured escrow. Hidden unless the active account pubkey is in the daemon escrow pubkey allowlist.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator dashboard: list on-chain trades assigned to the authenticated escrow pubkey. Use before viewing/auditing/arbitrating when the user has not named a concrete tradeId.\n\nAction id: `hostr.escrow.trades.list`\n\n```ts\nexport interface HostrEscrowTradesListInput {\n /** Maximum number of escrow trades to return. Defaults to 25, capped at 100. */\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 100,\n \"default\": 25,\n \"description\": \"Maximum number of escrow trades to return.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_view`\n\nEscrow-only tool. View the on-chain state, event history, and Hostr reservation context for a trade assigned to the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator trade detail: inspect on-chain state, event history, participants, amounts, and reservation context for a trade before audit or arbitration.\n\nAction id: `hostr.escrow.trades.view`\n\n```ts\nexport interface HostrEscrowTradeViewInput {\n /** Hostr reservation trade id to inspect. */\n tradeId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to inspect.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_audit`\n\nEscrow-only tool. Run a structured reservation and transition audit for a Hostr trade assigned to the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator analysis: run a structured audit of reservation state and transitions for a trade before deciding whether arbitration is needed. This does not settle funds.\n\nAction id: `hostr.escrow.trades.audit`\n\n```ts\nexport interface HostrEscrowTradeAuditInput {\n /** Hostr reservation trade id to audit. */\n tradeId: string;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to audit.\"\n }\n }\n}\n```\n\n## `hostr_escrow_trades_arbitrate`\n\nEscrow-only settlement tool. Preview or execute arbitration for a Hostr escrow trade. paymentForward and bondForward are fractions from 0 to 1. Keep dryRun true until the user explicitly approves the arbitration preview.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator settlement workflow: preview paymentForward and bondForward fractions before execution. Fractions are 0 to 1. Explain the proposed split and reason to the user, then execute with dryRun=false only after explicit approval.\n\nAction id: `hostr.escrow.trades.arbitrate`\n\n```ts\nexport interface HostrEscrowArbitrateInput {\n /** Hostr reservation trade id to arbitrate. */\n tradeId: string;\n /** Fraction of the escrowed payment to forward to the seller, from 0 to 1. */\n paymentForward: number;\n /** Fraction of the escrow bond to forward according to contract settlement rules, from 0 to 1. */\n bondForward: number;\n /** Optional human-readable arbitration reason. */\n reason?: string;\n /** Defaults to true. Set false only after explicit approval. */\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"tradeId\",\n \"paymentForward\",\n \"bondForward\"\n ],\n \"properties\": {\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Hostr reservation trade id to arbitrate.\"\n },\n \"paymentForward\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1,\n \"description\": \"Fraction of the escrowed payment to forward to the seller, from 0 to 1.\"\n },\n \"bondForward\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1,\n \"description\": \"Fraction of the escrow bond to forward according to the contract settlement rules, from 0 to 1.\"\n },\n \"reason\": {\n \"type\": \"string\",\n \"description\": \"Optional human-readable arbitration reason.\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_list`\n\nEscrow-only tool. List NIP-58 badge definitions published by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator badge inventory: list NIP-58 badge definitions issued by the authenticated escrow. Use before editing, awarding, or deleting badges when the identifier/anchor is unclear.\n\nAction id: `hostr.escrow.badges.definitions.list`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionsListInput {\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_edit`\n\nEscrow-only tool. Preview or publish a NIP-58 badge definition for the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator badge definition workflow: preview or publish a NIP-58 badge definition. Use for creating or updating the badge name, description, or image. Publish only after approval.\n\nAction id: `hostr.escrow.badges.definitions.edit`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionEditInput {\n /** Badge definition d-tag identifier. */\n identifier: string;\n name: string;\n description?: string;\n image?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"identifier\",\n \"name\"\n ],\n \"properties\": {\n \"identifier\": {\n \"type\": \"string\",\n \"description\": \"Badge definition d-tag identifier.\"\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"description\": {\n \"type\": \"string\"\n },\n \"image\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_definitions_delete`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for a badge definition owned by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive badge workflow: preview deletion of a badge definition and publish only after explicit approval. Include a reason when provided.\n\nAction id: `hostr.escrow.badges.definitions.delete`\n\n```ts\nexport interface HostrEscrowBadgeDefinitionDeleteInput {\n anchor: string;\n reason?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"anchor\"\n ],\n \"properties\": {\n \"anchor\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_awards_list`\n\nEscrow-only tool. List NIP-58 badge awards issued by the authenticated escrow pubkey, optionally filtered by definition anchor.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nEscrow-operator badge award view: list issued badge awards, optionally filtered by definition anchor. Use before revoking when the award id is unclear.\n\nAction id: `hostr.escrow.badges.awards.list`\n\n```ts\nexport interface HostrEscrowBadgeAwardsListInput {\n definitionAnchor?: string;\n limit?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"definitionAnchor\": {\n \"type\": \"string\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 200,\n \"default\": 50\n }\n }\n}\n```\n\n## `hostr_escrow_badges_award`\n\nEscrow-only tool. Preview or publish a NIP-58 badge award from the authenticated escrow pubkey to a recipient pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator award workflow: preview or publish a NIP-58 badge award to a recipient pubkey, optionally tied to a listing anchor. Publish only after approval.\n\nAction id: `hostr.escrow.badges.award`\n\n```ts\nexport interface HostrEscrowBadgeAwardInput {\n definitionAnchor: string;\n recipientPubkey: string;\n listingAnchor?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"definitionAnchor\",\n \"recipientPubkey\"\n ],\n \"properties\": {\n \"definitionAnchor\": {\n \"type\": \"string\"\n },\n \"recipientPubkey\": {\n \"type\": \"string\"\n },\n \"listingAnchor\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_escrow_badges_revoke`\n\nEscrow-only destructive tool. Preview or publish a NIP-09 deletion for a badge award issued by the authenticated escrow pubkey.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nEscrow role notes: this tool is visible only when the authenticated Hostr pubkey is configured as an escrow service. It is for escrow-operator work, not ordinary guest/host booking flows. Keep user profile edits in hostr_profile_edit; escrow service tools only manage escrow service events/settings.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nEscrow-operator destructive award workflow: preview revocation/deletion of an issued badge award and publish only after explicit approval. Include a reason when provided.\n\nAction id: `hostr.escrow.badges.revoke`\n\n```ts\nexport interface HostrEscrowBadgeRevokeInput {\n awardId: string;\n reason?: string;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"awardId\"\n ],\n \"properties\": {\n \"awardId\": {\n \"type\": \"string\"\n },\n \"reason\": {\n \"type\": \"string\"\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_swaps_watch`\n\nRead-only swap monitor. Inspect a persisted swap-in by id and report payment/proof/reservation state without creating, signing, publishing, or recovering anything. For book-and-pay follow-up, pass both the internal `swapId` and `tradeId` returned by `hostr_orders_bookAndPay`. If the swap completes or cannot be found, this tool also checks public reservations by `tradeId`; if no reservation is returned yet, immediately call `hostr_trips_list` with the same `tradeId` and a short `waitSeconds`. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; never report that pubkey difference as an identity mismatch. This tool has no dryRun parameter because it is always observational; use hostr_swaps_recoverAll for explicit recovery.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nRead-only monitor to use immediately after hostr_orders_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.\n\nAction id: `hostr.swaps.watch`\n\n```ts\nexport interface HostrSwapsWatchInput {\n swapId: string;\n tradeId?: string;\n reservationWaitSeconds?: number;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"swapId\"\n ],\n \"properties\": {\n \"swapId\": {\n \"type\": \"string\"\n },\n \"tradeId\": {\n \"type\": \"string\",\n \"description\": \"Optional reservation trade id used to fall back to public reservation lookup after the swap completes or is not found.\"\n },\n \"reservationWaitSeconds\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 60,\n \"default\": 20,\n \"description\": \"How long to poll for the committed reservation after proof completion or swap-not-found fallback. Keep short; capped below MCP client timeouts.\"\n }\n }\n}\n```\n\n## `hostr_swaps_recoverAll`\n\nPreview or run recovery for all persisted swap-in and swap-out operations.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user asks to recover stuck payments/swaps or when diagnostics show persisted swap operations need resumption. Preview first; run with dryRun=false only after approval. Use background=true only when the user wants recovery to continue asynchronously.\n\nAction id: `hostr.swaps.recoverAll`\n\n```ts\nexport interface HostrSwapsRecoverAllInput {\n background?: boolean;\n dryRun?: boolean;\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"background\": {\n \"type\": \"boolean\",\n \"default\": false\n },\n \"dryRun\": {\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n}\n```\n\n## `hostr_swaps_list`\n\nList persisted swap-in and swap-out operation states.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse to inspect persisted swap-in and swap-out states before recovery/debugging, or when the user asks about payment status, stuck swaps, refunds, or pending Lightning/on-chain operations.\n\nAction id: `hostr.swaps.list`\n\n```ts\nexport interface HostrSwapsListInput {\n namespace?: \"all\" | \"swap_in\" | \"swap_out\";\n}\n```\n\nJSON schema:\n\n```json\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"namespace\": {\n \"type\": \"string\",\n \"enum\": [\n \"all\",\n \"swap_in\",\n \"swap_out\"\n ],\n \"default\": \"all\"\n }\n }\n}\n```\n\n"; export const hostrActionCatalog = [ { @@ -1280,8 +1280,8 @@ export const hostrActionCatalog = [ readOnly: true, }, { - id: "hostr.listings.reservationGroups", - toolName: "hostr_listings_reservationGroups", + id: "hostr.listings.orderGroups", + toolName: "hostr_listings_orderGroups", title: "Fetch Listing Reservation Groups", description: "Fetch public reservation groups for one or more listings. Use this before availability-sensitive reservation workflows when the agent needs to explain conflicts.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse when the user asks why dates are unavailable, wants booking history/conflicts for a listing, or needs reservation context before changing availability-sensitive plans.", inputTypeName: "HostrListingsAnchorsInput", @@ -1312,11 +1312,11 @@ export const hostrActionCatalog = [ readOnly: true, }, { - id: "hostr.reservations.bookAndPay", - toolName: "hostr_reservations_bookAndPay", + id: "hostr.orders.bookAndPay", + toolName: "hostr_orders_bookAndPay", title: "Start Reservation Payment", - description: "Use this foreground handoff tool whenever the user says to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. It creates the private reservation offer and escrow funding swap. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time. Reservation privacy: Hostr intentionally publishes committed reservations and escrow trades under Hostr-created per-trade temporary pubkeys rather than the active account pubkey. This is normal and preserves user privacy; never present a different reservation buyer pubkey as an identity mismatch. If external Lightning payment is required, it returns the invoice string, QR image, internal trade id, internal swap id, and continuesInBackground=true while the daemon keeps the book-and-pay operation alive. CRITICAL UI REQUIREMENT: leave only the QR image and invoice text visibly in the answer to the user; do not show internal trade id or swap id in the payment prompt, and do not replace the payment prompt with a summary. The next assistant action after rendering that visible payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. The returned `reservationWaitSeconds` is short and capped below MCP client timeouts; do not substitute a longer proof timeout. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, query `hostr_trips_list` with `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nPrimary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_reservations_commit for this normal path; proof publication is owned by the global payment proof orchestrator.", - inputTypeName: "HostrReservationBookAndPayInput", + description: "Use this foreground handoff tool whenever the user says to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. It creates the private reservation offer and escrow funding swap. Reservation start/end values are calendar dates, not timezone instants. Encode the requested date as YYYY-MM-DDT00:00:00Z; the trailing Z is storage syntax only. Do not convert from the user timezone, listing timezone, check-in time, or check-out time. Reservation privacy: Hostr intentionally publishes committed reservations and escrow trades under Hostr-created per-trade temporary pubkeys rather than the active account pubkey. This is normal and preserves user privacy; never present a different reservation buyer pubkey as an identity mismatch. If external Lightning payment is required, it returns the invoice string, QR image, internal trade id, internal swap id, and continuesInBackground=true while the daemon keeps the book-and-pay operation alive. CRITICAL UI REQUIREMENT: leave only the QR image and invoice text visibly in the answer to the user; do not show internal trade id or swap id in the payment prompt, and do not replace the payment prompt with a summary. The next assistant action after rendering that visible payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. The returned `reservationWaitSeconds` is short and capped below MCP client timeouts; do not substitute a longer proof timeout. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, query `hostr_trips_list` with `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nPrimary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_orders_commit for this normal path; proof publication is owned by the global payment proof orchestrator.", + inputTypeName: "HostrOrderBookAndPayInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1381,15 +1381,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationBookAndPayInputSchema, + inputSchema: HostrOrderBookAndPayInputSchema, readOnly: false, }, { - id: "hostr.reservations.negotiateOffer", - toolName: "hostr_reservations_negotiateOffer", + id: "hostr.orders.negotiateOffer", + toolName: "hostr_orders_negotiateOffer", title: "Create Reservation Negotiation Offer", - description: "Create only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like \"book\", \"reserve\", \"make a reservation\", or instant-book at the listed price; those must use hostr_reservations_bookAndPay instead.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nNegotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward \"book/reserve\" intents on instant-book listings; use hostr_reservations_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.", - inputTypeName: "HostrReservationsOfferInput", + description: "Create only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like \"book\", \"reserve\", \"make a reservation\", or instant-book at the listed price; those must use hostr_orders_bookAndPay instead.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nReservation date rule: Hostr reservation start/end inputs are calendar dates, not timezone instants. Preserve the dates the user requested and encode them as YYYY-MM-DDT00:00:00Z. The trailing Z is storage syntax only; do not convert from the user timezone, listing timezone, El Salvador time, check-in time, or check-out time.\n\nNegotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward \"book/reserve\" intents on instant-book listings; use hostr_orders_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.", + inputTypeName: "HostrOrdersOfferInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1457,15 +1457,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationsOfferInputSchema, + inputSchema: HostrOrdersOfferInputSchema, readOnly: false, }, { - id: "hostr.reservations.negotiateAccept", - toolName: "hostr_reservations_negotiateAccept", + id: "hostr.orders.negotiateAccept", + toolName: "hostr_orders_negotiateAccept", title: "Accept Reservation Negotiation", description: "Accept the latest private negotiate-stage reservation offer in a trade thread by replying with a matching negotiate-stage event.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the user wants to accept the latest private negotiated offer in a known trade thread. If tradeId is unknown, call hostr_updates, hostr_thread_view, hostr_trips_list, or hostr_bookings_list first to identify the trade.", - inputTypeName: "HostrReservationTradeInput", + inputTypeName: "HostrOrderTradeInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1518,15 +1518,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationTradeInputSchema, + inputSchema: HostrOrderTradeInputSchema, readOnly: false, }, { - id: "hostr.reservations.pay", - toolName: "hostr_reservations_pay", + id: "hostr.orders.pay", + toolName: "hostr_orders_pay", title: "Pay Reservation Offer", - description: "Preview or create the escrow funding swap for a payable reservation trade. The live action sends the escrow selection into the private thread as an unsigned child event, prepares the escrow fund calls, creates the Boltz swap invoice, and persists the payment context for commit.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_reservations_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.", - inputTypeName: "HostrReservationPayInput", + description: "Preview or create the escrow funding swap for a payable reservation trade. The live action sends the escrow selection into the private thread as an unsigned child event, prepares the escrow fund calls, creates the Boltz swap invoice, and persists the payment context for commit.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_orders_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.", + inputTypeName: "HostrOrderPayInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1554,15 +1554,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationPayInputSchema, + inputSchema: HostrOrderPayInputSchema, readOnly: false, }, { - id: "hostr.reservations.commit", - toolName: "hostr_reservations_commit", + id: "hostr.orders.commit", + toolName: "hostr_orders_commit", title: "Commit Paid Reservation", - description: "Preview or publish the public commit-stage reservation after the escrow funding swap has completed and produced a claim transaction proof.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug commit flow only. Do not use after hostr_reservations_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.", - inputTypeName: "HostrReservationCommitInput", + description: "Preview or publish the public commit-stage reservation after the escrow funding swap has completed and produced a claim transaction proof.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nManual recovery/debug commit flow only. Do not use after hostr_orders_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.", + inputTypeName: "HostrOrderCommitInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1572,7 +1572,7 @@ export const hostrActionCatalog = [ "properties": { "swapId": { "type": "string", - "description": "Boltz swap id returned by hostr_reservations_pay." + "description": "Boltz swap id returned by hostr_orders_pay." }, "dryRun": { "type": "boolean", @@ -1586,15 +1586,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationCommitInputSchema, + inputSchema: HostrOrderCommitInputSchema, readOnly: false, }, { - id: "hostr.reservations.cancel", - toolName: "hostr_reservations_cancel", + id: "hostr.orders.cancel", + toolName: "hostr_orders_cancel", title: "Cancel Reservation", description: "Cancel either the private negotiate-stage reservation for a trade, or the committed public reservation if one exists.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse to cancel a private negotiation or committed reservation for a concrete trade. If tradeId is unclear, inspect updates, trips, bookings, or thread view first. Preview the cancellation and send with dryRun=false only after explicit approval.", - inputTypeName: "HostrReservationTradeInput", + inputTypeName: "HostrOrderTradeInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1647,15 +1647,15 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationTradeInputSchema, + inputSchema: HostrOrderTradeInputSchema, readOnly: false, }, { - id: "hostr.reservations.review", - toolName: "hostr_reservations_review", + id: "hostr.orders.review", + toolName: "hostr_orders_review", title: "Review Reservation", description: "Preview or publish a guest review for a committed Hostr reservation. This creates a Nostr review event with a participation proof for the reservation trade; preview first and only publish after explicit approval.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nWrite behavior: this tool can create, publish, send, recover, delete, pay, arbitrate, or otherwise change state outside ChatGPT. Explain the important effect to the user before live execution, preserve user-visible previews, and require explicit user approval before any irreversible or externally visible action.\n\nPreview rule: dryRun defaults to true. First call with dryRun=true, show the user the returned preview or card, and only repeat with dryRun=false after the user explicitly approves that preview in the conversation. Do not treat vague acknowledgement as approval for destructive, payment, publication, messaging, cancellation, recovery, or arbitration actions.\n\nUse when the guest wants to leave a rating/review for a completed or confirmed Hostr trip. If tradeId is unclear, inspect hostr_trips_list first. Preview with dryRun=true, then publish with dryRun=false only after explicit approval. Skip this action if no committed reservation can be found for the trade.", - inputTypeName: "HostrReservationReviewInput", + inputTypeName: "HostrOrderReviewInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1693,7 +1693,7 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationReviewInputSchema, + inputSchema: HostrOrderReviewInputSchema, readOnly: false, }, { @@ -1952,8 +1952,8 @@ export const hostrActionCatalog = [ id: "hostr.trips.list", toolName: "hostr_trips_list", title: "List Hostr Trips", - description: "List reservation groups involving the authenticated user as guest from the live userSubscriptions.myResolvedTripsList replay. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; treat those temporary pubkeys as expected reservation accounts for the active user, not as an identity mismatch. Do not perform fresh reservation-by-author Nostr queries for this view. Return the fixed trip-card display contract with resolved participant profile names. Cancelled trip cards must preserve a bold Cancelled marker. Pass `tradeId` after a book-and-pay swap watch completes or cannot find the swap to wait briefly for the committed public reservation and return it for display.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for guest-side reservations: \"my trips\", \"my bookings as guest\", \"my reservation reference\", \"did my reservation complete\", \"my host has not replied\", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_reservations_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.", - inputTypeName: "HostrReservationCollectionInput", + description: "List reservation groups involving the authenticated user as guest from the live userSubscriptions.myResolvedTripsList replay. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; treat those temporary pubkeys as expected reservation accounts for the active user, not as an identity mismatch. Do not perform fresh reservation-by-author Nostr queries for this view. Return the fixed trip-card display contract with resolved participant profile names. Cancelled trip cards must preserve a bold Cancelled marker. Pass `tradeId` after a book-and-pay swap watch completes or cannot find the swap to wait briefly for the committed public reservation and return it for display.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for guest-side reservations: \"my trips\", \"my bookings as guest\", \"my reservation reference\", \"did my reservation complete\", \"my host has not replied\", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_orders_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.", + inputTypeName: "HostrOrderCollectionInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -1977,7 +1977,7 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationCollectionInputSchema, + inputSchema: HostrOrderCollectionInputSchema, readOnly: true, }, { @@ -1985,7 +1985,7 @@ export const hostrActionCatalog = [ toolName: "hostr_bookings_list", title: "List Hostr Bookings", description: "List reservation groups where the authenticated user is the host from the live userSubscriptions.myResolvedHostingsList replay. Do not perform fresh Nostr listing/reservation-by-author queries for this view. Return the fixed hosting-card display contract with resolved participant profile names, including \"Hosting {guest} at: {stay}\" text.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nUse for host-side reservations on listings authored by the authenticated user: \"my bookings\", \"who booked my place\", \"hosting reservations\", or host calendar context. Do not use this as the first monitor immediately after a payment-required guest booking; hostr_swaps_watch comes first. Do not perform fresh reservation-by-author Nostr queries for this view.", - inputTypeName: "HostrReservationCollectionInput", + inputTypeName: "HostrOrderCollectionInput", inputJsonSchema: { "type": "object", "additionalProperties": false, @@ -2009,7 +2009,7 @@ export const hostrActionCatalog = [ } } }, - inputSchema: HostrReservationCollectionInputSchema, + inputSchema: HostrOrderCollectionInputSchema, readOnly: true, }, { @@ -2471,7 +2471,7 @@ export const hostrActionCatalog = [ id: "hostr.swaps.watch", toolName: "hostr_swaps_watch", title: "Watch Hostr Swap", - description: "Read-only swap monitor. Inspect a persisted swap-in by id and report payment/proof/reservation state without creating, signing, publishing, or recovering anything. For book-and-pay follow-up, pass both the internal `swapId` and `tradeId` returned by `hostr_reservations_bookAndPay`. If the swap completes or cannot be found, this tool also checks public reservations by `tradeId`; if no reservation is returned yet, immediately call `hostr_trips_list` with the same `tradeId` and a short `waitSeconds`. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; never report that pubkey difference as an identity mismatch. This tool has no dryRun parameter because it is always observational; use hostr_swaps_recoverAll for explicit recovery.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nRead-only monitor to use immediately after hostr_reservations_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.", + description: "Read-only swap monitor. Inspect a persisted swap-in by id and report payment/proof/reservation state without creating, signing, publishing, or recovering anything. For book-and-pay follow-up, pass both the internal `swapId` and `tradeId` returned by `hostr_orders_bookAndPay`. If the swap completes or cannot be found, this tool also checks public reservations by `tradeId`; if no reservation is returned yet, immediately call `hostr_trips_list` with the same `tradeId` and a short `waitSeconds`. Committed reservations may be authored by Hostr-created per-trade temporary pubkeys for privacy; never report that pubkey difference as an identity mismatch. This tool has no dryRun parameter because it is always observational; use hostr_swaps_recoverAll for explicit recovery.\n\nMCP driving notes: Hostr is the canonical tool surface for Hostr marketplace state and Hostr-related Nostr state, including listings, reservations, trips, bookings, reservation references/trade ids, inbox threads, Nostr Connect/NIP-46 signer login, relays, npubs/naddrs, gift-wrapped messages, escrow services, swaps, and on-chain escrow trades. Use Hostr tools for natural requests like \"I need a place to stay\", \"book a room with my guest account\", \"my host has not replied\", \"check this reservation reference\", \"I am hosting now\", \"show my bookings\", \"switch to my guest/host account\", \"I am handling escrow\", \"list trades\", \"arbitrate this trade\", or \"message the guest/host/escrow\". Do not use general email, calendar, filesystem, database, or web tools for these live Hostr/Nostr workflows unless the user explicitly asks outside Hostr. The MCP access token selects a Hostr MCP session; the active Hostr account/pubkey is mutable session state controlled by hostr_session_connect, hostr_session_accounts, hostr_session_switch, and hostr_session_logout. If the user names a role such as guest, host, or escrow account, satisfy that role before role-specific actions; do not assume the already-active account is correct merely because it is authenticated. Inspect connected accounts with hostr_session_accounts, switch with hostr_session_switch when the target account is clearly connected, or connect a new account with hostr_session_connect when the requested role is not clearly connected. Hostr reservation privacy: committed reservations, escrow trades, and reservation threads may use Hostr-created per-trade temporary pubkeys instead of the active account pubkey. This is expected privacy-preserving behavior, not an identity mismatch, and you should not warn the user that the reservation pubkey differs from their logged-in account. Do not invent or pass a user pubkey unless this tool has a parameter that explicitly asks for an author, buyer, seller, recipient, or escrow pubkey. Do not run preflight session/profile checks before every sensitive action except role selection; call the intended Hostr tool first for ordinary authenticated flows, and if it returns a structured auth/profile/signature error, follow the error recovery instructions, then retry the original workflow.\n\nRead-only behavior: this tool retrieves or analyzes Hostr state and is safe to call when the user asks to inspect, search, explain, debug, or choose the next action. Prefer read tools before write tools when the user intent is ambiguous or when you need concrete listing, trade, thread, or profile ids.\n\nRead-only monitor to use immediately after hostr_orders_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.", inputTypeName: "HostrSwapsWatchInput", inputJsonSchema: { "type": "object", diff --git a/ai/mcp-server/src/mcp/server.ts b/ai/mcp-server/src/mcp/server.ts index 09caf95a..baff4556 100644 --- a/ai/mcp-server/src/mcp/server.ts +++ b/ai/mcp-server/src/mcp/server.ts @@ -324,8 +324,8 @@ const escrowBadgeOutputSchema = z .passthrough(); const reservationActionIds = new Set([ - "hostr.reservations.bookAndPay", - "hostr.reservations.review", + "hostr.orders.bookAndPay", + "hostr.orders.review", "hostr.swaps.watch", "hostr.trips.list", "hostr.bookings.list", @@ -340,13 +340,13 @@ const threadActionIds = new Set([ const destructiveActionIds = new Set([ "hostr.listings.edit", - "hostr.reservations.negotiateOffer", - "hostr.reservations.negotiateAccept", + "hostr.orders.negotiateOffer", + "hostr.orders.negotiateAccept", "hostr.profile.edit", - "hostr.reservations.pay", - "hostr.reservations.commit", - "hostr.reservations.cancel", - "hostr.reservations.review", + "hostr.orders.pay", + "hostr.orders.commit", + "hostr.orders.cancel", + "hostr.orders.review", "hostr.escrow.involve", "hostr.escrow.service.edit", "hostr.escrow.service.delete", @@ -361,13 +361,13 @@ const openWorldActionIds = new Set([ "hostr.listings.search", "hostr.listings.create", "hostr.listings.edit", - "hostr.reservations.bookAndPay", - "hostr.reservations.negotiateOffer", - "hostr.reservations.negotiateAccept", - "hostr.reservations.pay", - "hostr.reservations.commit", - "hostr.reservations.cancel", - "hostr.reservations.review", + "hostr.orders.bookAndPay", + "hostr.orders.negotiateOffer", + "hostr.orders.negotiateAccept", + "hostr.orders.pay", + "hostr.orders.commit", + "hostr.orders.cancel", + "hostr.orders.review", "hostr.thread.message", "hostr.escrow.involve", "hostr.profile.edit", @@ -398,7 +398,7 @@ const toolAnnotations = (action: { }; const reservationToolMeta = (actionId: string): Record => { - if (actionId === "hostr.reservations.bookAndPay") { + if (actionId === "hostr.orders.bookAndPay") { return { ...widgetTemplateMeta(paymentRequiredWidgetUri), "hostr.preferredRenderer": "payment-external-required", @@ -456,7 +456,7 @@ const presentationContract = (actionId: string): string | null => { return "Returns listing-card output; render structuredContent.displayMarkdown and preserve image Markdown."; } if (reservationActionIds.has(actionId)) { - return actionId === "hostr.reservations.bookAndPay" + return actionId === "hostr.orders.bookAndPay" ? "May return a payment QR widget. If payment is required, render the QR/invoice and make the next assistant action a hostr_swaps_watch tool call with structuredContent.requiredNextTool.arguments. Do not stop after displaying the invoice." : "May return trip-card or hosting-card output; render structuredContent.displayMarkdown instead of raw JSON."; } @@ -484,9 +484,9 @@ const discoveryHint = (actionId: string): string | null => { return "Use this when the user asks to open, look up, inspect, or view another guest, host, seller, buyer, escrow, or participant profile from a reservation, listing, trade, or thread. It accepts npubs and 64-character hex pubkeys returned by Hostr cards."; case "hostr.swaps.list": return "Use this before recovery when the user asks about saved payments, payment operations, swap operations, stuck payments, pending payments, refunds, or whether payment got stuck."; - case "hostr.reservations.negotiateOffer": + case "hostr.orders.negotiateOffer": return "Use this for previewing or sending a new reservation offer/counteroffer. If the user asks what an offer would look like and gives a total price or says to use the same trip total, include that amount."; - case "hostr.reservations.negotiateAccept": + case "hostr.orders.negotiateAccept": return "Use this when the user asks to accept, preview accepting, or show what accepting the latest reservation offer would look like."; case "hostr.escrow.methods": return "Use this when escrow asks how the buyer or host/seller can be paid, refunded, released, reversed, or settled for a trade."; @@ -1842,7 +1842,7 @@ const reservationCardsFromResult = ( if ( actionId === "hostr.trips.list" || actionId === "hostr.bookings.list" || - actionId === "hostr.reservations.bookAndPay" + actionId === "hostr.orders.bookAndPay" ) { const fallbackType = actionId === "hostr.bookings.list" ? "hosting-card" : "trip-card"; @@ -3134,7 +3134,7 @@ const formatToolContent = ( } } - if (actionId === "hostr.reservations.negotiateOffer") { + if (actionId === "hostr.orders.negotiateOffer") { const listing = record(data.listing); const tradeId = stringValue(data.tradeId); const mode = result.dryRun === true ? "Preview" : "Broadcast"; @@ -3150,7 +3150,7 @@ const formatToolContent = ( .join("\n\n"); } - if (actionId === "hostr.reservations.bookAndPay") { + if (actionId === "hostr.orders.bookAndPay") { const state = record(data.state); const stateName = stringValue(state?.state) ?? stringValue(data.stateName); const externalPayment = @@ -3179,7 +3179,7 @@ const formatToolContent = ( .join("\n\n"); } - if (actionId === "hostr.reservations.review") { + if (actionId === "hostr.orders.review") { const mode = result.dryRun === true ? "Preview" : "Published"; const rating = Number(data.rating); const content = stringValue(data.content); @@ -3630,7 +3630,7 @@ const toolResponse = async ( ] : undefined; const bookAndPayPaymentRequired = - actionId === "hostr.reservations.bookAndPay" && Boolean(paymentDisplay); + actionId === "hostr.orders.bookAndPay" && Boolean(paymentDisplay); const swapWatchStatus = actionId === "hostr.swaps.watch" ? swapWatchInfo(safeResult) : null; const structuredResult = bookAndPayPaymentRequired @@ -6755,7 +6755,7 @@ const createServer = ( reservationActionIds.has(action.id) ? { outputSchema: - action.id === "hostr.reservations.bookAndPay" + action.id === "hostr.orders.bookAndPay" ? paymentRequiredOutputSchema : reservationCardOutputSchema, _meta: reservationToolMeta(action.id), @@ -6934,7 +6934,7 @@ const createServer = ( action: action.id, input: args, notificationToken, - ...(action.id === "hostr.reservations.bookAndPay" + ...(action.id === "hostr.orders.bookAndPay" ? { timeoutMs: bookAndPayTimeoutMs(args) } : {}), ...(action.id === "hostr.swaps.watch" diff --git a/ai/mcp-server/test/client-store.test.mjs b/ai/mcp-server/test/client-store.test.mjs index 59b415af..6460c92d 100644 --- a/ai/mcp-server/test/client-store.test.mjs +++ b/ai/mcp-server/test/client-store.test.mjs @@ -108,7 +108,7 @@ test("Hostr tool annotations mark external Hostr actions as open-world", () => { test("client tool visibility policy hook is currently non-blocking", () => { const visible = new Set([ "hostr.listings.search", - "hostr.reservations.bookAndPay", + "hostr.orders.bookAndPay", ]); const filtered = __testing.applyClientToolVisibilityPolicy(visible, { @@ -534,10 +534,10 @@ test("payment responses include a result-bound payment widget", async () => { qrImageUrlTemplate: "https://api.qrserver.com/v1/create-qr-code/?size=240x240&data={data}", }, - "hostr.reservations.bookAndPay", + "hostr.orders.bookAndPay", { ok: true, - command: "hostr.reservations.bookAndPay", + command: "hostr.orders.bookAndPay", environment: "staging", dryRun: false, traceId: "trace-payment", @@ -622,7 +622,7 @@ test("payment responses include a result-bound payment widget", async () => { test("book and pay advertises the payment widget at tool registration time", () => { const bookAndPayMeta = __testing.reservationToolMeta( - "hostr.reservations.bookAndPay", + "hostr.orders.bookAndPay", ); assert.equal( bookAndPayMeta["openai/outputTemplate"], @@ -654,7 +654,7 @@ test("payment widget can read ChatGPT multimodal payment output", () => { test("tool descriptions omit repeated boilerplate", () => { const description = __testing.toolDescription({ - id: "hostr.reservations.bookAndPay", + id: "hostr.orders.bookAndPay", description: [ "Book and pay for an instant-book reservation.", "MCP driving notes: long common notes.", @@ -663,7 +663,7 @@ test("tool descriptions omit repeated boilerplate", () => { "Preview rule: common preview notes.", "Specific workflow note.", ].join("\n\n"), - inputTypeName: "HostrReservationsBookAndPayInput", + inputTypeName: "HostrOrderBookAndPayInput", }); assert.match(description, /Book and pay/); @@ -677,7 +677,7 @@ test("tool descriptions omit repeated boilerplate", () => { test("book and pay advertises accurate ChatGPT write annotations", () => { assert.deepEqual( __testing.toolAnnotations({ - id: "hostr.reservations.bookAndPay", + id: "hostr.orders.bookAndPay", readOnly: false, }), { @@ -703,7 +703,7 @@ test("tool annotations distinguish destructive and non-destructive writes", () = assert.deepEqual( __testing.toolAnnotations({ - id: "hostr.reservations.cancel", + id: "hostr.orders.cancel", readOnly: false, }), { diff --git a/ai/plugins/shared/hostr/SKILL.md b/ai/plugins/shared/hostr/SKILL.md index f970ce2b..4d5f1313 100644 --- a/ai/plugins/shared/hostr/SKILL.md +++ b/ai/plugins/shared/hostr/SKILL.md @@ -53,7 +53,7 @@ Use the MCP tools by intent: - Uploads: `hostr_upload_image` - Search/read listings: `hostr_listings_search`, `hostr_listings_list`, `hostr_listings_availability`, `hostr_listings_reviews`, `hostr_listings_reservationGroups` - Manage listings: `hostr_listings_create`, `hostr_listings_edit` -- Reservations: `hostr_reservations_bookAndPay`, `hostr_reservations_negotiateOffer`, `hostr_reservations_negotiateAccept`, `hostr_reservations_pay`, `hostr_reservations_commit`, `hostr_reservations_cancel` +- Reservations: `hostr_orders_bookAndPay`, `hostr_orders_negotiateOffer`, `hostr_orders_negotiateAccept`, `hostr_orders_pay`, `hostr_orders_commit`, `hostr_orders_cancel` - Updates and messaging: `hostr_updates`, `hostr_reply` - Profile: `hostr_profile_show`, `hostr_profile_edit` - Trips and bookings: `hostr_trips_list`, `hostr_bookings_list` @@ -65,8 +65,8 @@ Use the MCP tools by intent: - New listing: ensure profile/session readiness, call `hostr_listings_create` with `dryRun: true`, show title, location, price, photo count, and event/listing preview, then publish only after approval. - Edit listing: inspect current listings if needed, preview with `hostr_listings_edit` and `dryRun: true`, then apply after approval. - Listing specifications: for `hostr_listings_create.specifications` and `hostr_listings_edit.patch.specifications`, use canonical snake_case amenity keys. Wi-Fi/wifi/WIFI is `wireless_internet`, not `wifi`; common keys include `kitchen`, `free_parking`, `allows_pets`, `pool`, `beachfront`, `max_guests`, `beds`, `bedrooms`, and `bathrooms`. -- Search and reserve: for "find a place to stay", "find somewhere to stay in ", "show me lodging/accommodations/rentals", "where can I stay", "find a hotel/room/apartment/villa/resort", call `hostr_listings_search` with the destination in `location`. Then check availability when dates are known. Use `hostr_reservations_bookAndPay` for user phrasing like "book", "reserve", "make a reservation", or "create a reservation" on instant-book listings at/above listed price. If the book-and-pay result includes external Lightning payment details, you MUST leave only the QR image and invoice string visibly in the user-facing output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the QR and invoice MUST be `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show the reservation card. Use negotiation tools only when the user explicitly wants to make/counter an offer. -- Payment: normal AI-initiated instant-book payment is `hostr_reservations_bookAndPay`; the Hostr daemon continues the book-and-pay operation in the background when external Lightning payment is required. The assistant must first show only the returned invoice string and QR image, then its next action MUST be `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion. Do not stop after displaying the invoice, do not wait for the user to say they paid first, and do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator. +- Search and reserve: for "find a place to stay", "find somewhere to stay in ", "show me lodging/accommodations/rentals", "where can I stay", "find a hotel/room/apartment/villa/resort", call `hostr_listings_search` with the destination in `location`. Then check availability when dates are known. Use `hostr_orders_bookAndPay` for user phrasing like "book", "reserve", "make a reservation", or "create a reservation" on instant-book listings at/above listed price. If the book-and-pay result includes external Lightning payment details, you MUST leave only the QR image and invoice string visibly in the user-facing output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the QR and invoice MUST be `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show the reservation card. Use negotiation tools only when the user explicitly wants to make/counter an offer. +- Payment: normal AI-initiated instant-book payment is `hostr_orders_bookAndPay`; the Hostr daemon continues the book-and-pay operation in the background when external Lightning payment is required. The assistant must first show only the returned invoice string and QR image, then its next action MUST be `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion. Do not stop after displaying the invoice, do not wait for the user to say they paid first, and do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator. - Messaging: inspect `hostr_updates`, preview `hostr_reply`, then send after approval. - Escrow messaging: when the user says "message the escrow", "involve escrow", or similar, it must refer to a specific reservation trade. Use `hostr_escrow_involve` with `tradeId`; do not create or use an escrow-only side thread. The escrow thread must include the buyer, seller, and escrow participants for that trade. If no trade is clear, ask which trip/booking/trade they mean. - Escrow compatibility: call `hostr_escrow_methods` before payment when the user needs compatible services explained or selected. diff --git a/app/integration_test/support/e2e_test_harness.dart b/app/integration_test/support/e2e_test_harness.dart index d3a204a6..c682b873 100644 --- a/app/integration_test/support/e2e_test_harness.dart +++ b/app/integration_test/support/e2e_test_harness.dart @@ -2432,7 +2432,7 @@ Future _stopUserSession(Hostr hostr) async { await hostr.userSubscriptions.reset(); await hostr.messaging.threads.reset(); await hostr.nwc.reset(); - await hostr.reservations.reset(); + await hostr.orderWorkflows.reset(); await _closeAllNostrSubscriptions(hostr, 'after-stop'); } @@ -3018,7 +3018,7 @@ Future _assertTripsPageContainsReservations( .whereType>() .any((item) => item.event.tradeId == reservation.tradeId), timeout: const Duration(seconds: 60), - reasonBuilder: () => _reservationGroupsSnapshot( + reasonBuilder: () => _orderGroupsSnapshot( tester, 'Trips should include valid paid reservation ${reservation.tradeId}', ), @@ -3083,7 +3083,7 @@ Finder _appShellRouteExpectedKey(PageRouteInfo route) { return find.byType(Scaffold); } -String _reservationGroupsSnapshot(WidgetTester tester, String prefix) { +String _orderGroupsSnapshot(WidgetTester tester, String prefix) { String describe(Validation item) { final group = item.event; final type = item.runtimeType; @@ -3105,7 +3105,7 @@ String _reservationGroupsSnapshot(WidgetTester tester, String prefix) { const >[]) .map(describe) .join(' | '); - final all = getIt().userSubscriptions.allMyReservationGroups$.items + final all = getIt().userSubscriptions.allMyOrderGroups$.items .map(describe) .join(' | '); final keys = tester @@ -3621,7 +3621,7 @@ Future _waitForPaidReservationGroupAndTripBookedDoneButton( } bool _hasPaidReservationGroup(Hostr hostr, String tradeId) { - return hostr.userSubscriptions.allMyReservationGroups$.items.any((item) { + return hostr.userSubscriptions.allMyOrderGroups$.items.any((item) { if (item.event.tradeId != tradeId) return false; final group = item.event; return group.reservations.any( @@ -3633,7 +3633,7 @@ bool _hasPaidReservationGroup(Hostr hostr, String tradeId) { } String _paidReservationGroupSnapshot(Hostr hostr, String tradeId) { - final groups = hostr.userSubscriptions.allMyReservationGroups$.items + final groups = hostr.userSubscriptions.allMyOrderGroups$.items .where((item) => item.event.tradeId == tradeId) .map( (item) => @@ -4697,8 +4697,8 @@ Future<_BackendLiveBooking> _createBackendLiveBooking({ label: 'backend live booking host commit', ); - await hostr.reservations.upsert(buyerCommit); - await hostr.reservations.upsert(hostCommit); + await hostr.orderWorkflows.upsert(buyerCommit); + await hostr.orderWorkflows.upsert(hostCommit); hostr.userSubscriptions.allMyReservations$.stream.add(buyerCommit); hostr.userSubscriptions.allMyReservations$.stream.add(hostCommit); await _waitForResolvedReservationGroup( @@ -4747,10 +4747,7 @@ _waitForResolvedReservationGroup({ }) async { final deadline = DateTime.now().add(timeout); while (DateTime.now().isBefore(deadline)) { - final matches = hostr - .userSubscriptions - .allMyResolvedReservationGroups$ - .items + final matches = hostr.userSubscriptions.allMyResolvedOrderGroups$.items .where((item) => item.group.tradeId == tradeId) .toList(growable: false); if (matches.isNotEmpty) { @@ -4773,7 +4770,7 @@ _waitForResolvedReservationGroup({ await Future.delayed(const Duration(milliseconds: 200)); } - final unresolved = hostr.userSubscriptions.allMyReservationGroups$.items + final unresolved = hostr.userSubscriptions.allMyOrderGroups$.items .where((item) => item.event.tradeId == tradeId) .map(_describeReservationGroupValidation) .join(' || '); @@ -4873,8 +4870,8 @@ Future<_BackendLiveBooking> _createBackendCompletedReviewBooking({ label: 'backend completed review host commit $label', ); - await hostr.reservations.upsert(buyerCommit); - await hostr.reservations.upsert(hostCommit); + await hostr.orderWorkflows.upsert(buyerCommit); + await hostr.orderWorkflows.upsert(hostCommit); hostr.userSubscriptions.allMyReservations$.stream.add(buyerCommit); hostr.userSubscriptions.allMyReservations$.stream.add(hostCommit); hostr.userSubscriptions.allMyReservations$.stream.addStatus( diff --git a/app/lib/logic/cubit/availability.cubit.dart b/app/lib/logic/cubit/availability.cubit.dart index 4eda2c4a..00af5704 100644 --- a/app/lib/logic/cubit/availability.cubit.dart +++ b/app/lib/logic/cubit/availability.cubit.dart @@ -21,19 +21,19 @@ class AvailabilityCubit extends Cubit { final DateRangeCubit dateRangeCubit; late final StreamSubscription _dateRangeSubscription; - List _reservationGroups; + List _orderGroups; AvailabilityCubit({ required this.dateRangeCubit, - List reservationGroups = const [], - }) : _reservationGroups = List.from(reservationGroups), + List orderGroups = const [], + }) : _orderGroups = List.from(orderGroups), super(AvailabilityLoading()) { _dateRangeSubscription = dateRangeCubit.stream.listen((_) => refresh()); refresh(); } - void updateReservationGroups(List reservationGroups) { - _reservationGroups = List.from(reservationGroups); + void updateOrderGroups(List orderGroups) { + _orderGroups = List.from(orderGroups); refresh(); } @@ -49,7 +49,7 @@ class AvailabilityCubit extends Cubit { final available = Listing.isAvailable( selectedRange.start, selectedRange.end, - _reservationGroups, + _orderGroups, ); emit( diff --git a/app/lib/presentation/component/providers/nostr/listing_dependencies.provider.dart b/app/lib/presentation/component/providers/nostr/listing_dependencies.provider.dart index 7128966a..b1a2e8c8 100644 --- a/app/lib/presentation/component/providers/nostr/listing_dependencies.provider.dart +++ b/app/lib/presentation/component/providers/nostr/listing_dependencies.provider.dart @@ -11,8 +11,7 @@ import 'package:rxdart/rxdart.dart'; class ListingDependencies { Listing listing; final StreamWithStatus> verifiedReviews; - final StreamWithStatus> - verifiedReservationGroups; + final StreamWithStatus> verifiedOrderGroups; StreamWithStatus>>? _reviewItemsSource; StreamWithStatus>>? _reservationGroupItemsSource; @@ -33,7 +32,7 @@ class ListingDependencies { }, ), ), - verifiedReservationGroups: getIt().reservationGroups.queryVerified( + verifiedOrderGroups: getIt().orderGroupVerification.queryVerified( listingAnchor: anchor, ), ); @@ -42,7 +41,7 @@ class ListingDependencies { ListingDependencies({ required this.listing, required this.verifiedReviews, - required this.verifiedReservationGroups, + required this.verifiedOrderGroups, }); StreamWithStatus>> get _reviewItems => @@ -50,7 +49,7 @@ class ListingDependencies { StreamWithStatus>> get _reservationGroupItems => _reservationGroupItemsSource ??= - verifiedReservationGroups.accumulateByKey((g) => g.event.groupId); + verifiedOrderGroups.accumulateByKey((g) => g.event.groupId); late final Stream>> reviewItems = _reviewItems .replayStream @@ -91,7 +90,7 @@ class ListingDependencies { await _reservationGroupItemsSource?.close(); _reservationGroupItemsSource = null; await verifiedReviews.close(); - await verifiedReservationGroups.close(); + await verifiedOrderGroups.close(); } } diff --git a/app/lib/presentation/component/providers/nostr/reservation.provider.dart b/app/lib/presentation/component/providers/nostr/reservation.provider.dart index 62e01978..44d39dee 100644 --- a/app/lib/presentation/component/providers/nostr/reservation.provider.dart +++ b/app/lib/presentation/component/providers/nostr/reservation.provider.dart @@ -5,5 +5,5 @@ import 'package:models/main.dart'; class ReservationProvider extends DefaultEntityProvider { ReservationProvider({super.key, super.e, super.a, super.builder, super.child}) - : super(kinds: Reservation.kinds, crud: getIt().reservations); + : super(kinds: Reservation.kinds, crud: getIt().orderWorkflows); } diff --git a/app/lib/presentation/component/widgets/listing/edit_review.dart b/app/lib/presentation/component/widgets/listing/edit_review.dart index b4949647..c767dc50 100644 --- a/app/lib/presentation/component/widgets/listing/edit_review.dart +++ b/app/lib/presentation/component/widgets/listing/edit_review.dart @@ -98,7 +98,7 @@ class EditReviewController extends UpsertFormController { debugPrint( 'REVIEW_SAVE upsert:reservationAuthor=${reservationAuthorKeyPair.publicKey}', ); - final proof = await getIt().reservations + final proof = await getIt().orderWorkflows .createParticipationProofForReview( reservation: reservationContext, role: 'buyer', diff --git a/app/lib/presentation/component/widgets/listing/listing_list_item.dart b/app/lib/presentation/component/widgets/listing/listing_list_item.dart index 05eb8b23..3ac11875 100644 --- a/app/lib/presentation/component/widgets/listing/listing_list_item.dart +++ b/app/lib/presentation/component/widgets/listing/listing_list_item.dart @@ -180,7 +180,7 @@ class ListingListItemWidgetState extends State { .toList(); _latestAvailabilityGroups = availabilityGroups; - _availabilityCubit?.updateReservationGroups(availabilityGroups); + _availabilityCubit?.updateOrderGroups(availabilityGroups); }); } @@ -212,7 +212,7 @@ class ListingListItemWidgetState extends State { _localDateRangeCubit ??= DateRangeCubit(); _availabilityCubit = AvailabilityCubit( dateRangeCubit: dateRangeCubit ?? _localDateRangeCubit!, - reservationGroups: _latestAvailabilityGroups, + orderGroups: _latestAvailabilityGroups, ); } diff --git a/app/lib/presentation/reservation_published_popup_listener.dart b/app/lib/presentation/reservation_published_popup_listener.dart index f078b939..04a9b22b 100644 --- a/app/lib/presentation/reservation_published_popup_listener.dart +++ b/app/lib/presentation/reservation_published_popup_listener.dart @@ -35,7 +35,7 @@ class _ReservationPublishedPopupListenerState // CrudUseCase only emits updates after relay broadcast succeeds. Listening // here keeps the popup tied to a real reservation publish instead of relay // replays or pre-broadcast optimistic state. - _subscription = getIt().reservations.updates + _subscription = getIt().orderWorkflows.updates .where((reservation) => reservation.isCommit) .where((reservation) => reservation.proof != null) .listen(_showTripBookedPopup); diff --git a/app/lib/presentation/screens/shared/listing/block_dates.dart b/app/lib/presentation/screens/shared/listing/block_dates.dart index 8499661e..52eaefdc 100644 --- a/app/lib/presentation/screens/shared/listing/block_dates.dart +++ b/app/lib/presentation/screens/shared/listing/block_dates.dart @@ -58,7 +58,7 @@ class _BlockDatesWidgetState extends State { ? null : () async { final range = dateRangeController.dateRange!; - await getIt().reservations.createBlocked( + await getIt().orderWorkflows.createBlocked( listingAnchor: widget.listingAnchor, start: range.start, end: range.end, diff --git a/app/lib/presentation/screens/shared/listing/listing_view.dart b/app/lib/presentation/screens/shared/listing/listing_view.dart index fb357d36..8f4ebf21 100644 --- a/app/lib/presentation/screens/shared/listing/listing_view.dart +++ b/app/lib/presentation/screens/shared/listing/listing_view.dart @@ -103,8 +103,7 @@ class _ListingViewContent extends StatelessWidget { listing: listing, reservationGroupItemsStream: dependencies.reservationGroupItems, - reservationsStatus: - dependencies.verifiedReservationGroups.status, + reservationsStatus: dependencies.verifiedOrderGroups.status, ), ), ), @@ -126,10 +125,10 @@ class _ListingViewContent extends StatelessWidget { ), reviewsListWidget: reviewsListWidget, reserveBottomBar: reserveBottomBar, - verifiedGroupsStream: dependencies.verifiedReservationGroups, + verifiedGroupsStream: dependencies.verifiedOrderGroups, hostKeyPair: activeKeyPair, onCancelBlockedReservation: (reservation) async { - await getIt().reservations.cancel( + await getIt().orderWorkflows.cancel( ReservationGroup.fromReservation(reservation), getIt().auth.getActiveKey(), ); diff --git a/app/lib/presentation/screens/shared/listing/reserve.dart b/app/lib/presentation/screens/shared/listing/reserve.dart index 78954a88..42e01740 100644 --- a/app/lib/presentation/screens/shared/listing/reserve.dart +++ b/app/lib/presentation/screens/shared/listing/reserve.dart @@ -113,10 +113,9 @@ class _ReserveState extends State { Widget build(BuildContext context) { return StreamBuilder>>( stream: widget.reservationGroupItemsStream, - builder: (context, reservationGroupsSnapshot) { - final reservationGroups = - (reservationGroupsSnapshot.data ?? - const >[]) + builder: (context, orderGroupsSnapshot) { + final orderGroups = + (orderGroupsSnapshot.data ?? const >[]) .whereType>() .map((validated) => validated.event) .toList(growable: false); @@ -138,7 +137,7 @@ class _ReserveState extends State { onTap: () => selectDates( context, context.read(), - reservationGroups, + orderGroups, enforceContiguousAvailability: true, ), ), @@ -265,7 +264,7 @@ class _ReserveState extends State { Future selectDates( BuildContext context, DateRangeCubit dateRangeCubit, - List reservationGroups, { + List orderGroups, { bool enforceContiguousAvailability = true, }) async { bool selectableDayPredicate( @@ -283,13 +282,13 @@ Future selectDates( } if (enforceContiguousAvailability) { - return Listing.isAvailable(selectedStartDay, day, reservationGroups); + return Listing.isAvailable(selectedStartDay, day, orderGroups); } return true; } - if (!Listing.isAvailable(day, day, reservationGroups)) { + if (!Listing.isAvailable(day, day, orderGroups)) { return false; } diff --git a/app/pubspec.lock b/app/pubspec.lock index cd1c7750..d9dd5b45 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1253,8 +1253,8 @@ packages: dependency: "direct main" description: path: "packages/ndk" - ref: "codex/hostr-ndk-fixes-upstream-master" - resolved-ref: "85f5ca2d3791b56149caaac09a0877b658f56d5a" + ref: "feat/ndk-marketplace" + resolved-ref: "3e3bf19ae4535d726059ab78e366c82414802d98" url: "https://github.com/sudonym-btc/ndk.git" source: git version: "0.8.2-dev.8" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index d1fceee2..4c547593 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -117,7 +117,7 @@ dependency_overrides: ndk: git: url: https://github.com/sudonym-btc/ndk.git - ref: codex/hostr-ndk-fixes-upstream-master + ref: feat/ndk-marketplace path: packages/ndk intl: ^0.20.2 pointycastle: ^4.0.0 diff --git a/app/test/logic/availability_cubit_test.dart b/app/test/logic/availability_cubit_test.dart index 3cbe8882..0c67b92a 100644 --- a/app/test/logic/availability_cubit_test.dart +++ b/app/test/logic/availability_cubit_test.dart @@ -55,7 +55,7 @@ void main() { ); return AvailabilityCubit( dateRangeCubit: dateRangeCubit, - reservationGroups: [ + orderGroups: [ _reservationGroup( start: DateTime(2026, 2, 10), end: DateTime(2026, 2, 12), @@ -75,7 +75,7 @@ void main() { ); return AvailabilityCubit( dateRangeCubit: dateRangeCubit, - reservationGroups: [ + orderGroups: [ _reservationGroup( start: DateTime(2026, 2, 2), end: DateTime(2026, 2, 4), @@ -98,7 +98,7 @@ void main() { ); return AvailabilityCubit( dateRangeCubit: dateRangeCubit, - reservationGroups: [ + orderGroups: [ _reservationGroup( start: DateTime(2026, 2, 2), end: DateTime(2026, 2, 4), diff --git a/app/test/presentation/component/widgets/reservation/trade_header_test.dart b/app/test/presentation/component/widgets/reservation/trade_header_test.dart index f01863fe..30a3ee27 100644 --- a/app/test/presentation/component/widgets/reservation/trade_header_test.dart +++ b/app/test/presentation/component/widgets/reservation/trade_header_test.dart @@ -142,7 +142,11 @@ void main() { amount: null, stage: NegotiationStage( reservationRequests: [reservation], - overlapLock: (isLoading: false, isBlocked: false, reason: null), + overlapLock: ( + isLoading: false, + isBlocked: false, + reason: null, + ), policy: const NegotiationPolicy( latestOffer: null, lastOfferByUs: null, diff --git a/app/widgetbook_workspace/lib/listing/listing_list_item.dart b/app/widgetbook_workspace/lib/listing/listing_list_item.dart index 4237a71b..8bd6ced8 100644 --- a/app/widgetbook_workspace/lib/listing/listing_list_item.dart +++ b/app/widgetbook_workspace/lib/listing/listing_list_item.dart @@ -28,7 +28,7 @@ Widget listingPureDateSelected(BuildContext context) { final dependencies = ListingDependencies( listing: mockListings[0], verifiedReviews: _emptyValidatedStream(), - verifiedReservationGroups: _emptyValidatedStream(), + verifiedOrderGroups: _emptyValidatedStream(), ); return ListingListItemView( @@ -50,7 +50,7 @@ Widget listingPureNoDateSelected(BuildContext context) { final dependencies = ListingDependencies( listing: mockListings[0], verifiedReviews: _emptyValidatedStream(), - verifiedReservationGroups: _emptyValidatedStream(), + verifiedOrderGroups: _emptyValidatedStream(), ); return ListingListItemView( diff --git a/app/widgetbook_workspace/pubspec.lock b/app/widgetbook_workspace/pubspec.lock index f2cf1773..57a59607 100644 --- a/app/widgetbook_workspace/pubspec.lock +++ b/app/widgetbook_workspace/pubspec.lock @@ -1165,8 +1165,8 @@ packages: dependency: "direct overridden" description: path: "packages/ndk" - ref: "codex/hostr-ndk-fixes-upstream-master" - resolved-ref: "85f5ca2d3791b56149caaac09a0877b658f56d5a" + ref: "feat/ndk-marketplace" + resolved-ref: "40db898a8b2dc4428d7fdd7c8170e73f3ea5ed87" url: "https://github.com/sudonym-btc/ndk.git" source: git version: "0.8.2-dev.8" diff --git a/app/widgetbook_workspace/pubspec.yaml b/app/widgetbook_workspace/pubspec.yaml index c6441ef1..0685709b 100644 --- a/app/widgetbook_workspace/pubspec.yaml +++ b/app/widgetbook_workspace/pubspec.yaml @@ -42,7 +42,7 @@ dependency_overrides: ndk: git: url: https://github.com/sudonym-btc/ndk.git - ref: codex/hostr-ndk-fixes-upstream-master + ref: feat/ndk-marketplace path: packages/ndk google_maps_flutter_web: path: ../../dependencies/google_maps_flutter_web diff --git a/escrow/lib/daemon/handlers.dart b/escrow/lib/daemon/handlers.dart index 82a0d4aa..65360f33 100644 --- a/escrow/lib/daemon/handlers.dart +++ b/escrow/lib/daemon/handlers.dart @@ -41,7 +41,7 @@ class DaemonHandler { server.registerMethod(kRpcUpdateProfile, _updateProfile); server.registerMethod(kRpcGetEvmMnemonic, _getEvmMnemonic); server.registerMethod(kRpcResolveNames, _resolveNames); - server.registerMethod(kRpcListReservationGroups, _listReservationGroups); + server.registerMethod(kRpcListOrderGroups, _listOrderGroups); server.registerMethod(kRpcListBadgeDefinitions, _listBadgeDefinitions); server.registerMethod(kRpcUpsertBadgeDefinition, _upsertBadgeDefinition); server.registerMethod(kRpcDeleteBadgeDefinition, _deleteBadgeDefinition); @@ -285,7 +285,7 @@ class DaemonHandler { String tradeId, { bool cachedOnly = false, }) async { - for (final group in daemon.reservationGroups.values) { + for (final group in daemon.orderGroups.values) { try { if (group.tradeId == tradeId) return group; } catch (_) { @@ -295,12 +295,11 @@ class DaemonHandler { if (cachedOnly) return null; - final reservations = await hostr.reservations.getByTradeId(tradeId); + final reservations = await hostr.orderWorkflows.getByTradeId(tradeId); if (reservations.isEmpty) return null; - final groups = Reservations.toReservationGroups(reservations: reservations) - .values - .toList(); + final groups = + Reservations.toOrderGroups(reservations: reservations).values.toList(); groups .sort((a, b) => b.reservations.length.compareTo(a.reservations.length)); for (final group in groups) { @@ -962,8 +961,8 @@ class DaemonHandler { // ── Reservation Groups ──────────────────────────────────────────────────── - Map _listReservationGroups(json_rpc.Parameters params) { - final groups = daemon.reservationGroups; + Map _listOrderGroups(json_rpc.Parameters params) { + final groups = daemon.orderGroups; return { 'groups': groups.entries.map((e) { final g = e.value; diff --git a/escrow/lib/shared/protocol.dart b/escrow/lib/shared/protocol.dart index c7cffe04..6daa3b9c 100644 --- a/escrow/lib/shared/protocol.dart +++ b/escrow/lib/shared/protocol.dart @@ -91,7 +91,7 @@ const kRpcResolveNames = 'resolveNames'; /// List all reservation groups the escrow is tracking. /// Returns `{ "groups": [ ReservationGroupSummaryJson, … ] }`. -const kRpcListReservationGroups = 'listReservationGroups'; +const kRpcListOrderGroups = 'listOrderGroups'; // ── Badges ────────────────────────────────────────────────────────────────── diff --git a/escrow/pubspec.lock b/escrow/pubspec.lock index 756a3224..71f2eef6 100644 --- a/escrow/pubspec.lock +++ b/escrow/pubspec.lock @@ -747,8 +747,8 @@ packages: dependency: "direct main" description: path: "packages/ndk" - ref: "codex/hostr-ndk-fixes-upstream-master" - resolved-ref: "85f5ca2d3791b56149caaac09a0877b658f56d5a" + ref: "feat/ndk-marketplace" + resolved-ref: "3e3bf19ae4535d726059ab78e366c82414802d98" url: "https://github.com/sudonym-btc/ndk.git" source: git version: "0.8.2-dev.8" diff --git a/escrow/pubspec.yaml b/escrow/pubspec.yaml index 7cce543b..25ca1192 100644 --- a/escrow/pubspec.yaml +++ b/escrow/pubspec.yaml @@ -33,7 +33,7 @@ dependency_overrides: ndk: git: url: https://github.com/sudonym-btc/ndk.git - ref: codex/hostr-ndk-fixes-upstream-master + ref: feat/ndk-marketplace path: packages/ndk pointycastle: ^4.0.0 js: ^0.7.2 diff --git a/hostr_cli/lib/src/actions/hostr_actions.dart b/hostr_cli/lib/src/actions/hostr_actions.dart index 0ee2d118..4b9605f8 100644 --- a/hostr_cli/lib/src/actions/hostr_actions.dart +++ b/hostr_cli/lib/src/actions/hostr_actions.dart @@ -407,8 +407,8 @@ class HostrListingsAvailabilityInput { } } -class HostrReservationsOfferInput { - const HostrReservationsOfferInput({ +class HostrOrdersOfferInput { + const HostrOrdersOfferInput({ this.listingAnchor, this.start, this.end, @@ -428,13 +428,13 @@ class HostrReservationsOfferInput { bool get isFollowUpOffer => tradeId != null; - factory HostrReservationsOfferInput.fromJson(Map json) { + factory HostrOrdersOfferInput.fromJson(Map json) { final tradeId = _optionalString(json['tradeId']); final listingAnchor = _optionalString( json['listingAnchor'] ?? json['anchor'], ); if (tradeId != null) { - return HostrReservationsOfferInput( + return HostrOrdersOfferInput( tradeId: tradeId, amount: json['amount'] is Map ? HostrAmountInput.fromJson( @@ -450,7 +450,7 @@ class HostrReservationsOfferInput { if (listingAnchor == null) { throw const FormatException('Missing required listingAnchor or tradeId.'); } - return HostrReservationsOfferInput( + return HostrOrdersOfferInput( listingAnchor: listingAnchor, start: DateTime.parse(_requiredString(json, 'start')), end: DateTime.parse(_requiredString(json, 'end')), @@ -475,8 +475,8 @@ class HostrReservationsOfferInput { }; } -class HostrReservationBookAndPayInput { - const HostrReservationBookAndPayInput({ +class HostrOrderBookAndPayInput { + const HostrOrderBookAndPayInput({ required this.listingAnchor, required this.start, required this.end, @@ -492,8 +492,8 @@ class HostrReservationBookAndPayInput { final String? escrowServiceId; final int proofTimeoutSeconds; - factory HostrReservationBookAndPayInput.fromJson(Map json) { - return HostrReservationBookAndPayInput( + factory HostrOrderBookAndPayInput.fromJson(Map json) { + return HostrOrderBookAndPayInput( listingAnchor: _requiredString(json, 'listingAnchor'), start: DateTime.parse(_requiredString(json, 'start')), end: DateTime.parse(_requiredString(json, 'end')), @@ -517,8 +517,8 @@ class HostrReservationBookAndPayInput { }; } -class HostrReservationTradeInput { - const HostrReservationTradeInput({ +class HostrOrderTradeInput { + const HostrOrderTradeInput({ required this.tradeId, this.amount, this.reason, @@ -532,8 +532,8 @@ class HostrReservationTradeInput { final bool dryRun; final int timeoutSeconds; - factory HostrReservationTradeInput.fromJson(Map json) { - return HostrReservationTradeInput( + factory HostrOrderTradeInput.fromJson(Map json) { + return HostrOrderTradeInput( tradeId: _requiredString(json, 'tradeId'), amount: json['amount'] is Map ? HostrAmountInput.fromJson(Map.from(json['amount'])) @@ -547,8 +547,8 @@ class HostrReservationTradeInput { } } -class HostrReservationReviewInput { - const HostrReservationReviewInput({ +class HostrOrderReviewInput { + const HostrOrderReviewInput({ required this.tradeId, required this.rating, required this.content, @@ -562,9 +562,9 @@ class HostrReservationReviewInput { final bool dryRun; final int timeoutSeconds; - factory HostrReservationReviewInput.fromJson(Map json) { + factory HostrOrderReviewInput.fromJson(Map json) { final rating = (_optionalInt(json['rating']) ?? 0).clamp(1, 5).toInt(); - return HostrReservationReviewInput( + return HostrOrderReviewInput( tradeId: _requiredString(json, 'tradeId'), rating: rating, content: _requiredString(json, 'content'), @@ -576,8 +576,8 @@ class HostrReservationReviewInput { } } -class HostrReservationPayInput { - const HostrReservationPayInput({ +class HostrOrderPayInput { + const HostrOrderPayInput({ required this.tradeId, this.escrowServiceId, this.dryRun = true, @@ -589,8 +589,8 @@ class HostrReservationPayInput { final bool dryRun; final int timeoutSeconds; - factory HostrReservationPayInput.fromJson(Map json) { - return HostrReservationPayInput( + factory HostrOrderPayInput.fromJson(Map json) { + return HostrOrderPayInput( tradeId: _requiredString(json, 'tradeId'), escrowServiceId: _optionalString(json['escrowServiceId']), dryRun: _optionalBool(json['dryRun']) ?? true, @@ -601,8 +601,8 @@ class HostrReservationPayInput { } } -class HostrReservationCommitInput { - const HostrReservationCommitInput({ +class HostrOrderCommitInput { + const HostrOrderCommitInput({ required this.swapId, this.dryRun = true, this.timeoutSeconds = 12, @@ -612,8 +612,8 @@ class HostrReservationCommitInput { final bool dryRun; final int timeoutSeconds; - factory HostrReservationCommitInput.fromJson(Map json) { - return HostrReservationCommitInput( + factory HostrOrderCommitInput.fromJson(Map json) { + return HostrOrderCommitInput( swapId: _requiredString(json, 'swapId'), dryRun: _optionalBool(json['dryRun']) ?? true, timeoutSeconds: (_optionalInt(json['timeoutSeconds']) ?? 12) @@ -775,8 +775,8 @@ class HostrProfileLookupInput { } } -class HostrReservationCollectionInput { - const HostrReservationCollectionInput({ +class HostrOrderCollectionInput { + const HostrOrderCollectionInput({ this.limit = 50, this.tradeId, this.waitSeconds = 15, @@ -786,8 +786,8 @@ class HostrReservationCollectionInput { final String? tradeId; final int waitSeconds; - factory HostrReservationCollectionInput.fromJson(Map json) { - return HostrReservationCollectionInput( + factory HostrOrderCollectionInput.fromJson(Map json) { + return HostrOrderCollectionInput( limit: (_optionalInt(json['limit']) ?? 50).clamp(1, 200).toInt(), tradeId: _optionalString(json['tradeId']), waitSeconds: (_optionalInt(json['waitSeconds']) ?? 15) @@ -1223,21 +1223,21 @@ class HostrActionSpec { return 'Use after a user has selected one or more listings and supplied dates, before booking or explaining date conflicts. Pass listing anchors from search/list results. If dates are missing, ask for them instead of guessing.'; case 'hostr.listings.reviews': return 'Use when the user asks about reviews, reputation, prior guest feedback, or trust signals for one or more listings. Pass listing anchors from search/list results.'; - case 'hostr.listings.reservationGroups': + case 'hostr.listings.orderGroups': return 'Use when the user asks why dates are unavailable, wants booking history/conflicts for a listing, or needs reservation context before changing availability-sensitive plans.'; - case 'hostr.reservations.bookAndPay': - return 'Primary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_reservations_commit for this normal path; proof publication is owned by the global payment proof orchestrator.'; - case 'hostr.reservations.negotiateOffer': - return 'Negotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward "book/reserve" intents on instant-book listings; use hostr_reservations_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.'; - case 'hostr.reservations.negotiateAccept': + case 'hostr.orders.bookAndPay': + return 'Primary guest booking flow: use this when the user says book, reserve, make a reservation, create a reservation, or otherwise clearly wants an instant-book stay at or above the listed price. If the user says guest, my guest account, my trip, or similar, make sure the active account is the guest account first by using session account tools; do not book from an unrelated host or escrow account just because it is already active. It creates the private offer, prepares escrow funding, returns external Lightning payment details when needed, and keeps the daemon-side book-and-pay operation alive. The committed reservation and escrow trade are intentionally published under Hostr-created per-trade temporary pubkeys for privacy, so the buyer/reservation pubkey may differ from the active logged-in Hostr account. Treat that as normal and never describe it as an identity mismatch. If invoice/QR are returned, show only the invoice string and QR image visibly in the payment prompt; keep internal tradeId and swapId hidden from the user-facing payment message. The next assistant action after rendering the payment prompt must be hostr_swaps_watch with swapId, tradeId, and reservationWaitSeconds to monitor payment/proof/reservation completion. Do not stop after displaying the invoice or wait for the user to say they paid. reservationWaitSeconds is intentionally short and capped below MCP client timeouts; if watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. When watch completes or cannot find the swap, call hostr_trips_list with the same tradeId until the committed reservation appears. Do not call hostr_orders_commit for this normal path; proof publication is owned by the global payment proof orchestrator.'; + case 'hostr.orders.negotiateOffer': + return 'Negotiation-only flow: use for explicit offers, counteroffers, price/date negotiation, or non-instant-book reservation proposals. Do not use this for straightforward "book/reserve" intents on instant-book listings; use hostr_orders_bookAndPay there. Preview with dryRun=true, then send the private negotiation event with dryRun=false only after approval.'; + case 'hostr.orders.negotiateAccept': return 'Use when the user wants to accept the latest private negotiated offer in a known trade thread. If tradeId is unknown, call hostr_updates, hostr_thread_view, hostr_trips_list, or hostr_bookings_list first to identify the trade.'; - case 'hostr.reservations.pay': - return 'Manual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_reservations_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.'; - case 'hostr.reservations.commit': - return 'Manual recovery/debug commit flow only. Do not use after hostr_reservations_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.'; - case 'hostr.reservations.cancel': + case 'hostr.orders.pay': + return 'Manual recovery/debug payment flow only. Normal AI-initiated instant-book payment should use hostr_orders_bookAndPay. Use this when a negotiated or partially completed trade already exists and the user explicitly wants to create or inspect escrow funding for that trade.'; + case 'hostr.orders.commit': + return 'Manual recovery/debug commit flow only. Do not use after hostr_orders_bookAndPay; that path relies on the global payment proof orchestrator. Use only when a swap proof already exists for a trade and the user explicitly needs to preview or publish the public commit-stage reservation.'; + case 'hostr.orders.cancel': return 'Use to cancel a private negotiation or committed reservation for a concrete trade. If tradeId is unclear, inspect updates, trips, bookings, or thread view first. Preview the cancellation and send with dryRun=false only after explicit approval.'; - case 'hostr.reservations.review': + case 'hostr.orders.review': return 'Use when the guest wants to leave a rating/review for a completed or confirmed Hostr trip. If tradeId is unclear, inspect hostr_trips_list first. Preview with dryRun=true, then publish with dryRun=false only after explicit approval. Skip this action if no committed reservation can be found for the trade.'; case 'hostr.updates': return 'Use as the inbox/home-state tool when the user asks for messages, offers, notifications, reviews, trips, bookings, reservation references, latest activity, "what are my updates", "my host has not replied", or what needs attention. It processes gift-wrapped inbox events and returns thread cards, reviews left on the user\'s listings, trips the user booked, and hosting reservations. Present displayMarkdown, not raw event JSON.'; @@ -1254,7 +1254,7 @@ class HostrActionSpec { case 'hostr.profile.edit': return 'Use when the user wants to update profile name, about/bio, picture, banner, website, lightning address, or other profile metadata. Preview first; publish only after approval. Publishing also refreshes Hostr seller configuration, which is useful before creating or editing listings.'; case 'hostr.trips.list': - return 'Use for guest-side reservations: "my trips", "my bookings as guest", "my reservation reference", "did my reservation complete", "my host has not replied", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_reservations_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.'; + return 'Use for guest-side reservations: "my trips", "my bookings as guest", "my reservation reference", "did my reservation complete", "my host has not replied", or after book-and-pay/swap watch with tradeId to wait for the committed reservation card. Do not use this as the first monitor immediately after a payment-required hostr_orders_bookAndPay result; first call hostr_swaps_watch with the required next-tool arguments, then use trips once the swap watch resolves or reports the reservation is pending. Trip cards may resolve committed reservations authored by Hostr-created per-trade temporary pubkeys; this is expected privacy behavior for the active account, not a mismatch. Do not perform fresh reservation-by-author Nostr queries for this view.'; case 'hostr.bookings.list': return 'Use for host-side reservations on listings authored by the authenticated user: "my bookings", "who booked my place", "hosting reservations", or host calendar context. Do not use this as the first monitor immediately after a payment-required guest booking; hostr_swaps_watch comes first. Do not perform fresh reservation-by-author Nostr queries for this view.'; case 'hostr.escrow.methods': @@ -1288,7 +1288,7 @@ class HostrActionSpec { case 'hostr.escrow.badges.revoke': return 'Escrow-operator destructive award workflow: preview revocation/deletion of an issued badge award and publish only after explicit approval. Include a reason when provided.'; case 'hostr.swaps.watch': - return 'Read-only monitor to use immediately after hostr_reservations_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.'; + return 'Read-only monitor to use immediately after hostr_orders_bookAndPay returns swapId/tradeId, or when inspecting a specific swap. It observes persisted swap/payment/proof state and optionally waits briefly for the committed reservation by tradeId. Keep reservationWaitSeconds short; the schema caps it at 60 seconds so the tool returns before MCP client timeouts. If watch times out before the swap or reservation returns, call hostr_swaps_watch again with the returned retry arguments. If the swap has completed but the reservation is still pending, call hostr_trips_list with the same tradeId or call hostr_swaps_watch again with retry arguments. The committed reservation may be authored by a Hostr-created per-trade temporary pubkey for privacy; do not flag this as different from the active account. It has no dryRun parameter and does not recover stale swaps; use hostr_swaps_recoverAll for explicit recovery.'; case 'hostr.swaps.recoverAll': return 'Use when the user asks to recover stuck payments/swaps or when diagnostics show persisted swap operations need resumption. Preview first; run with dryRun=false only after approval. Use background=true only when the user wants recovery to continue asynchronously.'; case 'hostr.swaps.list': @@ -1388,7 +1388,7 @@ const Map _tradeInputSchema = { }; const String _tradeTypescriptInput = ''' -export interface HostrReservationTradeInput { +export interface HostrOrderTradeInput { tradeId: string; amount?: HostrAmountInput; reason?: string; @@ -1995,8 +1995,8 @@ export interface HostrListingsAvailabilityInput { typescriptInput: _anchorsTypescriptInput, ); - static const listingsReservationGroups = HostrActionSpec( - id: 'hostr.listings.reservationGroups', + static const listingsOrderGroups = HostrActionSpec( + id: 'hostr.listings.orderGroups', title: 'Fetch Listing Reservation Groups', description: 'Fetch public reservation groups for one or more listings. Use this before availability-sensitive reservation workflows when the agent needs to explain conflicts.', @@ -2007,11 +2007,11 @@ export interface HostrListingsAvailabilityInput { ); static const reservationsOffer = HostrActionSpec( - id: 'hostr.reservations.negotiateOffer', + id: 'hostr.orders.negotiateOffer', title: 'Create Reservation Negotiation Offer', description: - 'Create only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like "book", "reserve", "make a reservation", or instant-book at the listed price; those must use hostr_reservations_bookAndPay instead.', - inputTypeName: 'HostrReservationsOfferInput', + 'Create only a private negotiate-stage reservation offer. Use this for explicit negotiation/counteroffer requests, not for user intents like "book", "reserve", "make a reservation", or instant-book at the listed price; those must use hostr_orders_bookAndPay instead.', + inputTypeName: 'HostrOrdersOfferInput', readOnly: false, inputSchema: { 'type': 'object', @@ -2087,7 +2087,7 @@ export interface HostrAmountInput { decimals?: number; } -export interface HostrReservationsOfferInput { +export interface HostrOrdersOfferInput { /** Listing naddr/a-tag anchor for a first offer. */ listingAnchor?: string; /** Single listing anchor alternative to listingAnchor. */ @@ -2108,7 +2108,7 @@ export interface HostrReservationsOfferInput { ); static const reservationsBookAndPay = HostrActionSpec( - id: 'hostr.reservations.bookAndPay', + id: 'hostr.orders.bookAndPay', title: 'Start Reservation Payment', description: 'Use this foreground handoff tool whenever the user says to ' @@ -2137,9 +2137,9 @@ export interface HostrReservationsOfferInput { 'again with the returned retry arguments. When watch completes or ' 'cannot find the swap, query `hostr_trips_list` with `tradeId` until ' 'the committed reservation appears, then show a reservation card. Do ' - 'not call `hostr_reservations_commit`; proof publication is owned by ' + 'not call `hostr_orders_commit`; proof publication is owned by ' 'the global Hostr payment proof orchestrator.', - inputTypeName: 'HostrReservationBookAndPayInput', + inputTypeName: 'HostrOrderBookAndPayInput', readOnly: false, inputSchema: { 'type': 'object', @@ -2198,7 +2198,7 @@ export interface HostrReservationsOfferInput { }, }, typescriptInput: ''' -export interface HostrReservationBookAndPayInput { +export interface HostrOrderBookAndPayInput { /** Listing naddr/a-tag anchor to instant-book. */ listingAnchor: string; /** Reservation start calendar date encoded as YYYY-MM-DDT00:00:00Z. Do not timezone-convert date-only reservation inputs. */ @@ -2216,22 +2216,22 @@ export interface HostrReservationBookAndPayInput { ); static const reservationsNegotiateAccept = HostrActionSpec( - id: 'hostr.reservations.negotiateAccept', + id: 'hostr.orders.negotiateAccept', title: 'Accept Reservation Negotiation', description: 'Accept the latest private negotiate-stage reservation offer in a trade thread by replying with a matching negotiate-stage event.', - inputTypeName: 'HostrReservationTradeInput', + inputTypeName: 'HostrOrderTradeInput', readOnly: false, inputSchema: _tradeInputSchema, typescriptInput: _tradeTypescriptInput, ); static const reservationsPay = HostrActionSpec( - id: 'hostr.reservations.pay', + id: 'hostr.orders.pay', title: 'Pay Reservation Offer', description: 'Preview or create the escrow funding swap for a payable reservation trade. The live action sends the escrow selection into the private thread as an unsigned child event, prepares the escrow fund calls, creates the Boltz swap invoice, and persists the payment context for commit.', - inputTypeName: 'HostrReservationPayInput', + inputTypeName: 'HostrOrderPayInput', readOnly: false, inputSchema: { 'type': 'object', @@ -2257,7 +2257,7 @@ export interface HostrReservationBookAndPayInput { }, }, typescriptInput: ''' -export interface HostrReservationPayInput { +export interface HostrOrderPayInput { /** Reservation trade id from negotiation updates. */ tradeId: string; /** Optional escrow service id/pubkey/contract address. */ @@ -2269,11 +2269,11 @@ export interface HostrReservationPayInput { ); static const reservationsCommit = HostrActionSpec( - id: 'hostr.reservations.commit', + id: 'hostr.orders.commit', title: 'Commit Paid Reservation', description: 'Preview or publish the public commit-stage reservation after the escrow funding swap has completed and produced a claim transaction proof.', - inputTypeName: 'HostrReservationCommitInput', + inputTypeName: 'HostrOrderCommitInput', readOnly: false, inputSchema: { 'type': 'object', @@ -2282,7 +2282,7 @@ export interface HostrReservationPayInput { 'properties': { 'swapId': { 'type': 'string', - 'description': 'Boltz swap id returned by hostr_reservations_pay.', + 'description': 'Boltz swap id returned by hostr_orders_pay.', }, 'dryRun': {'type': 'boolean', 'default': true}, 'timeoutSeconds': { @@ -2294,8 +2294,8 @@ export interface HostrReservationPayInput { }, }, typescriptInput: ''' -export interface HostrReservationCommitInput { - /** Boltz swap id returned by hostr_reservations_pay. */ +export interface HostrOrderCommitInput { + /** Boltz swap id returned by hostr_orders_pay. */ swapId: string; dryRun?: boolean; timeoutSeconds?: number; @@ -2304,22 +2304,22 @@ export interface HostrReservationCommitInput { ); static const reservationsCancel = HostrActionSpec( - id: 'hostr.reservations.cancel', + id: 'hostr.orders.cancel', title: 'Cancel Reservation', description: 'Cancel either the private negotiate-stage reservation for a trade, or the committed public reservation if one exists.', - inputTypeName: 'HostrReservationTradeInput', + inputTypeName: 'HostrOrderTradeInput', readOnly: false, inputSchema: _tradeInputSchema, typescriptInput: _tradeTypescriptInput, ); static const reservationsReview = HostrActionSpec( - id: 'hostr.reservations.review', + id: 'hostr.orders.review', title: 'Review Reservation', description: 'Preview or publish a guest review for a committed Hostr reservation. This creates a Nostr review event with a participation proof for the reservation trade; preview first and only publish after explicit approval.', - inputTypeName: 'HostrReservationReviewInput', + inputTypeName: 'HostrOrderReviewInput', readOnly: false, inputSchema: { 'type': 'object', @@ -2356,7 +2356,7 @@ export interface HostrReservationCommitInput { }, }, typescriptInput: ''' -export interface HostrReservationReviewInput { +export interface HostrOrderReviewInput { /** Reservation trade id for the trip to review. */ tradeId: string; /** Guest rating from 1 to 5. */ @@ -2641,7 +2641,7 @@ export interface HostrProfileEditInput { 'book-and-pay swap watch completes or cannot find the swap to wait ' 'briefly for the committed public reservation and return it for ' 'display.', - inputTypeName: 'HostrReservationCollectionInput', + inputTypeName: 'HostrOrderCollectionInput', readOnly: true, inputSchema: { 'type': 'object', @@ -2669,7 +2669,7 @@ export interface HostrProfileEditInput { }, }, typescriptInput: ''' -export interface HostrReservationCollectionInput { +export interface HostrOrderCollectionInput { limit?: number; tradeId?: string; waitSeconds?: number; @@ -2682,7 +2682,7 @@ export interface HostrReservationCollectionInput { title: 'List Hostr Bookings', description: 'List reservation groups where the authenticated user is the host from the live userSubscriptions.myResolvedHostingsList replay. Do not perform fresh Nostr listing/reservation-by-author queries for this view. Return the fixed hosting-card display contract with resolved participant profile names, including "Hosting {guest} at: {stay}" text.', - inputTypeName: 'HostrReservationCollectionInput', + inputTypeName: 'HostrOrderCollectionInput', readOnly: true, inputSchema: { 'type': 'object', @@ -2710,7 +2710,7 @@ export interface HostrReservationCollectionInput { }, }, typescriptInput: ''' -export interface HostrReservationCollectionInput { +export interface HostrOrderCollectionInput { limit?: number; tradeId?: string; waitSeconds?: number; @@ -3268,7 +3268,7 @@ export interface HostrSwapsListInput { 'and report payment/proof/reservation state without creating, ' 'signing, publishing, or recovering anything. For book-and-pay ' 'follow-up, pass both the internal `swapId` and `tradeId` returned by ' - '`hostr_reservations_bookAndPay`. If the swap completes or cannot be ' + '`hostr_orders_bookAndPay`. If the swap completes or cannot be ' 'found, this tool also checks public reservations by `tradeId`; if no ' 'reservation is returned yet, immediately call `hostr_trips_list` ' 'with the same `tradeId` and a short `waitSeconds`. Committed ' @@ -3341,7 +3341,7 @@ export interface HostrSwapsRecoverAllInput { listingsEdit, listingsAvailability, listingsReviews, - listingsReservationGroups, + listingsOrderGroups, reservationsBookAndPay, reservationsOffer, reservationsNegotiateAccept, @@ -3415,7 +3415,7 @@ export interface HostrSwapsRecoverAllInput { ) ..writeln() ..writeln( - 'Most write tools default to preview mode. Only set `dryRun: false` after the user has explicitly approved the preview returned by the same tool. `hostr_reservations_bookAndPay` is the correct foreground handoff tool when the user asks to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. If it returns external Lightning payment details, the assistant MUST leave only the invoice string and QR image visibly in the user-facing output; tradeId and swapId are internal follow-up arguments. The next assistant action after rendering the QR and invoice must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. `reservationWaitSeconds` is capped below MCP client timeouts. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator.', + 'Most write tools default to preview mode. Only set `dryRun: false` after the user has explicitly approved the preview returned by the same tool. `hostr_orders_bookAndPay` is the correct foreground handoff tool when the user asks to book, reserve, make, or create a reservation for an instant-book listing at or above the listed price. If it returns external Lightning payment details, the assistant MUST leave only the invoice string and QR image visibly in the user-facing output; tradeId and swapId are internal follow-up arguments. The next assistant action after rendering the QR and invoice must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. `reservationWaitSeconds` is capped below MCP client timeouts. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator.', ) ..writeln() ..writeln('## Reservation date semantics') @@ -3441,19 +3441,19 @@ export interface HostrSwapsRecoverAllInput { ..writeln('### Search and reserve workflow') ..writeln() ..writeln( - 'Call `hostr_listings_search`, then `hostr_listings_availability`. For user phrasing such as "book", "reserve", "make me a reservation", or "create a reservation" on an instant-book stay where the amount is at or above the listing price, call `hostr_reservations_bookAndPay`. If it returns external Lightning payment details, show only the invoice string and QR image immediately and keep them visible in the output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; proof publication is owned by the global Hostr payment proof orchestrator. Do not stop after `hostr_reservations_negotiateOffer` for this intent. For explicit negotiation-only requests, call `hostr_reservations_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM.', + 'Call `hostr_listings_search`, then `hostr_listings_availability`. For user phrasing such as "book", "reserve", "make me a reservation", or "create a reservation" on an instant-book stay where the amount is at or above the listing price, call `hostr_orders_bookAndPay`. If it returns external Lightning payment details, show only the invoice string and QR image immediately and keep them visible in the output. Do not show internal tradeId or swapId in the payment prompt. The next assistant action after rendering the payment prompt must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds`; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; proof publication is owned by the global Hostr payment proof orchestrator. Do not stop after `hostr_orders_negotiateOffer` for this intent. For explicit negotiation-only requests, call `hostr_orders_negotiateOffer` with `dryRun: true`; repeat with `dryRun: false` to send the private negotiate-stage reservation DM.', ) ..writeln() ..writeln('### Negotiation workflow') ..writeln() ..writeln( - 'Call `hostr_updates` to inspect thread/trade ids. Use `hostr_reservations_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_reservations_negotiateAccept` to accept the latest offer, or `hostr_reservations_cancel` to cancel the private negotiation or committed reservation.', + 'Call `hostr_updates` to inspect thread/trade ids. Use `hostr_orders_negotiateOffer` with `tradeId` and `amount` to send a follow-up offer, `hostr_orders_negotiateAccept` to accept the latest offer, or `hostr_orders_cancel` to cancel the private negotiation or committed reservation.', ) ..writeln() ..writeln('### Payment workflow') ..writeln() ..writeln( - 'For normal AI-initiated instant-book payment, use `hostr_reservations_bookAndPay`. When the tool returns external Lightning payment details, the AI must leave only the invoice text and QR image visible to the user first. The next assistant action must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion while the daemon continues the book-and-pay operation in the background; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_reservations_commit`; payment proof publication is owned by the global Hostr payment proof orchestrator. Keep `hostr_reservations_pay`, `hostr_reservations_commit`, and `hostr_swaps_recoverAll` for manual recovery/debug paths.', + 'For normal AI-initiated instant-book payment, use `hostr_orders_bookAndPay`. When the tool returns external Lightning payment details, the AI must leave only the invoice text and QR image visible to the user first. The next assistant action must be the read-only `hostr_swaps_watch` with the returned `swapId`, `tradeId`, and `reservationWaitSeconds` to monitor payment/proof/reservation completion while the daemon continues the book-and-pay operation in the background; do not stop after displaying the invoice or wait for the user to say they paid. If watch times out before the swap or reservation returns, call `hostr_swaps_watch` again with the returned retry arguments. When watch completes or cannot find the swap, call `hostr_trips_list` with the same `tradeId` until the committed reservation appears, then show a reservation card. Do not call `hostr_orders_commit`; payment proof publication is owned by the global Hostr payment proof orchestrator. Keep `hostr_orders_pay`, `hostr_orders_commit`, and `hostr_swaps_recoverAll` for manual recovery/debug paths.', ) ..writeln() ..writeln('### Messaging workflow') @@ -3465,7 +3465,7 @@ export interface HostrSwapsRecoverAllInput { ..writeln('### Review workflow') ..writeln() ..writeln( - 'When a guest asks to review a trip, identify the trade with `hostr_trips_list`, call `hostr_reservations_review` with `dryRun: true`, show the preview, then repeat with `dryRun: false` only after explicit approval. If no committed reservation can be found, skip the review action and explain that the trip is not reviewable yet.', + 'When a guest asks to review a trip, identify the trade with `hostr_trips_list`, call `hostr_orders_review` with `dryRun: true`, show the preview, then repeat with `dryRun: false` only after explicit approval. If no committed reservation can be found, skip the review action and explain that the trip is not reviewable yet.', ) ..writeln() ..writeln('### Swaps workflow') diff --git a/hostr_cli/lib/src/commands/listings_command.dart b/hostr_cli/lib/src/commands/listings_command.dart index 077b425d..5331cc34 100644 --- a/hostr_cli/lib/src/commands/listings_command.dart +++ b/hostr_cli/lib/src/commands/listings_command.dart @@ -13,7 +13,7 @@ class ListingsCommand extends Command { addSubcommand(ListingsEditCommand(stdout: stdout, stderr: stderr)); addSubcommand(ListingsAvailableCommand(stdout: stdout, stderr: stderr)); addSubcommand(ListingsReviewsCommand(stdout: stdout, stderr: stderr)); - addSubcommand(ListingsReservationsCommand(stdout: stdout, stderr: stderr)); + addSubcommand(ListingsOrdersCommand(stdout: stdout, stderr: stderr)); } @override @@ -218,22 +218,22 @@ class ListingsReviewsCommand extends HostrCliCommand { ); } -class ListingsReservationsCommand extends HostrCliCommand { - ListingsReservationsCommand({required super.stdout, required super.stderr}) { +class ListingsOrdersCommand extends HostrCliCommand { + ListingsOrdersCommand({required super.stdout, required super.stderr}) { argParser.addOption('input', help: 'JSON input with anchors.'); argParser.addMultiOption('anchor', help: 'Listing anchor.'); } @override - final String name = 'reservations'; + final String name = 'orders'; @override - final String description = 'Fetch reservation groups for listings.'; + final String description = 'Fetch order groups for listings.'; @override Future runCommand() => runSharedAction( this, - action: 'hostr.listings.reservationGroups', + action: 'hostr.listings.orderGroups', input: _anchorsInput(this), ); } diff --git a/hostr_cli/lib/src/commands/reservations_command.dart b/hostr_cli/lib/src/commands/orders_command.dart similarity index 71% rename from hostr_cli/lib/src/commands/reservations_command.dart rename to hostr_cli/lib/src/commands/orders_command.dart index 51af413d..91f40a98 100644 --- a/hostr_cli/lib/src/commands/reservations_command.dart +++ b/hostr_cli/lib/src/commands/orders_command.dart @@ -6,33 +6,31 @@ import 'package:args/command_runner.dart'; import 'action_bridge.dart'; import 'base.dart'; -class ReservationsCommand extends Command { - ReservationsCommand({required IOSink stdout, required IOSink stderr}) { - addSubcommand(ReservationOfferCommand(stdout: stdout, stderr: stderr)); - addSubcommand(ReservationPayCommand(stdout: stdout, stderr: stderr)); - addSubcommand(ReservationCommitCommand(stdout: stdout, stderr: stderr)); - addSubcommand(ReservationCancelCommand(stdout: stdout, stderr: stderr)); - addSubcommand( - ReservationNegotiationCommand(stdout: stdout, stderr: stderr), - ); +class OrdersCommand extends Command { + OrdersCommand({required IOSink stdout, required IOSink stderr}) { + addSubcommand(OrderOfferCommand(stdout: stdout, stderr: stderr)); + addSubcommand(OrderPayCommand(stdout: stdout, stderr: stderr)); + addSubcommand(OrderCommitCommand(stdout: stdout, stderr: stderr)); + addSubcommand(OrderCancelCommand(stdout: stdout, stderr: stderr)); + addSubcommand(OrderNegotiationCommand(stdout: stdout, stderr: stderr)); addSubcommand(TripsListCommand(stdout: stdout, stderr: stderr)); addSubcommand(BookingsListCommand(stdout: stdout, stderr: stderr)); } @override - final String name = 'reservations'; + final String name = 'orders'; @override - final String description = 'Create and manage Hostr reservations.'; + final String description = 'Create and manage Hostr marketplace orders.'; } -class ReservationOfferCommand extends HostrCliCommand { - ReservationOfferCommand({required super.stdout, required super.stderr}) { +class OrderOfferCommand extends HostrCliCommand { + OrderOfferCommand({required super.stdout, required super.stderr}) { argParser ..addOption( 'input', mandatory: true, - help: 'Reservation JSON input file, inline object, or "-".', + help: 'Order JSON input file, inline object, or "-".', ) ..addFlag( 'yes', @@ -47,22 +45,22 @@ class ReservationOfferCommand extends HostrCliCommand { @override final String description = - 'Send a private gift-wrapped negotiate-stage reservation offer.'; + 'Send a private gift-wrapped negotiate-stage order offer.'; @override Future runCommand() async { final input = readInputObject(); return runSharedAction( this, - action: 'hostr.reservations.negotiateOffer', + action: 'hostr.orders.negotiateOffer', input: input, requireYesForLive: true, ); } } -class ReservationPayCommand extends HostrCliCommand { - ReservationPayCommand({required super.stdout, required super.stderr}) { +class OrderPayCommand extends HostrCliCommand { + OrderPayCommand({required super.stdout, required super.stderr}) { argParser ..addOption( 'trade-context', @@ -82,29 +80,29 @@ class ReservationPayCommand extends HostrCliCommand { @override final String description = - 'Create the Boltz swap invoice for a payable reservation trade.'; + 'Create the Boltz swap invoice for a payable order trade.'; @override Future runCommand() async { final input = _readTradeContextArg(this); return runSharedAction( this, - action: 'hostr.reservations.pay', + action: 'hostr.orders.pay', input: input, requireYesForLive: true, ); } } -class ReservationCommitCommand extends HostrCliCommand { - ReservationCommitCommand({required super.stdout, required super.stderr}) { +class OrderCommitCommand extends HostrCliCommand { + OrderCommitCommand({required super.stdout, required super.stderr}) { argParser ..addOption('swap-id', mandatory: true, help: 'Boltz swap id.') ..addFlag( 'yes', abbr: 'y', negatable: false, - help: 'Publish the committed reservation without prompting.', + help: 'Publish the committed order without prompting.', ); } @@ -113,22 +111,22 @@ class ReservationCommitCommand extends HostrCliCommand { @override final String description = - 'Publish a public commit-stage reservation with escrow proof.'; + 'Publish a public commit-stage order with escrow proof.'; @override Future runCommand() async { final swapId = (argResults?['swap-id'] as String).trim(); return runSharedAction( this, - action: 'hostr.reservations.commit', + action: 'hostr.orders.commit', input: {'swapId': swapId}, requireYesForLive: true, ); } } -class ReservationCancelCommand extends HostrCliCommand { - ReservationCancelCommand({required super.stdout, required super.stderr}) { +class OrderCancelCommand extends HostrCliCommand { + OrderCancelCommand({required super.stdout, required super.stderr}) { argParser ..addOption( 'input', @@ -147,31 +145,25 @@ class ReservationCancelCommand extends HostrCliCommand { final String name = 'cancel'; @override - final String description = - 'Cancel a private negotiation or a committed reservation.'; + final String description = 'Cancel a private negotiation or committed order.'; @override Future runCommand() async { final input = readInputObject(); return runSharedAction( this, - action: 'hostr.reservations.cancel', + action: 'hostr.orders.cancel', input: input, requireYesForLive: true, ); } } -class ReservationNegotiationCommand extends Command { - ReservationNegotiationCommand({ - required IOSink stdout, - required IOSink stderr, - }) { +class OrderNegotiationCommand extends Command { + OrderNegotiationCommand({required IOSink stdout, required IOSink stderr}) { + addSubcommand(OrderNegotiationOfferCommand(stdout: stdout, stderr: stderr)); addSubcommand( - ReservationNegotiationOfferCommand(stdout: stdout, stderr: stderr), - ); - addSubcommand( - ReservationNegotiationAcceptCommand(stdout: stdout, stderr: stderr), + OrderNegotiationAcceptCommand(stdout: stdout, stderr: stderr), ); } @@ -179,14 +171,11 @@ class ReservationNegotiationCommand extends Command { final String name = 'negotiation'; @override - final String description = 'Manage reservation negotiation events.'; + final String description = 'Manage order negotiation events.'; } -class ReservationNegotiationOfferCommand extends HostrCliCommand { - ReservationNegotiationOfferCommand({ - required super.stdout, - required super.stderr, - }) { +class OrderNegotiationOfferCommand extends HostrCliCommand { + OrderNegotiationOfferCommand({required super.stdout, required super.stderr}) { argParser ..addOption( 'input', @@ -205,22 +194,22 @@ class ReservationNegotiationOfferCommand extends HostrCliCommand { final String name = 'offer'; @override - final String description = 'Send a reservation negotiation offer.'; + final String description = 'Send an order negotiation offer.'; @override Future runCommand() async { final input = readInputObject(); return runSharedAction( this, - action: 'hostr.reservations.negotiateOffer', + action: 'hostr.orders.negotiateOffer', input: input, requireYesForLive: true, ); } } -class ReservationNegotiationAcceptCommand extends HostrCliCommand { - ReservationNegotiationAcceptCommand({ +class OrderNegotiationAcceptCommand extends HostrCliCommand { + OrderNegotiationAcceptCommand({ required super.stdout, required super.stderr, }) { @@ -242,14 +231,14 @@ class ReservationNegotiationAcceptCommand extends HostrCliCommand { final String name = 'accept'; @override - final String description = 'Accept the latest reservation negotiation offer.'; + final String description = 'Accept the latest order negotiation offer.'; @override Future runCommand() async { final input = readInputObject(); return runSharedAction( this, - action: 'hostr.reservations.negotiateAccept', + action: 'hostr.orders.negotiateAccept', input: input, requireYesForLive: true, ); @@ -266,7 +255,7 @@ class TripsListCommand extends HostrCliCommand { @override final String description = - 'List reservation events involving the active user as guest.'; + 'List order events involving the active user as guest.'; @override Future runCommand() => @@ -283,7 +272,7 @@ class BookingsListCommand extends HostrCliCommand { @override final String description = - 'List reservation events for listings authored by the active user.'; + 'List order events for listings authored by the active user.'; @override Future runCommand() => diff --git a/hostr_cli/lib/src/daemon/hostr_daemon.dart b/hostr_cli/lib/src/daemon/hostr_daemon.dart index 9da1bc5f..016d1126 100644 --- a/hostr_cli/lib/src/daemon/hostr_daemon.dart +++ b/hostr_cli/lib/src/daemon/hostr_daemon.dart @@ -113,6 +113,7 @@ class HostrDaemon { input: input, notificationToken: notificationToken, traceId: traceId, + hydrateAuthenticatedSession: false, ); }, traceId: traceId); } @@ -191,10 +192,12 @@ class HostrDaemon { String? notificationToken, String? traceId, HostrCancellationToken? cancellationToken, + bool hydrateAuthenticatedSession = true, }) async { cancellationToken?.throwIfCancelled(); final activePubkey = session.auth.activePubkey; - if (activePubkey != null && + if (hydrateAuthenticatedSession && + activePubkey != null && activePubkey.isNotEmpty && !session.auth.needsBunkerRecovery && await session.auth.isAuthenticated()) { @@ -284,33 +287,33 @@ class HostrDaemon { HostrListingsAnchorsInput.fromJson(input), ), ), - 'hostr.listings.reservationGroups' => ( + 'hostr.listings.orderGroups' => ( dryRun: false, - data: await _listingsReservationGroups( + data: await _listingsOrderGroups( session, HostrListingsAnchorsInput.fromJson(input), ), ), - 'hostr.reservations.negotiateOffer' => await () async { - final offerInput = HostrReservationsOfferInput.fromJson(input); + 'hostr.orders.negotiateOffer' => await () async { + final offerInput = HostrOrdersOfferInput.fromJson(input); return ( dryRun: offerInput.dryRun, data: await _reservationsOffer(tokenPubkey, session, offerInput), ); }(), - 'hostr.reservations.bookAndPay' => ( + 'hostr.orders.bookAndPay' => ( dryRun: false, data: await _reservationsBookAndPay( tokenPubkey, session, - HostrReservationBookAndPayInput.fromJson(input), + HostrOrderBookAndPayInput.fromJson(input), notificationToken: notificationToken, traceId: traceId, cancellationToken: cancellationToken, ), ), - 'hostr.reservations.negotiateAccept' => await () async { - final tradeInput = HostrReservationTradeInput.fromJson(input); + 'hostr.orders.negotiateAccept' => await () async { + final tradeInput = HostrOrderTradeInput.fromJson(input); return ( dryRun: tradeInput.dryRun, data: await _reservationsOfferOrAccept( @@ -321,29 +324,29 @@ class HostrDaemon { ), ); }(), - 'hostr.reservations.pay' => await () async { - final payInput = HostrReservationPayInput.fromJson(input); + 'hostr.orders.pay' => await () async { + final payInput = HostrOrderPayInput.fromJson(input); return ( dryRun: payInput.dryRun, data: await _reservationsPay(tokenPubkey, session, payInput), ); }(), - 'hostr.reservations.commit' => await () async { - final commitInput = HostrReservationCommitInput.fromJson(input); + 'hostr.orders.commit' => await () async { + final commitInput = HostrOrderCommitInput.fromJson(input); return ( dryRun: commitInput.dryRun, data: await _reservationsCommit(tokenPubkey, session, commitInput), ); }(), - 'hostr.reservations.cancel' => await () async { - final tradeInput = HostrReservationTradeInput.fromJson(input); + 'hostr.orders.cancel' => await () async { + final tradeInput = HostrOrderTradeInput.fromJson(input); return ( dryRun: tradeInput.dryRun, data: await _reservationsCancel(tokenPubkey, session, tradeInput), ); }(), - 'hostr.reservations.review' => await () async { - final reviewInput = HostrReservationReviewInput.fromJson(input); + 'hostr.orders.review' => await () async { + final reviewInput = HostrOrderReviewInput.fromJson(input); return ( dryRun: reviewInput.dryRun, data: await _reservationsReview(tokenPubkey, session, reviewInput), @@ -402,7 +405,7 @@ class HostrDaemon { data: await _reservationCollection( tokenPubkey, session, - HostrReservationCollectionInput.fromJson(input), + HostrOrderCollectionInput.fromJson(input), mode: 'trips', ), ), @@ -411,7 +414,7 @@ class HostrDaemon { data: await _reservationCollection( tokenPubkey, session, - HostrReservationCollectionInput.fromJson(input), + HostrOrderCollectionInput.fromJson(input), mode: 'bookings', ), ), @@ -580,7 +583,7 @@ class HostrDaemon { }; keepNotificationOperation = - action == 'hostr.reservations.bookAndPay' && + action == 'hostr.orders.bookAndPay' && result.data['continuesInBackground'] == true; return HostrCliResult( @@ -1648,7 +1651,7 @@ class HostrDaemon { results.add({'anchor': anchor, 'found': false, 'available': false}); continue; } - final groups = await session.reservations.queryReservationGroups( + final groups = await session.orderWorkflows.queryOrderGroups( listing: listing, ); results.add({ @@ -1682,7 +1685,7 @@ class HostrDaemon { return {'tag': kListingRefTag, 'results': results}; } - Future> _listingsReservationGroups( + Future> _listingsOrderGroups( HostrSession session, HostrListingsAnchorsInput input, ) async { @@ -1724,7 +1727,7 @@ class HostrDaemon { }); continue; } - final groups = await session.reservations.queryReservationGroups( + final groups = await session.orderWorkflows.queryOrderGroups( listing: listing, ); results.add({ @@ -1743,13 +1746,13 @@ class HostrDaemon { Future> _reservationsOffer( String tokenPubkey, HostrSession session, - HostrReservationsOfferInput input, + HostrOrdersOfferInput input, ) async { if (input.isFollowUpOffer) { return _reservationsOfferOrAccept( tokenPubkey, session, - HostrReservationTradeInput( + HostrOrderTradeInput( tradeId: input.tradeId!, amount: input.amount, dryRun: input.dryRun, @@ -1773,7 +1776,7 @@ class HostrDaemon { details: {'anchor': input.listingAnchor}, ); } - final groups = await session.reservations.queryReservationGroups( + final groups = await session.orderWorkflows.queryOrderGroups( listing: listing, ); if (!Listing.isAvailable( @@ -1847,7 +1850,7 @@ class HostrDaemon { Future> _reservationsBookAndPay( String tokenPubkey, HostrSession session, - HostrReservationBookAndPayInput input, { + HostrOrderBookAndPayInput input, { String? notificationToken, String? traceId, HostrCancellationToken? cancellationToken, @@ -1884,7 +1887,7 @@ class HostrDaemon { accountSeedStore: session.accountSeedStore, auth: session.auth, listings: session.listings, - reservations: session.reservations, + reservations: session.orderWorkflows, reservationRequests: session.reservationRequests, messaging: session.messaging, escrow: session.escrow, @@ -2070,7 +2073,7 @@ class HostrDaemon { Future> _reservationsOfferOrAccept( String tokenPubkey, HostrSession session, - HostrReservationTradeInput input, { + HostrOrderTradeInput input, { required bool acceptLatest, }) async { await _requireAuthenticatedPubkey( @@ -2177,7 +2180,7 @@ class HostrDaemon { Future> _reservationsPay( String tokenPubkey, HostrSession session, - HostrReservationPayInput input, + HostrOrderPayInput input, ) async { final activePubkey = await _requireAuthenticatedPubkey( tokenPubkey, @@ -2331,7 +2334,7 @@ class HostrDaemon { Future> _reservationsCommit( String tokenPubkey, HostrSession session, - HostrReservationCommitInput input, + HostrOrderCommitInput input, ) async { await _requireAuthenticatedPubkey( tokenPubkey, @@ -2459,7 +2462,7 @@ class HostrDaemon { sellerPubkey: listing.pubKey, tradeId: tradeId, ); - final committed = await hostr.reservations.createSelfSigned( + final committed = await hostr.orderWorkflows.createSelfSigned( activeKeyPair: activeKeyPair, negotiateReservation: reservation, proof: PaymentProof( @@ -2503,7 +2506,7 @@ class HostrDaemon { Future> _reservationsCancel( String tokenPubkey, HostrSession session, - HostrReservationTradeInput input, + HostrOrderTradeInput input, ) async { await _requireAuthenticatedPubkey( tokenPubkey, @@ -2544,7 +2547,7 @@ class HostrDaemon { 'reservationGroup': publicReservations.map(eventJson).toList(), }; } - final cancelled = await hostr.reservations.cancel( + final cancelled = await hostr.orderWorkflows.cancel( publicGroup, await _activeReservationKeyPair( hostr, @@ -2614,7 +2617,7 @@ class HostrDaemon { Future> _reservationsReview( String tokenPubkey, HostrSession session, - HostrReservationReviewInput input, + HostrOrderReviewInput input, ) async { await _requireAuthenticatedPubkey( tokenPubkey, @@ -2687,7 +2690,7 @@ class HostrDaemon { content: ReviewContent( rating: input.rating, content: input.content, - proof: await hostr.reservations.createParticipationProofForReview( + proof: await hostr.orderWorkflows.createParticipationProofForReview( reservation: reservation, role: 'buyer', recipientKeyPair: recipientKeyPair, @@ -3148,7 +3151,7 @@ class HostrDaemon { Future> _reservationCollection( String tokenPubkey, HostrSession session, - HostrReservationCollectionInput input, { + HostrOrderCollectionInput input, { required String mode, }) async { await _requireAuthenticatedPubkey( @@ -4096,7 +4099,7 @@ class HostrDaemon { HostrSession session, String tradeId, ) { - for (final group in session.escrowDaemon.reservationGroups.values) { + for (final group in session.escrowDaemon.orderGroups.values) { try { if (group.tradeId == tradeId) return group; } catch (_) { @@ -5870,7 +5873,7 @@ Future<_EscrowFundingPlan> _buildEscrowFundingPlan({ ? await _readPersistedTradeReservation(hostr, tradeId) : null; final publicReservations = privateReservation == null - ? await hostr.reservations.getByTradeId(tradeId) + ? await hostr.orderWorkflows.getByTradeId(tradeId) : const []; final reservations = [ ?privateReservation, diff --git a/hostr_cli/lib/src/runner.dart b/hostr_cli/lib/src/runner.dart index f18b61ac..c2a77852 100644 --- a/hostr_cli/lib/src/runner.dart +++ b/hostr_cli/lib/src/runner.dart @@ -7,7 +7,7 @@ import 'commands/escrow_methods_command.dart'; import 'commands/inbox_command.dart'; import 'commands/listings_command.dart'; import 'commands/profile_command.dart'; -import 'commands/reservations_command.dart'; +import 'commands/orders_command.dart'; import 'commands/session_command.dart'; import 'commands/swaps_command.dart'; @@ -63,7 +63,7 @@ Future runHostrCli( ..addCommand(SessionCommand(stdout: stdout, stderr: stderr)) ..addCommand(ProfileCommand(stdout: stdout, stderr: stderr)) ..addCommand(ListingsCommand(stdout: stdout, stderr: stderr)) - ..addCommand(ReservationsCommand(stdout: stdout, stderr: stderr)) + ..addCommand(OrdersCommand(stdout: stdout, stderr: stderr)) ..addCommand(EscrowMethodsCommand(stdout: stdout, stderr: stderr)) ..addCommand(SwapsCommand(stdout: stdout, stderr: stderr)) ..addCommand(TripsCommand(stdout: stdout, stderr: stderr)) diff --git a/hostr_cli/pubspec.lock b/hostr_cli/pubspec.lock index 4793fd3e..8c37132c 100644 --- a/hostr_cli/pubspec.lock +++ b/hostr_cli/pubspec.lock @@ -603,8 +603,8 @@ packages: dependency: "direct main" description: path: "packages/ndk" - ref: "codex/hostr-ndk-fixes-upstream-master" - resolved-ref: "85f5ca2d3791b56149caaac09a0877b658f56d5a" + ref: "feat/ndk-marketplace" + resolved-ref: "3e3bf19ae4535d726059ab78e366c82414802d98" url: "https://github.com/sudonym-btc/ndk.git" source: git version: "0.8.2-dev.8" diff --git a/hostr_cli/pubspec.yaml b/hostr_cli/pubspec.yaml index 1638c24a..88c15a60 100644 --- a/hostr_cli/pubspec.yaml +++ b/hostr_cli/pubspec.yaml @@ -34,7 +34,7 @@ dependency_overrides: ndk: git: url: https://github.com/sudonym-btc/ndk.git - ref: codex/hostr-ndk-fixes-upstream-master + ref: feat/ndk-marketplace path: packages/ndk freezed_annotation: ^3.1.0 pointycastle: ^4.0.0 diff --git a/hostr_cli/test/integration/development_reservation_flow_test.dart b/hostr_cli/test/integration/development_reservation_flow_test.dart index e9097638..0c67958c 100644 --- a/hostr_cli/test/integration/development_reservation_flow_test.dart +++ b/hostr_cli/test/integration/development_reservation_flow_test.dart @@ -17,7 +17,7 @@ void main() { final runIntegration = Platform.environment['HOSTR_CLI_RUN_DEV_IT'] == '1'; group( - 'development reservation CLI flow', + 'development order CLI flow', () { late _CliSession host; late _CliSession guest; @@ -36,8 +36,7 @@ void main() { await host.ensure(ensureSellerConfig: true); listingAnchor = await host.createListing( - title: - 'CLI reservation flow ${DateTime.now().microsecondsSinceEpoch}', + title: 'CLI order flow ${DateTime.now().microsecondsSinceEpoch}', ); }); @@ -56,7 +55,7 @@ void main() { amount: _usd('1.00'), ); final cancel = await guest.runOk([ - 'reservations', + 'orders', 'cancel', '--input', jsonEncode({'tradeId': cancelTrade}), @@ -73,7 +72,7 @@ void main() { amount: _usd('1.00'), ); final followUp = await host.runOk([ - 'reservations', + 'orders', 'negotiation', 'offer', '--input', @@ -86,7 +85,7 @@ void main() { final followUpPay = await guest.runOk([ '--dry-run', - 'reservations', + 'orders', 'pay', '--trade-context', followUpTrade, @@ -101,7 +100,7 @@ void main() { amount: _usd('1.00'), ); final accept = await host.runOk([ - 'reservations', + 'orders', 'negotiation', 'accept', '--input', @@ -114,7 +113,7 @@ void main() { final acceptedPay = await guest.runOk([ '--dry-run', - 'reservations', + 'orders', 'pay', '--trade-context', acceptTrade, @@ -137,7 +136,7 @@ void main() { expect(tradeContext, isNotNull); final payment = await guest.runOk([ - 'reservations', + 'orders', 'pay', '--trade-context', jsonEncode(tradeContext), @@ -171,7 +170,7 @@ void main() { } final commit = await guest.runOk([ - 'reservations', + 'orders', 'commit', '--swap-id', swapId, @@ -183,7 +182,7 @@ void main() { expect(commit['readbackCount'], greaterThanOrEqualTo(1)); final cancel = await guest.runOk([ - 'reservations', + 'orders', 'cancel', '--input', jsonEncode({'tradeId': tradeId}), @@ -295,7 +294,7 @@ class _CliSession { }; if (amount != null) input['amount'] = amount; final data = await runOk([ - 'reservations', + 'orders', 'offer', '--input', jsonEncode(input), diff --git a/hostr_cli/test/unit/hostr_actions_test.dart b/hostr_cli/test/unit/hostr_actions_test.dart index 1d863801..9babbbaa 100644 --- a/hostr_cli/test/unit/hostr_actions_test.dart +++ b/hostr_cli/test/unit/hostr_actions_test.dart @@ -17,12 +17,12 @@ void main() { 'hostr_listings_edit', 'hostr_listings_availability', 'hostr_listings_reviews', - 'hostr_listings_reservationGroups', - 'hostr_reservations_negotiateOffer', - 'hostr_reservations_negotiateAccept', - 'hostr_reservations_pay', - 'hostr_reservations_commit', - 'hostr_reservations_cancel', + 'hostr_listings_orderGroups', + 'hostr_orders_negotiateOffer', + 'hostr_orders_negotiateAccept', + 'hostr_orders_pay', + 'hostr_orders_commit', + 'hostr_orders_cancel', 'hostr_updates', 'hostr_thread_view', 'hostr_thread_message', @@ -40,7 +40,7 @@ void main() { expect( HostrActionCatalog.all.map((spec) => spec.id), - isNot(contains('hostr.reservations.offer')), + isNot(contains('hostr.orders.offer')), ); expect( HostrActionCatalog.all.map((spec) => spec.id), @@ -63,15 +63,10 @@ void main() { isNot(contains('counter')), ); - final reservation = HostrActionCatalog.byId( - 'hostr.reservations.negotiateOffer', - ); - expect(reservation.inputTypeName, 'HostrReservationsOfferInput'); + final reservation = HostrActionCatalog.byId('hostr.orders.negotiateOffer'); + expect(reservation.inputTypeName, 'HostrOrdersOfferInput'); expect(reservation.inputSchema, isNot(contains('required'))); - expect( - reservation.typescriptInput, - contains('HostrReservationsOfferInput'), - ); + expect(reservation.typescriptInput, contains('HostrOrdersOfferInput')); }); test('listings search input normalizes optional fields safely', () { @@ -121,7 +116,7 @@ void main() { expect(liveCreate.dTag, 'draft-listing-1'); expect(liveCreate.toListingJson(), containsPair('dTag', 'draft-listing-1')); - final reservation = HostrReservationsOfferInput.fromJson({ + final reservation = HostrOrdersOfferInput.fromJson({ 'listingAnchor': 'naddr1...', 'start': '2026-05-04T12:00:00Z', 'end': '2026-05-05T12:00:00Z', @@ -129,7 +124,7 @@ void main() { expect(reservation.dryRun, isTrue); expect(reservation.isFollowUpOffer, isFalse); - final followUpOffer = HostrReservationsOfferInput.fromJson({ + final followUpOffer = HostrOrdersOfferInput.fromJson({ 'tradeId': 'trade-1', 'amount': {'value': '1.50', 'currency': 'USD'}, }); @@ -138,10 +133,10 @@ void main() { expect(followUpOffer.dryRun, isTrue); expect(followUpOffer.isFollowUpOffer, isTrue); - final pay = HostrReservationPayInput.fromJson({'tradeId': 'trade-1'}); + final pay = HostrOrderPayInput.fromJson({'tradeId': 'trade-1'}); expect(pay.dryRun, isTrue); - final commit = HostrReservationCommitInput.fromJson({'swapId': 'swap-1'}); + final commit = HostrOrderCommitInput.fromJson({'swapId': 'swap-1'}); expect(commit.dryRun, isTrue); final createSchema = HostrActionCatalog.byId( @@ -152,15 +147,13 @@ void main() { expect(createProperties, isNot(contains('publish'))); final offerSchema = HostrActionCatalog.byId( - 'hostr.reservations.negotiateOffer', + 'hostr.orders.negotiateOffer', ).inputSchema; final offerProperties = offerSchema['properties'] as Map; expect(offerProperties, contains('dryRun')); expect(offerProperties, isNot(contains('broadcast'))); - final paySchema = HostrActionCatalog.byId( - 'hostr.reservations.pay', - ).inputSchema; + final paySchema = HostrActionCatalog.byId('hostr.orders.pay').inputSchema; final payProperties = paySchema['properties'] as Map; expect(payProperties, contains('dryRun')); expect(payProperties, isNot(contains('broadcast'))); @@ -239,9 +232,9 @@ void main() { expect(docs, contains('Edit listing workflow')); expect(docs, contains('Negotiation workflow')); expect(docs, contains('Payment workflow')); - expect(docs, contains('hostr_reservations_negotiateOffer')); - expect(docs, contains('hostr_reservations_pay')); - expect(docs, contains('hostr_reservations_commit')); + expect(docs, contains('hostr_orders_negotiateOffer')); + expect(docs, contains('hostr_orders_pay')); + expect(docs, contains('hostr_orders_commit')); expect(docs, contains('hostr_profile_show')); expect(docs, contains('hostr_trips_list')); expect(docs, contains('hostr_bookings_list')); @@ -254,7 +247,7 @@ void main() { test( 'reservation privacy descriptions do not frame temp pubkeys as mismatches', () { - final booking = HostrActionCatalog.byId('hostr.reservations.bookAndPay'); + final booking = HostrActionCatalog.byId('hostr.orders.bookAndPay'); final trips = HostrActionCatalog.byId('hostr.trips.list'); final swaps = HostrActionCatalog.byId('hostr.swaps.watch'); diff --git a/hostr_cli/test/unit/runner_contract_test.dart b/hostr_cli/test/unit/runner_contract_test.dart index 160ae8a2..b824ea67 100644 --- a/hostr_cli/test/unit/runner_contract_test.dart +++ b/hostr_cli/test/unit/runner_contract_test.dart @@ -65,56 +65,46 @@ void main() { expectPngDataUri(invoiceQr); }); - test( - 'reservation flow commands fail fast without an active session', - () async { - final stateDir = await Directory.systemTemp.createTemp( - 'hostr-cli-test-', - ); - Future<_RunResult> runIsolated(List args) { - return _run([ - '--env', - 'development', - '--json', - '--state-dir', - stateDir.path, - '--allow-insecure-file-secrets', - ...args, - ]); - } + test('order flow commands fail fast without an active session', () async { + final stateDir = await Directory.systemTemp.createTemp('hostr-cli-test-'); + Future<_RunResult> runIsolated(List args) { + return _run([ + '--env', + 'development', + '--json', + '--state-dir', + stateDir.path, + '--allow-insecure-file-secrets', + ...args, + ]); + } - _expectAuthRequired( - await runIsolated([ - 'reservations', - 'pay', - '--trade-context', - 'trade-123', - ]), - 'reservations pay', - ); - _expectAuthRequired( - await runIsolated(['swaps', 'watch', '--swap-id', 'swap-123']), - 'swaps watch', - ); - _expectAuthRequired( - await runIsolated([ - 'reservations', - 'cancel', - '--input', - jsonEncode({'tradeId': 'trade-123'}), - ]), - 'reservations cancel', - ); - _expectAuthRequired( - await runIsolated([ - 'escrow-methods', - '--user', - List.filled(64, '0').join(), - ]), + _expectAuthRequired( + await runIsolated(['orders', 'pay', '--trade-context', 'trade-123']), + 'orders pay', + ); + _expectAuthRequired( + await runIsolated(['swaps', 'watch', '--swap-id', 'swap-123']), + 'swaps watch', + ); + _expectAuthRequired( + await runIsolated([ + 'orders', + 'cancel', + '--input', + jsonEncode({'tradeId': 'trade-123'}), + ]), + 'orders cancel', + ); + _expectAuthRequired( + await runIsolated([ 'escrow-methods', - ); - }, - ); + '--user', + List.filled(64, '0').join(), + ]), + 'escrow-methods', + ); + }); test( 'listing create dry-run works after local mnemonic session', diff --git a/hostr_sdk/lib/hostr.dart b/hostr_sdk/lib/hostr.dart index 7ca120dd..a566cb58 100644 --- a/hostr_sdk/lib/hostr.dart +++ b/hostr_sdk/lib/hostr.dart @@ -25,10 +25,9 @@ class Hostr { Listings get listings => scope(); LnurlUseCase get lnurl => scope(); Location get location => scope(); - Reservations get reservations => scope(); - ReservationGroups get reservationGroups => scope(); - ReservationTransitions get reservationTransitions => - scope(); + Reservations get orderWorkflows => scope(); + OrderGroupVerification get orderGroupVerification => + scope(); GiftWraps get giftWraps => scope(); DmRelays get dmRelays => scope(); EscrowUseCase get escrow => scope(); @@ -95,7 +94,7 @@ class Hostr { await paymentProofOrchestrator.reset(); await userSubscriptions.reset(); await messaging.threads.close(); - await reservations.dispose(); + await orderWorkflows.dispose(); await nwc.dispose(); await evm.dispose(); await auth.dispose(); diff --git a/hostr_sdk/lib/injection.config.dart b/hostr_sdk/lib/injection.config.dart index 53a120a1..7ddbec72 100644 --- a/hostr_sdk/lib/injection.config.dart +++ b/hostr_sdk/lib/injection.config.dart @@ -86,12 +86,10 @@ import 'package:hostr_sdk/usecase/payments/payments.dart' as _i226; import 'package:hostr_sdk/usecase/relays/relays.dart' as _i883; import 'package:hostr_sdk/usecase/requests/in_memory.requests.dart' as _i286; import 'package:hostr_sdk/usecase/requests/requests.dart' as _i1014; -import 'package:hostr_sdk/usecase/reservation_groups/reservation_groups.dart' +import 'package:hostr_sdk/usecase/order_groups/order_group_verification.dart' as _i533; import 'package:hostr_sdk/usecase/reservation_requests/reservation_requests.dart' as _i49; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart' - as _i826; import 'package:hostr_sdk/usecase/reservations/reservations.dart' as _i326; import 'package:hostr_sdk/usecase/reviews/reviews.dart' as _i660; import 'package:hostr_sdk/usecase/startup/startup_coordinator.dart' as _i145; @@ -256,13 +254,6 @@ extension GetItInjectableX on _i174.GetIt { ), registerFor: {_test, _mock}, ); - gh.singleton<_i826.ReservationTransitions>( - () => _i826.ReservationTransitions( - requests: gh<_i1014.Requests>(), - logger: gh<_i372.CustomLogger>(), - ndk: gh<_i857.Ndk>(), - ), - ); gh.singleton<_i308.GiftWraps>( () => _i308.GiftWraps( ndk: gh<_i857.Ndk>(), @@ -504,7 +495,6 @@ extension GetItInjectableX on _i174.GetIt { logger: gh<_i372.CustomLogger>(), messaging: gh<_i1019.Messaging>(), auth: gh<_i1000.Auth>(), - transitions: gh<_i826.ReservationTransitions>(), listings: gh<_i906.Listings>(), relays: gh<_i883.Relays>(), ), @@ -528,14 +518,14 @@ extension GetItInjectableX on _i174.GetIt { gh.singleton<_i179.TradeAudit>( () => _i179.TradeAudit( reservations: gh<_i326.Reservations>(), - transitions: gh<_i826.ReservationTransitions>(), + ndk: gh<_i857.Ndk>(), listings: gh<_i906.Listings>(), logger: gh<_i372.CustomLogger>(), evm: gh<_i305.Evm>(), ), ); - gh.singleton<_i533.ReservationGroups>( - () => _i533.ReservationGroups( + gh.singleton<_i533.OrderGroupVerification>( + () => _i533.OrderGroupVerification( reservations: gh<_i326.Reservations>(), logger: gh<_i372.CustomLogger>(), evm: gh<_i305.Evm>(), @@ -558,8 +548,7 @@ extension GetItInjectableX on _i174.GetIt { giftWraps: gh<_i308.GiftWraps>(), heartbeats: gh<_i175.Heartbeats>(), reservations: gh<_i326.Reservations>(), - transitions: gh<_i826.ReservationTransitions>(), - reservationGroups: gh<_i533.ReservationGroups>(), + orderGroupVerification: gh<_i533.OrderGroupVerification>(), reviews: gh<_i660.Reviews>(), zaps: gh<_i1045.Zaps>(), escrow: gh<_i376.EscrowUseCase>(), @@ -685,7 +674,7 @@ extension GetItInjectableX on _i174.GetIt { metadata: gh<_i149.MetadataUseCase>(), identityClaims: gh<_i950.IdentityClaimsUseCase>(), userSubscriptions: gh<_i576.UserSubscriptions>(), - reservationGroups: gh<_i533.ReservationGroups>(), + orderGroupVerification: gh<_i533.OrderGroupVerification>(), threads: gh<_i768.Threads>(), tradeAccountAllocator: gh<_i1068.TradeAccountAllocator>(), reservationRequests: gh<_i49.ReservationRequests>(), diff --git a/hostr_sdk/lib/mocks/usecase_mocks.mocks.dart b/hostr_sdk/lib/mocks/usecase_mocks.mocks.dart index 9b451cd7..1c6fe7e6 100644 --- a/hostr_sdk/lib/mocks/usecase_mocks.mocks.dart +++ b/hostr_sdk/lib/mocks/usecase_mocks.mocks.dart @@ -3,63 +3,61 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i29; +import 'dart:async' as _i28; import 'package:hostr_sdk/usecase/auth/auth.dart' as _i14; import 'package:hostr_sdk/usecase/auth/auth_models.dart' as _i4; import 'package:hostr_sdk/usecase/background_worker/background_worker.dart' - as _i44; -import 'package:hostr_sdk/usecase/badge_awards/badge_awards.dart' as _i40; + as _i43; +import 'package:hostr_sdk/usecase/badge_awards/badge_awards.dart' as _i39; import 'package:hostr_sdk/usecase/badge_definitions/badge_definitions.dart' - as _i39; + as _i38; import 'package:hostr_sdk/usecase/crud.usecase.dart' as _i9; import 'package:hostr_sdk/usecase/deterministic_keys/deterministic_keys.dart' as _i3; -import 'package:hostr_sdk/usecase/escrow/escrow.dart' as _i33; +import 'package:hostr_sdk/usecase/escrow/escrow.dart' as _i32; import 'package:hostr_sdk/usecase/escrow/operations/claim/escrow_claim_models.dart' - as _i35; + as _i34; import 'package:hostr_sdk/usecase/escrow/operations/claim/escrow_claim_operation.dart' - as _i19; + as _i18; import 'package:hostr_sdk/usecase/escrow/operations/fund/escrow_fund_models.dart' - as _i34; + as _i33; import 'package:hostr_sdk/usecase/escrow/operations/fund/escrow_fund_preparer.dart' - as _i18; + as _i17; import 'package:hostr_sdk/usecase/escrow/operations/release/escrow_release_models.dart' - as _i36; + as _i35; import 'package:hostr_sdk/usecase/escrow/operations/release/escrow_release_operation.dart' - as _i20; + as _i19; import 'package:hostr_sdk/usecase/escrow/supported_escrow_contract/supported_escrow_contract.dart' - as _i37; -import 'package:hostr_sdk/usecase/escrow_methods/escrows_methods.dart' as _i38; -import 'package:hostr_sdk/usecase/escrows/escrows.dart' as _i21; -import 'package:hostr_sdk/usecase/evm/chain/evm_chain.dart' as _i26; + as _i36; +import 'package:hostr_sdk/usecase/escrow_methods/escrows_methods.dart' as _i37; +import 'package:hostr_sdk/usecase/escrows/escrows.dart' as _i20; +import 'package:hostr_sdk/usecase/evm/chain/evm_chain.dart' as _i25; import 'package:hostr_sdk/usecase/evm/chain/operations/swap_out/swap_out_operation.dart' - as _i43; -import 'package:hostr_sdk/usecase/evm/evm.dart' as _i42; -import 'package:hostr_sdk/usecase/listings/listings.dart' as _i16; + as _i42; +import 'package:hostr_sdk/usecase/evm/evm.dart' as _i41; +import 'package:hostr_sdk/usecase/listings/listings.dart' as _i15; import 'package:hostr_sdk/usecase/messaging/messaging.dart' as _i13; -import 'package:hostr_sdk/usecase/messaging/threads.dart' as _i22; -import 'package:hostr_sdk/usecase/metadata/metadata.dart' as _i30; +import 'package:hostr_sdk/usecase/messaging/threads.dart' as _i21; +import 'package:hostr_sdk/usecase/metadata/metadata.dart' as _i29; import 'package:hostr_sdk/usecase/nwc/nwc.cubit.dart' as _i11; import 'package:hostr_sdk/usecase/nwc/nwc.dart' as _i12; -import 'package:hostr_sdk/usecase/payments/operations/pay_models.dart' as _i24; +import 'package:hostr_sdk/usecase/payments/operations/pay_models.dart' as _i23; import 'package:hostr_sdk/usecase/payments/operations/pay_operation.dart' - as _i25; -import 'package:hostr_sdk/usecase/payments/payments.dart' as _i23; -import 'package:hostr_sdk/usecase/relays/relays.dart' as _i45; + as _i24; +import 'package:hostr_sdk/usecase/payments/payments.dart' as _i22; +import 'package:hostr_sdk/usecase/relays/relays.dart' as _i44; import 'package:hostr_sdk/usecase/requests/requests.dart' as _i8; import 'package:hostr_sdk/usecase/reservation_requests/reservation_requests.dart' - as _i41; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart' - as _i15; -import 'package:hostr_sdk/usecase/reservations/reservations.dart' as _i17; -import 'package:hostr_sdk/usecase/storage/storage.dart' as _i27; -import 'package:hostr_sdk/usecase/zaps/zaps.dart' as _i32; + as _i40; +import 'package:hostr_sdk/usecase/reservations/reservations.dart' as _i16; +import 'package:hostr_sdk/usecase/storage/storage.dart' as _i26; +import 'package:hostr_sdk/usecase/zaps/zaps.dart' as _i31; import 'package:hostr_sdk/util/main.dart' as _i7; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i28; +import 'package:mockito/src/dummies.dart' as _i27; import 'package:models/main.dart' as _i10; -import 'package:ndk/entities.dart' as _i31; +import 'package:ndk/entities.dart' as _i30; import 'package:ndk/ndk.dart' as _i6; import 'package:ndk/shared/nips/nip01/key_pair.dart' as _i5; import 'package:rxdart/rxdart.dart' as _i2; @@ -222,118 +220,112 @@ class _FakeAuth_25 extends _i1.SmartFake implements _i14.Auth { : super(parent, parentInvocation); } -class _FakeReservationTransitions_26 extends _i1.SmartFake - implements _i15.ReservationTransitions { - _FakeReservationTransitions_26(Object parent, Invocation parentInvocation) +class _FakeListings_26 extends _i1.SmartFake implements _i15.Listings { + _FakeListings_26(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeListings_27 extends _i1.SmartFake implements _i16.Listings { - _FakeListings_27(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); -} - -class _FakeParticipationProof_28 extends _i1.SmartFake +class _FakeParticipationProof_27 extends _i1.SmartFake implements _i10.ParticipationProof { - _FakeParticipationProof_28(Object parent, Invocation parentInvocation) + _FakeParticipationProof_27(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeReservation_29 extends _i1.SmartFake implements _i10.Reservation { - _FakeReservation_29(Object parent, Invocation parentInvocation) +class _FakeReservation_28 extends _i1.SmartFake implements _i10.Reservation { + _FakeReservation_28(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeReservationDeps_30 extends _i1.SmartFake - implements _i17.ReservationDeps { - _FakeReservationDeps_30(Object parent, Invocation parentInvocation) +class _FakeReservationDeps_29 extends _i1.SmartFake + implements _i16.ReservationDeps { + _FakeReservationDeps_29(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeValidation_31 extends _i1.SmartFake +class _FakeValidation_30 extends _i1.SmartFake implements _i10.Validation { - _FakeValidation_31(Object parent, Invocation parentInvocation) + _FakeValidation_30(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEscrowFundPreparer_32 extends _i1.SmartFake - implements _i18.EscrowFundPreparer { - _FakeEscrowFundPreparer_32(Object parent, Invocation parentInvocation) +class _FakeEscrowFundPreparer_31 extends _i1.SmartFake + implements _i17.EscrowFundPreparer { + _FakeEscrowFundPreparer_31(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEscrowClaimOperation_33 extends _i1.SmartFake - implements _i19.EscrowClaimOperation { - _FakeEscrowClaimOperation_33(Object parent, Invocation parentInvocation) +class _FakeEscrowClaimOperation_32 extends _i1.SmartFake + implements _i18.EscrowClaimOperation { + _FakeEscrowClaimOperation_32(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEscrowReleaseOperation_34 extends _i1.SmartFake - implements _i20.EscrowReleaseOperation { - _FakeEscrowReleaseOperation_34(Object parent, Invocation parentInvocation) +class _FakeEscrowReleaseOperation_33 extends _i1.SmartFake + implements _i19.EscrowReleaseOperation { + _FakeEscrowReleaseOperation_33(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeMutualEscrowResult_35 extends _i1.SmartFake - implements _i21.MutualEscrowResult { - _FakeMutualEscrowResult_35(Object parent, Invocation parentInvocation) +class _FakeMutualEscrowResult_34 extends _i1.SmartFake + implements _i20.MutualEscrowResult { + _FakeMutualEscrowResult_34(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEscrowService_36 extends _i1.SmartFake +class _FakeEscrowService_35 extends _i1.SmartFake implements _i10.EscrowService { - _FakeEscrowService_36(Object parent, Invocation parentInvocation) + _FakeEscrowService_35(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEscrowMethod_37 extends _i1.SmartFake implements _i10.EscrowMethod { - _FakeEscrowMethod_37(Object parent, Invocation parentInvocation) +class _FakeEscrowMethod_36 extends _i1.SmartFake implements _i10.EscrowMethod { + _FakeEscrowMethod_36(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeBadgeDefinition_38 extends _i1.SmartFake +class _FakeBadgeDefinition_37 extends _i1.SmartFake implements _i10.BadgeDefinition { - _FakeBadgeDefinition_38(Object parent, Invocation parentInvocation) + _FakeBadgeDefinition_37(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeBadgeAward_39 extends _i1.SmartFake implements _i10.BadgeAward { - _FakeBadgeAward_39(Object parent, Invocation parentInvocation) +class _FakeBadgeAward_38 extends _i1.SmartFake implements _i10.BadgeAward { + _FakeBadgeAward_38(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeThreads_40 extends _i1.SmartFake implements _i22.Threads { - _FakeThreads_40(Object parent, Invocation parentInvocation) +class _FakeThreads_39 extends _i1.SmartFake implements _i21.Threads { + _FakeThreads_39(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeAutomaticInvoiceDestination_41 extends _i1.SmartFake - implements _i23.AutomaticInvoiceDestination { - _FakeAutomaticInvoiceDestination_41( +class _FakeAutomaticInvoiceDestination_40 extends _i1.SmartFake + implements _i22.AutomaticInvoiceDestination { + _FakeAutomaticInvoiceDestination_40( Object parent, Invocation parentInvocation, ) : super(parent, parentInvocation); } -class _FakePayOperation_42< - T extends _i24.PayParameters, - RD extends _i24.ResolvedDetails, - CD extends _i24.CallbackDetails, - CmpD extends _i24.CompletedDetails +class _FakePayOperation_41< + T extends _i23.PayParameters, + RD extends _i23.ResolvedDetails, + CD extends _i23.CallbackDetails, + CmpD extends _i23.CompletedDetails > extends _i1.SmartFake - implements _i25.PayOperation { - _FakePayOperation_42(Object parent, Invocation parentInvocation) + implements _i24.PayOperation { + _FakePayOperation_41(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeEvmChain_43 extends _i1.SmartFake implements _i26.EvmChain { - _FakeEvmChain_43(Object parent, Invocation parentInvocation) +class _FakeEvmChain_42 extends _i1.SmartFake implements _i25.EvmChain { + _FakeEvmChain_42(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } -class _FakeRelayStorage_44 extends _i1.SmartFake implements _i27.RelayStorage { - _FakeRelayStorage_44(Object parent, Invocation parentInvocation) +class _FakeRelayStorage_43 extends _i1.SmartFake implements _i26.RelayStorage { + _FakeRelayStorage_43(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } @@ -419,7 +411,7 @@ class MockAuth extends _i1.Mock implements _i14.Auth { T service() => (super.noSuchMethod( Invocation.method(#service, []), - returnValue: _i28.dummyValue( + returnValue: _i27.dummyValue( this, Invocation.method(#service, []), ), @@ -427,38 +419,38 @@ class MockAuth extends _i1.Mock implements _i14.Auth { as T); @override - _i29.Future ensureNip42AuthForHostrRelay({ + _i28.Future ensureNip42AuthForHostrRelay({ Duration? timeout = const Duration(seconds: 30), }) => (super.noSuchMethod( Invocation.method(#ensureNip42AuthForHostrRelay, [], { #timeout: timeout, }), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future signup() => + _i28.Future signup() => (super.noSuchMethod( Invocation.method(#signup, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future signin(String? input) => + _i28.Future signin(String? input) => (super.noSuchMethod( Invocation.method(#signin, [input]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future signinWithBunkerUrl( + _i28.Future signinWithBunkerUrl( String? bunkerUrl, { void Function(String)? authCallback, }) => @@ -468,13 +460,13 @@ class MockAuth extends _i1.Mock implements _i14.Auth { [bunkerUrl], {#authCallback: authCallback}, ), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future signinWithNostrConnect( + _i28.Future signinWithNostrConnect( _i6.NostrConnect? nostrConnect, { void Function(String)? authCallback, }) => @@ -484,13 +476,13 @@ class MockAuth extends _i1.Mock implements _i14.Auth { [nostrConnect], {#authCallback: authCallback}, ), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future signinWithBunkerConnection( + _i28.Future signinWithBunkerConnection( _i6.BunkerConnection? bunkerConnection, { void Function(String)? authCallback, }) => @@ -500,13 +492,13 @@ class MockAuth extends _i1.Mock implements _i14.Auth { [bunkerConnection], {#authCallback: authCallback}, ), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i4.AuthRecord> previewResolvedIdentity( + _i28.Future<_i4.AuthRecord> previewResolvedIdentity( String? input, { int? nostrAccountIndex = 0, }) => @@ -516,7 +508,7 @@ class MockAuth extends _i1.Mock implements _i14.Auth { [input], {#nostrAccountIndex: nostrAccountIndex}, ), - returnValue: _i29.Future<_i4.AuthRecord>.value( + returnValue: _i28.Future<_i4.AuthRecord>.value( _FakeAuthRecord_2( this, Invocation.method( @@ -527,33 +519,33 @@ class MockAuth extends _i1.Mock implements _i14.Auth { ), ), ) - as _i29.Future<_i4.AuthRecord>); + as _i28.Future<_i4.AuthRecord>); @override - _i29.Future logout() => + _i28.Future logout() => (super.noSuchMethod( Invocation.method(#logout, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future init() => + _i28.Future init() => (super.noSuchMethod( Invocation.method(#init, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future isAuthenticated() => + _i28.Future isAuthenticated() => (super.noSuchMethod( Invocation.method(#isAuthenticated, []), - returnValue: _i29.Future.value(false), + returnValue: _i28.Future.value(false), ) - as _i29.Future); + as _i28.Future); @override bool ensureNdkAccountsMatch() => @@ -564,21 +556,21 @@ class MockAuth extends _i1.Mock implements _i14.Auth { as bool); @override - _i29.Future retryBunkerSessionRestore() => + _i28.Future retryBunkerSessionRestore() => (super.noSuchMethod( Invocation.method(#retryBunkerSessionRestore, []), - returnValue: _i29.Future.value(false), + returnValue: _i28.Future.value(false), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future markBunkerSessionRecoveryRequired(Object? error) => + _i28.Future markBunkerSessionRecoveryRequired(Object? error) => (super.noSuchMethod( Invocation.method(#markBunkerSessionRecoveryRequired, [error]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i5.KeyPair getActiveKey() => @@ -592,32 +584,32 @@ class MockAuth extends _i1.Mock implements _i14.Auth { as _i5.KeyPair); @override - _i29.Future<_i6.Nip01Event> signEvent(_i6.Nip01Event? event) => + _i28.Future<_i6.Nip01Event> signEvent(_i6.Nip01Event? event) => (super.noSuchMethod( Invocation.method(#signEvent, [event]), - returnValue: _i29.Future<_i6.Nip01Event>.value( + returnValue: _i28.Future<_i6.Nip01Event>.value( _FakeNip01Event_4(this, Invocation.method(#signEvent, [event])), ), ) - as _i29.Future<_i6.Nip01Event>); + as _i28.Future<_i6.Nip01Event>); @override - _i29.Future updateMaxAccountIndex(int? maxAccountIndex) => + _i28.Future updateMaxAccountIndex(int? maxAccountIndex) => (super.noSuchMethod( Invocation.method(#updateMaxAccountIndex, [maxAccountIndex]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future dispose() => + _i28.Future dispose() => (super.noSuchMethod( Invocation.method(#dispose, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); } /// A class which mocks [Requests]. @@ -668,7 +660,7 @@ class MockRequests extends _i1.Mock implements _i8.Requests { as _i7.StreamWithStatus); @override - _i29.Stream query({ + _i28.Stream query({ required _i6.Filter? filter, List? relays, Duration? timeout, @@ -685,12 +677,12 @@ class MockRequests extends _i1.Mock implements _i8.Requests { #cacheRead: cacheRead, #cacheWrite: cacheWrite, }), - returnValue: _i29.Stream.empty(), + returnValue: _i28.Stream.empty(), ) - as _i29.Stream); + as _i28.Stream); @override - _i29.Future count({ + _i28.Future count({ required _i6.Filter? filter, Duration? timeout, List? relays, @@ -701,12 +693,12 @@ class MockRequests extends _i1.Mock implements _i8.Requests { #timeout: timeout, #relays: relays, }), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i8.BroadcastResult> broadcastEvent({ + _i28.Future<_i8.BroadcastResult> broadcastEvent({ required _i6.Nip01Event? event, List? relays, _i8.NostrEventSigner? signer, @@ -717,7 +709,7 @@ class MockRequests extends _i1.Mock implements _i8.Requests { #relays: relays, #signer: signer, }), - returnValue: _i29.Future<_i8.BroadcastResult>.value( + returnValue: _i28.Future<_i8.BroadcastResult>.value( _FakeBroadcastResult_7( this, Invocation.method(#broadcastEvent, [], { @@ -728,7 +720,7 @@ class MockRequests extends _i1.Mock implements _i8.Requests { ), ), ) - as _i29.Future<_i8.BroadcastResult>); + as _i28.Future<_i8.BroadcastResult>); @override _i8.LiveSubscriptionHandle liveSubscription({ @@ -763,7 +755,7 @@ class MockRequests extends _i1.Mock implements _i8.Requests { /// A class which mocks [MetadataUseCase]. /// /// See the documentation for Mockito's code generation for more information. -class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { +class MockMetadataUseCase extends _i1.Mock implements _i29.MetadataUseCase { MockMetadataUseCase() { _i1.throwOnMissingStub(this); } @@ -789,26 +781,26 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.ProfileMetadata> get updates => + _i28.Stream<_i10.ProfileMetadata> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.ProfileMetadata>.empty(), + returnValue: _i28.Stream<_i10.ProfileMetadata>.empty(), ) - as _i29.Stream<_i10.ProfileMetadata>); + as _i28.Stream<_i10.ProfileMetadata>); @override - _i29.Future afterUpsert( + _i28.Future afterUpsert( _i9.UpsertResult<_i10.ProfileMetadata>? result, ) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i10.ProfileMetadata?> loadMetadata( + _i28.Future<_i10.ProfileMetadata?> loadMetadata( String? pubkey, { bool? forceRefresh = false, }) => @@ -818,12 +810,12 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { [pubkey], {#forceRefresh: forceRefresh}, ), - returnValue: _i29.Future<_i10.ProfileMetadata?>.value(), + returnValue: _i28.Future<_i10.ProfileMetadata?>.value(), ) - as _i29.Future<_i10.ProfileMetadata?>); + as _i28.Future<_i10.ProfileMetadata?>); @override - _i29.Future<_i10.ProfileMetadata?> loadMetadataFromSources( + _i28.Future<_i10.ProfileMetadata?> loadMetadataFromSources( String? pubkey, { required bool? forceRefresh, }) => @@ -833,35 +825,35 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { [pubkey], {#forceRefresh: forceRefresh}, ), - returnValue: _i29.Future<_i10.ProfileMetadata?>.value(), + returnValue: _i28.Future<_i10.ProfileMetadata?>.value(), ) - as _i29.Future<_i10.ProfileMetadata?>); + as _i28.Future<_i10.ProfileMetadata?>); @override - _i29.Future<_i31.UserRelayList?> refreshNip65(String? pubkey) => + _i28.Future<_i30.UserRelayList?> refreshNip65(String? pubkey) => (super.noSuchMethod( Invocation.method(#refreshNip65, [pubkey]), - returnValue: _i29.Future<_i31.UserRelayList?>.value(), + returnValue: _i28.Future<_i30.UserRelayList?>.value(), ) - as _i29.Future<_i31.UserRelayList?>); + as _i28.Future<_i30.UserRelayList?>); @override - _i29.Future ensureSellerConfig(String? pubkey) => + _i28.Future ensureSellerConfig(String? pubkey) => (super.noSuchMethod( Invocation.method(#ensureSellerConfig, [pubkey]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future ensureUserConfig(String? pubkey) => + _i28.Future ensureUserConfig(String? pubkey) => (super.noSuchMethod( Invocation.method(#ensureUserConfig, [pubkey]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override void notifyUpdate(_i10.ProfileMetadata? event) => super.noSuchMethod( @@ -870,13 +862,13 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { ); @override - _i29.Future beforeUpsert(_i10.ProfileMetadata? event) => + _i28.Future beforeUpsert(_i10.ProfileMetadata? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.ProfileMetadata> subscribe( @@ -950,16 +942,16 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { as _i8.ExpandableSubscription<_i10.ProfileMetadata>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.ProfileMetadata>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -973,46 +965,46 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.ProfileMetadata>> upsert( + _i28.Future<_i9.UpsertResult<_i10.ProfileMetadata>> upsert( _i10.ProfileMetadata? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), returnValue: - _i29.Future<_i9.UpsertResult<_i10.ProfileMetadata>>.value( + _i28.Future<_i9.UpsertResult<_i10.ProfileMetadata>>.value( _FakeUpsertResult_13<_i10.ProfileMetadata>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.ProfileMetadata>>); + as _i28.Future<_i9.UpsertResult<_i10.ProfileMetadata>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.ProfileMetadata? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.ProfileMetadata>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.ProfileMetadata?> getOne( + _i28.Future<_i10.ProfileMetadata?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -1023,48 +1015,48 @@ class MockMetadataUseCase extends _i1.Mock implements _i30.MetadataUseCase { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.ProfileMetadata?>.value(), + returnValue: _i28.Future<_i10.ProfileMetadata?>.value(), ) - as _i29.Future<_i10.ProfileMetadata?>); + as _i28.Future<_i10.ProfileMetadata?>); @override - _i29.Future<_i10.ProfileMetadata?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.ProfileMetadata?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.ProfileMetadata?>.value(), + returnValue: _i28.Future<_i10.ProfileMetadata?>.value(), ) - as _i29.Future<_i10.ProfileMetadata?>); + as _i28.Future<_i10.ProfileMetadata?>); @override - _i29.Future<_i10.ProfileMetadata> getById(String? id) => + _i28.Future<_i10.ProfileMetadata> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.ProfileMetadata>.value( + returnValue: _i28.Future<_i10.ProfileMetadata>.value( _FakeProfileMetadata_14(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.ProfileMetadata>); + as _i28.Future<_i10.ProfileMetadata>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag( + _i28.Future> findByTag( String? tag, String? value, ) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.ProfileMetadata>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [Nwc]. @@ -1084,12 +1076,12 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { as List<_i11.NwcCubit>); @override - _i29.Stream> get connectionsStream => + _i28.Stream> get connectionsStream => (super.noSuchMethod( Invocation.getter(#connectionsStream), - returnValue: _i29.Stream>.empty(), + returnValue: _i28.Stream>.empty(), ) - as _i29.Stream>); + as _i28.Stream>); @override set connections(List<_i11.NwcCubit>? value) => super.noSuchMethod( @@ -1098,83 +1090,83 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { ); @override - _i29.Future save() => + _i28.Future save() => (super.noSuchMethod( Invocation.method(#save, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future add(_i11.NwcCubit? reactiveConnection) => + _i28.Future add(_i11.NwcCubit? reactiveConnection) => (super.noSuchMethod( Invocation.method(#add, [reactiveConnection]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future remove(_i11.NwcCubit? reactiveConnection) => + _i28.Future remove(_i11.NwcCubit? reactiveConnection) => (super.noSuchMethod( Invocation.method(#remove, [reactiveConnection]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i11.NwcCubit> initiateAndAdd(String? url) => + _i28.Future<_i11.NwcCubit> initiateAndAdd(String? url) => (super.noSuchMethod( Invocation.method(#initiateAndAdd, [url]), - returnValue: _i29.Future<_i11.NwcCubit>.value( + returnValue: _i28.Future<_i11.NwcCubit>.value( _FakeNwcCubit_15(this, Invocation.method(#initiateAndAdd, [url])), ), ) - as _i29.Future<_i11.NwcCubit>); + as _i28.Future<_i11.NwcCubit>); @override - _i29.Future<_i6.NwcConnection> connect(String? url) => + _i28.Future<_i6.NwcConnection> connect(String? url) => (super.noSuchMethod( Invocation.method(#connect, [url]), - returnValue: _i29.Future<_i6.NwcConnection>.value( + returnValue: _i28.Future<_i6.NwcConnection>.value( _FakeNwcConnection_16(this, Invocation.method(#connect, [url])), ), ) - as _i29.Future<_i6.NwcConnection>); + as _i28.Future<_i6.NwcConnection>); @override - _i29.Future<_i6.GetInfoResponse> getInfo(_i6.NwcConnection? connection) => + _i28.Future<_i6.GetInfoResponse> getInfo(_i6.NwcConnection? connection) => (super.noSuchMethod( Invocation.method(#getInfo, [connection]), - returnValue: _i29.Future<_i6.GetInfoResponse>.value( + returnValue: _i28.Future<_i6.GetInfoResponse>.value( _FakeGetInfoResponse_17( this, Invocation.method(#getInfo, [connection]), ), ), ) - as _i29.Future<_i6.GetInfoResponse>); + as _i28.Future<_i6.GetInfoResponse>); @override - _i29.Future<_i6.PayInvoiceResponse> payInvoice( + _i28.Future<_i6.PayInvoiceResponse> payInvoice( _i6.NwcConnection? connection, String? invoice, ) => (super.noSuchMethod( Invocation.method(#payInvoice, [connection, invoice]), - returnValue: _i29.Future<_i6.PayInvoiceResponse>.value( + returnValue: _i28.Future<_i6.PayInvoiceResponse>.value( _FakePayInvoiceResponse_18( this, Invocation.method(#payInvoice, [connection, invoice]), ), ), ) - as _i29.Future<_i6.PayInvoiceResponse>); + as _i28.Future<_i6.PayInvoiceResponse>); @override - _i29.Future<_i6.MakeInvoiceResponse> makeInvoice( + _i28.Future<_i6.MakeInvoiceResponse> makeInvoice( _i6.NwcConnection? connection, { required int? amountSats, String? description, @@ -1192,7 +1184,7 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { #expiry: expiry, }, ), - returnValue: _i29.Future<_i6.MakeInvoiceResponse>.value( + returnValue: _i28.Future<_i6.MakeInvoiceResponse>.value( _FakeMakeInvoiceResponse_19( this, Invocation.method( @@ -1208,10 +1200,10 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { ), ), ) - as _i29.Future<_i6.MakeInvoiceResponse>); + as _i28.Future<_i6.MakeInvoiceResponse>); @override - _i29.Future<_i6.LookupInvoiceResponse> lookupInvoice( + _i28.Future<_i6.LookupInvoiceResponse> lookupInvoice( _i6.NwcConnection? connection, { String? paymentHash, String? invoice, @@ -1222,7 +1214,7 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { [connection], {#paymentHash: paymentHash, #invoice: invoice}, ), - returnValue: _i29.Future<_i6.LookupInvoiceResponse>.value( + returnValue: _i28.Future<_i6.LookupInvoiceResponse>.value( _FakeLookupInvoiceResponse_20( this, Invocation.method( @@ -1233,40 +1225,40 @@ class MockNwc extends _i1.Mock implements _i12.Nwc { ), ), ) - as _i29.Future<_i6.LookupInvoiceResponse>); + as _i28.Future<_i6.LookupInvoiceResponse>); @override - _i29.Future reset() => + _i28.Future reset() => (super.noSuchMethod( Invocation.method(#reset, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future dispose() => + _i28.Future dispose() => (super.noSuchMethod( Invocation.method(#dispose, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future start() => + _i28.Future start() => (super.noSuchMethod( Invocation.method(#start, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); } /// A class which mocks [Zaps]. /// /// See the documentation for Mockito's code generation for more information. -class MockZaps extends _i1.Mock implements _i32.Zaps { +class MockZaps extends _i1.Mock implements _i31.Zaps { MockZaps() { _i1.throwOnMissingStub(this); } @@ -1288,7 +1280,7 @@ class MockZaps extends _i1.Mock implements _i32.Zaps { as _i6.Ndk); @override - _i29.Future<_i6.ZapResponse> zap({ + _i28.Future<_i6.ZapResponse> zap({ required String? lnurl, required int? amountSats, }) => @@ -1297,7 +1289,7 @@ class MockZaps extends _i1.Mock implements _i32.Zaps { #lnurl: lnurl, #amountSats: amountSats, }), - returnValue: _i29.Future<_i6.ZapResponse>.value( + returnValue: _i28.Future<_i6.ZapResponse>.value( _FakeZapResponse_22( this, Invocation.method(#zap, [], { @@ -1307,10 +1299,10 @@ class MockZaps extends _i1.Mock implements _i32.Zaps { ), ), ) - as _i29.Future<_i6.ZapResponse>); + as _i28.Future<_i6.ZapResponse>); @override - _i29.Future<_i6.InvoiceResponse?> fetchInvoice({ + _i28.Future<_i6.InvoiceResponse?> fetchInvoice({ required String? lud16Link, required int? amountSats, _i6.ZapRequest? zapRequest, @@ -1321,9 +1313,9 @@ class MockZaps extends _i1.Mock implements _i32.Zaps { #amountSats: amountSats, #zapRequest: zapRequest, }), - returnValue: _i29.Future<_i6.InvoiceResponse?>.value(), + returnValue: _i28.Future<_i6.InvoiceResponse?>.value(), ) - as _i29.Future<_i6.InvoiceResponse?>); + as _i28.Future<_i6.InvoiceResponse?>); @override _i7.StreamWithStatus<_i6.Nip01Event> subscribeZapReceipts({ @@ -1355,7 +1347,7 @@ class MockZaps extends _i1.Mock implements _i32.Zaps { /// A class which mocks [Listings]. /// /// See the documentation for Mockito's code generation for more information. -class MockListings extends _i1.Mock implements _i16.Listings { +class MockListings extends _i1.Mock implements _i15.Listings { MockListings() { _i1.throwOnMissingStub(this); } @@ -1381,31 +1373,31 @@ class MockListings extends _i1.Mock implements _i16.Listings { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.Listing> get updates => + _i28.Stream<_i10.Listing> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.Listing>.empty(), + returnValue: _i28.Stream<_i10.Listing>.empty(), ) - as _i29.Stream<_i10.Listing>); + as _i28.Stream<_i10.Listing>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Listing>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future beforeUpsert(_i10.Listing? event) => + _i28.Future beforeUpsert(_i10.Listing? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override void notifyUpdate(_i10.Listing? event) => super.noSuchMethod( @@ -1414,13 +1406,13 @@ class MockListings extends _i1.Mock implements _i16.Listings { ); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.Listing>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.Listing>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.Listing> subscribe(_i6.Filter? f, {String? name}) => @@ -1488,16 +1480,16 @@ class MockListings extends _i1.Mock implements _i16.Listings { as _i8.ExpandableSubscription<_i10.Listing>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.Listing>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -1511,33 +1503,33 @@ class MockListings extends _i1.Mock implements _i16.Listings { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.Listing>> upsert( + _i28.Future<_i9.UpsertResult<_i10.Listing>> upsert( _i10.Listing? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), - returnValue: _i29.Future<_i9.UpsertResult<_i10.Listing>>.value( + returnValue: _i28.Future<_i9.UpsertResult<_i10.Listing>>.value( _FakeUpsertResult_13<_i10.Listing>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.Listing>>); + as _i28.Future<_i9.UpsertResult<_i10.Listing>>); @override - _i29.Future> delete(_i10.Listing? event) => + _i28.Future> delete(_i10.Listing? event) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.Listing?> getOne( + _i28.Future<_i10.Listing?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -1548,51 +1540,51 @@ class MockListings extends _i1.Mock implements _i16.Listings { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.Listing?>.value(), + returnValue: _i28.Future<_i10.Listing?>.value(), ) - as _i29.Future<_i10.Listing?>); + as _i28.Future<_i10.Listing?>); @override - _i29.Future<_i10.Listing?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.Listing?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.Listing?>.value(), + returnValue: _i28.Future<_i10.Listing?>.value(), ) - as _i29.Future<_i10.Listing?>); + as _i28.Future<_i10.Listing?>); @override - _i29.Future<_i10.Listing> getById(String? id) => + _i28.Future<_i10.Listing> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.Listing>.value( + returnValue: _i28.Future<_i10.Listing>.value( _FakeListing_23(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.Listing>); + as _i28.Future<_i10.Listing>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Listing>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [Reservations]. /// /// See the documentation for Mockito's code generation for more information. -class MockReservations extends _i1.Mock implements _i17.Reservations { +class MockReservations extends _i1.Mock implements _i16.Reservations { MockReservations() { _i1.throwOnMissingStub(this); } @@ -1614,29 +1606,18 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i14.Auth); @override - _i15.ReservationTransitions get transitions => - (super.noSuchMethod( - Invocation.getter(#transitions), - returnValue: _FakeReservationTransitions_26( - this, - Invocation.getter(#transitions), - ), - ) - as _i15.ReservationTransitions); - - @override - _i16.Listings get listings => + _i15.Listings get listings => (super.noSuchMethod( Invocation.getter(#listings), - returnValue: _FakeListings_27(this, Invocation.getter(#listings)), + returnValue: _FakeListings_26(this, Invocation.getter(#listings)), ) - as _i16.Listings); + as _i15.Listings); @override String get verificationStreamName => (super.noSuchMethod( Invocation.getter(#verificationStreamName), - returnValue: _i28.dummyValue( + returnValue: _i27.dummyValue( this, Invocation.getter(#verificationStreamName), ), @@ -1664,48 +1645,48 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.Reservation> get updates => + _i28.Stream<_i10.Reservation> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.Reservation>.empty(), + returnValue: _i28.Stream<_i10.Reservation>.empty(), ) - as _i29.Stream<_i10.Reservation>); + as _i28.Stream<_i10.Reservation>); @override - _i29.Future beforeUpsert(_i10.Reservation? event) => + _i28.Future beforeUpsert(_i10.Reservation? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> getByTradeId(String? tradeId) => + _i28.Future> getByTradeId(String? tradeId) => (super.noSuchMethod( Invocation.method(#getByTradeId, [tradeId]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> getListingReservations({ + _i28.Future> getListingReservations({ required String? listingAnchor, }) => (super.noSuchMethod( Invocation.method(#getListingReservations, [], { #listingAnchor: listingAnchor, }), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.ParticipationProof> createParticipationProofForReview({ + _i28.Future<_i10.ParticipationProof> createParticipationProofForReview({ required _i10.Reservation? reservation, required String? role, required _i5.KeyPair? recipientKeyPair, @@ -1718,8 +1699,8 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { #recipientKeyPair: recipientKeyPair, #identityKeyPair: identityKeyPair, }), - returnValue: _i29.Future<_i10.ParticipationProof>.value( - _FakeParticipationProof_28( + returnValue: _i28.Future<_i10.ParticipationProof>.value( + _FakeParticipationProof_27( this, Invocation.method(#createParticipationProofForReview, [], { #reservation: reservation, @@ -1730,7 +1711,7 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { ), ), ) - as _i29.Future<_i10.ParticipationProof>); + as _i28.Future<_i10.ParticipationProof>); @override Map> groupByCommitment( @@ -1744,16 +1725,16 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as Map>); @override - _i29.Future> queryReservationGroups({ + _i28.Future> queryOrderGroups({ required _i10.Listing? listing, }) => (super.noSuchMethod( - Invocation.method(#queryReservationGroups, [], {#listing: listing}), - returnValue: _i29.Future>.value( + Invocation.method(#queryOrderGroups, [], {#listing: listing}), + returnValue: _i28.Future>.value( {}, ), ) - as _i29.Future>); + as _i28.Future>); @override Map groupByThread( @@ -1777,7 +1758,7 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i7.StreamWithStatus<_i10.Reservation>); @override - _i29.Future> accept( + _i28.Future> accept( String? anchor, _i10.Reservation? request, String? guestPubkey, @@ -1790,14 +1771,14 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { guestPubkey, saltedPubkey, ]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.Reservation> createSelfSigned({ + _i28.Future<_i10.Reservation> createSelfSigned({ required _i5.KeyPair? activeKeyPair, required _i10.Reservation? negotiateReservation, required _i10.PaymentProof? proof, @@ -1808,8 +1789,8 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { #negotiateReservation: negotiateReservation, #proof: proof, }), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#createSelfSigned, [], { #activeKeyPair: activeKeyPair, @@ -1819,42 +1800,42 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future<_i10.Reservation> cancel( + _i28.Future<_i10.Reservation> cancel( _i10.ReservationGroup? reservationGroup, _i5.KeyPair? keyPair, ) => (super.noSuchMethod( Invocation.method(#cancel, [reservationGroup, keyPair]), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#cancel, [reservationGroup, keyPair]), ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future<_i10.Reservation> confirm( + _i28.Future<_i10.Reservation> confirm( _i10.ReservationGroup? reservationGroup, _i5.KeyPair? keyPair, ) => (super.noSuchMethod( Invocation.method(#confirm, [reservationGroup, keyPair]), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#confirm, [reservationGroup, keyPair]), ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future<_i10.Reservation> createBlocked({ + _i28.Future<_i10.Reservation> createBlocked({ required String? listingAnchor, required DateTime? start, required DateTime? end, @@ -1865,8 +1846,8 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { #start: start, #end: end, }), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#createBlocked, [], { #listingAnchor: listingAnchor, @@ -1876,7 +1857,7 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override _i7.StreamWithStatus<_i10.Validation<_i10.Reservation>> @@ -1901,22 +1882,22 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i7.StreamWithStatus<_i10.Validation<_i10.Reservation>>); @override - _i29.Future reset() => + _i28.Future reset() => (super.noSuchMethod( Invocation.method(#reset, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future dispose() => + _i28.Future dispose() => (super.noSuchMethod( Invocation.method(#dispose, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.Validation<_i10.Reservation>> queryVerified({ @@ -1946,17 +1927,17 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i7.StreamWithStatus<_i10.Validation<_i10.Reservation>>); @override - _i29.Future<_i17.ReservationDeps> resolve(_i10.Reservation? item) => + _i28.Future<_i16.ReservationDeps> resolve(_i10.Reservation? item) => (super.noSuchMethod( Invocation.method(#resolve, [item]), - returnValue: _i29.Future<_i17.ReservationDeps>.value( - _FakeReservationDeps_30( + returnValue: _i28.Future<_i16.ReservationDeps>.value( + _FakeReservationDeps_29( this, Invocation.method(#resolve, [item]), ), ), ) - as _i29.Future<_i17.ReservationDeps>); + as _i28.Future<_i16.ReservationDeps>); @override _i7.StreamWithStatus<_i10.Validation<_i10.Reservation>> subscribeVerified({ @@ -1988,11 +1969,11 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { @override _i10.Validation<_i10.Reservation> verify( _i10.Reservation? item, - _i17.ReservationDeps? deps, + _i16.ReservationDeps? deps, ) => (super.noSuchMethod( Invocation.method(#verify, [item, deps]), - returnValue: _FakeValidation_31<_i10.Reservation>( + returnValue: _FakeValidation_30<_i10.Reservation>( this, Invocation.method(#verify, [item, deps]), ), @@ -2006,13 +1987,13 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { ); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.Reservation>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.Reservation>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.Reservation> subscribe( @@ -2083,16 +2064,16 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i8.ExpandableSubscription<_i10.Reservation>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.Reservation>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -2106,45 +2087,45 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.Reservation>> upsert( + _i28.Future<_i9.UpsertResult<_i10.Reservation>> upsert( _i10.Reservation? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), - returnValue: _i29.Future<_i9.UpsertResult<_i10.Reservation>>.value( + returnValue: _i28.Future<_i9.UpsertResult<_i10.Reservation>>.value( _FakeUpsertResult_13<_i10.Reservation>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.Reservation>>); + as _i28.Future<_i9.UpsertResult<_i10.Reservation>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.Reservation? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.Reservation?> getOne( + _i28.Future<_i10.Reservation?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -2155,107 +2136,107 @@ class MockReservations extends _i1.Mock implements _i17.Reservations { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.Reservation?>.value(), + returnValue: _i28.Future<_i10.Reservation?>.value(), ) - as _i29.Future<_i10.Reservation?>); + as _i28.Future<_i10.Reservation?>); @override - _i29.Future<_i10.Reservation?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.Reservation?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.Reservation?>.value(), + returnValue: _i28.Future<_i10.Reservation?>.value(), ) - as _i29.Future<_i10.Reservation?>); + as _i28.Future<_i10.Reservation?>); @override - _i29.Future<_i10.Reservation> getById(String? id) => + _i28.Future<_i10.Reservation> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [EscrowUseCase]. /// /// See the documentation for Mockito's code generation for more information. -class MockEscrowUseCase extends _i1.Mock implements _i33.EscrowUseCase { +class MockEscrowUseCase extends _i1.Mock implements _i32.EscrowUseCase { MockEscrowUseCase() { _i1.throwOnMissingStub(this); } @override - _i18.EscrowFundPreparer fund(_i34.EscrowFundParams? params) => + _i17.EscrowFundPreparer fund(_i33.EscrowFundParams? params) => (super.noSuchMethod( Invocation.method(#fund, [params]), - returnValue: _FakeEscrowFundPreparer_32( + returnValue: _FakeEscrowFundPreparer_31( this, Invocation.method(#fund, [params]), ), ) - as _i18.EscrowFundPreparer); + as _i17.EscrowFundPreparer); @override - _i19.EscrowClaimOperation claim(_i35.EscrowClaimParams? params) => + _i18.EscrowClaimOperation claim(_i34.EscrowClaimParams? params) => (super.noSuchMethod( Invocation.method(#claim, [params]), - returnValue: _FakeEscrowClaimOperation_33( + returnValue: _FakeEscrowClaimOperation_32( this, Invocation.method(#claim, [params]), ), ) - as _i19.EscrowClaimOperation); + as _i18.EscrowClaimOperation); @override - _i20.EscrowReleaseOperation release(_i36.EscrowReleaseParams? params) => + _i19.EscrowReleaseOperation release(_i35.EscrowReleaseParams? params) => (super.noSuchMethod( Invocation.method(#release, [params]), - returnValue: _FakeEscrowReleaseOperation_34( + returnValue: _FakeEscrowReleaseOperation_33( this, Invocation.method(#release, [params]), ), ) - as _i20.EscrowReleaseOperation); + as _i19.EscrowReleaseOperation); @override - _i7.StreamWithStatus<_i37.EscrowEvent> checkEscrowStatus( + _i7.StreamWithStatus<_i36.EscrowEvent> checkEscrowStatus( _i10.EscrowServiceSelected? selectedEscrow, String? tradeId, ) => (super.noSuchMethod( Invocation.method(#checkEscrowStatus, [selectedEscrow, tradeId]), - returnValue: _FakeStreamWithStatus_6<_i37.EscrowEvent>( + returnValue: _FakeStreamWithStatus_6<_i36.EscrowEvent>( this, Invocation.method(#checkEscrowStatus, [selectedEscrow, tradeId]), ), ) - as _i7.StreamWithStatus<_i37.EscrowEvent>); + as _i7.StreamWithStatus<_i36.EscrowEvent>); } /// A class which mocks [Escrows]. /// /// See the documentation for Mockito's code generation for more information. -class MockEscrows extends _i1.Mock implements _i21.Escrows { +class MockEscrows extends _i1.Mock implements _i20.Escrows { MockEscrows() { _i1.throwOnMissingStub(this); } @@ -2281,15 +2262,15 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.EscrowService> get updates => + _i28.Stream<_i10.EscrowService> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.EscrowService>.empty(), + returnValue: _i28.Stream<_i10.EscrowService>.empty(), ) - as _i29.Stream<_i10.EscrowService>); + as _i28.Stream<_i10.EscrowService>); @override - _i29.Future<_i21.MutualEscrowResult> determineMutualEscrow( + _i28.Future<_i20.MutualEscrowResult> determineMutualEscrow( String? buyerPubkey, String? sellerPubkey, ) => @@ -2298,8 +2279,8 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { buyerPubkey, sellerPubkey, ]), - returnValue: _i29.Future<_i21.MutualEscrowResult>.value( - _FakeMutualEscrowResult_35( + returnValue: _i28.Future<_i20.MutualEscrowResult>.value( + _FakeMutualEscrowResult_34( this, Invocation.method(#determineMutualEscrow, [ buyerPubkey, @@ -2308,7 +2289,7 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { ), ), ) - as _i29.Future<_i21.MutualEscrowResult>); + as _i28.Future<_i20.MutualEscrowResult>); @override void notifyUpdate(_i10.EscrowService? event) => super.noSuchMethod( @@ -2317,22 +2298,22 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { ); @override - _i29.Future beforeUpsert(_i10.EscrowService? event) => + _i28.Future beforeUpsert(_i10.EscrowService? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.EscrowService>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.EscrowService>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.EscrowService> subscribe( @@ -2406,16 +2387,16 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { as _i8.ExpandableSubscription<_i10.EscrowService>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.EscrowService>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -2429,46 +2410,46 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.EscrowService>> upsert( + _i28.Future<_i9.UpsertResult<_i10.EscrowService>> upsert( _i10.EscrowService? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), returnValue: - _i29.Future<_i9.UpsertResult<_i10.EscrowService>>.value( + _i28.Future<_i9.UpsertResult<_i10.EscrowService>>.value( _FakeUpsertResult_13<_i10.EscrowService>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.EscrowService>>); + as _i28.Future<_i9.UpsertResult<_i10.EscrowService>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.EscrowService? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.EscrowService>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.EscrowService?> getOne( + _i28.Future<_i10.EscrowService?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -2479,51 +2460,51 @@ class MockEscrows extends _i1.Mock implements _i21.Escrows { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.EscrowService?>.value(), + returnValue: _i28.Future<_i10.EscrowService?>.value(), ) - as _i29.Future<_i10.EscrowService?>); + as _i28.Future<_i10.EscrowService?>); @override - _i29.Future<_i10.EscrowService?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.EscrowService?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.EscrowService?>.value(), + returnValue: _i28.Future<_i10.EscrowService?>.value(), ) - as _i29.Future<_i10.EscrowService?>); + as _i28.Future<_i10.EscrowService?>); @override - _i29.Future<_i10.EscrowService> getById(String? id) => + _i28.Future<_i10.EscrowService> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.EscrowService>.value( - _FakeEscrowService_36(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.EscrowService>.value( + _FakeEscrowService_35(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.EscrowService>); + as _i28.Future<_i10.EscrowService>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.EscrowService>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [EscrowMethods]. /// /// See the documentation for Mockito's code generation for more information. -class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { +class MockEscrowMethods extends _i1.Mock implements _i37.EscrowMethods { MockEscrowMethods() { _i1.throwOnMissingStub(this); } @@ -2549,23 +2530,23 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.EscrowMethod> get updates => + _i28.Stream<_i10.EscrowMethod> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.EscrowMethod>.empty(), + returnValue: _i28.Stream<_i10.EscrowMethod>.empty(), ) - as _i29.Stream<_i10.EscrowMethod>); + as _i28.Stream<_i10.EscrowMethod>); @override - _i29.Future<_i10.EscrowMethod?> myMethod() => + _i28.Future<_i10.EscrowMethod?> myMethod() => (super.noSuchMethod( Invocation.method(#myMethod, []), - returnValue: _i29.Future<_i10.EscrowMethod?>.value(), + returnValue: _i28.Future<_i10.EscrowMethod?>.value(), ) - as _i29.Future<_i10.EscrowMethod?>); + as _i28.Future<_i10.EscrowMethod?>); @override - _i29.Future ensureEscrowMethod({ + _i28.Future ensureEscrowMethod({ Set? bytecodeHashes = const {}, List? trustedEscrowPubkeys = const [], List<_i10.AcceptedPaymentForm>? acceptedPaymentForms, @@ -2576,10 +2557,10 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { #trustedEscrowPubkeys: trustedEscrowPubkeys, #acceptedPaymentForms: acceptedPaymentForms, }), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override void notifyUpdate(_i10.EscrowMethod? event) => super.noSuchMethod( @@ -2588,22 +2569,22 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { ); @override - _i29.Future beforeUpsert(_i10.EscrowMethod? event) => + _i28.Future beforeUpsert(_i10.EscrowMethod? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.EscrowMethod>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.EscrowMethod>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.EscrowMethod> subscribe( @@ -2677,16 +2658,16 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { as _i8.ExpandableSubscription<_i10.EscrowMethod>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.EscrowMethod>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -2700,45 +2681,45 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.EscrowMethod>> upsert( + _i28.Future<_i9.UpsertResult<_i10.EscrowMethod>> upsert( _i10.EscrowMethod? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), - returnValue: _i29.Future<_i9.UpsertResult<_i10.EscrowMethod>>.value( + returnValue: _i28.Future<_i9.UpsertResult<_i10.EscrowMethod>>.value( _FakeUpsertResult_13<_i10.EscrowMethod>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.EscrowMethod>>); + as _i28.Future<_i9.UpsertResult<_i10.EscrowMethod>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.EscrowMethod? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.EscrowMethod>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.EscrowMethod?> getOne( + _i28.Future<_i10.EscrowMethod?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -2749,51 +2730,51 @@ class MockEscrowMethods extends _i1.Mock implements _i38.EscrowMethods { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.EscrowMethod?>.value(), + returnValue: _i28.Future<_i10.EscrowMethod?>.value(), ) - as _i29.Future<_i10.EscrowMethod?>); + as _i28.Future<_i10.EscrowMethod?>); @override - _i29.Future<_i10.EscrowMethod?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.EscrowMethod?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.EscrowMethod?>.value(), + returnValue: _i28.Future<_i10.EscrowMethod?>.value(), ) - as _i29.Future<_i10.EscrowMethod?>); + as _i28.Future<_i10.EscrowMethod?>); @override - _i29.Future<_i10.EscrowMethod> getById(String? id) => + _i28.Future<_i10.EscrowMethod> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.EscrowMethod>.value( - _FakeEscrowMethod_37(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.EscrowMethod>.value( + _FakeEscrowMethod_36(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.EscrowMethod>); + as _i28.Future<_i10.EscrowMethod>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.EscrowMethod>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [BadgeDefinitions]. /// /// See the documentation for Mockito's code generation for more information. -class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { +class MockBadgeDefinitions extends _i1.Mock implements _i38.BadgeDefinitions { MockBadgeDefinitions() { _i1.throwOnMissingStub(this); } @@ -2819,12 +2800,12 @@ class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.BadgeDefinition> get updates => + _i28.Stream<_i10.BadgeDefinition> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.BadgeDefinition>.empty(), + returnValue: _i28.Stream<_i10.BadgeDefinition>.empty(), ) - as _i29.Stream<_i10.BadgeDefinition>); + as _i28.Stream<_i10.BadgeDefinition>); @override void notifyUpdate(_i10.BadgeDefinition? event) => super.noSuchMethod( @@ -2833,24 +2814,24 @@ class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { ); @override - _i29.Future beforeUpsert(_i10.BadgeDefinition? event) => + _i28.Future beforeUpsert(_i10.BadgeDefinition? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future afterUpsert( + _i28.Future afterUpsert( _i9.UpsertResult<_i10.BadgeDefinition>? result, ) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.BadgeDefinition> subscribe( @@ -2924,16 +2905,16 @@ class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { as _i8.ExpandableSubscription<_i10.BadgeDefinition>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.BadgeDefinition>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -2947,46 +2928,46 @@ class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.BadgeDefinition>> upsert( + _i28.Future<_i9.UpsertResult<_i10.BadgeDefinition>> upsert( _i10.BadgeDefinition? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), returnValue: - _i29.Future<_i9.UpsertResult<_i10.BadgeDefinition>>.value( + _i28.Future<_i9.UpsertResult<_i10.BadgeDefinition>>.value( _FakeUpsertResult_13<_i10.BadgeDefinition>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.BadgeDefinition>>); + as _i28.Future<_i9.UpsertResult<_i10.BadgeDefinition>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.BadgeDefinition? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.BadgeDefinition>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.BadgeDefinition?> getOne( + _i28.Future<_i10.BadgeDefinition?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -2997,54 +2978,54 @@ class MockBadgeDefinitions extends _i1.Mock implements _i39.BadgeDefinitions { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.BadgeDefinition?>.value(), + returnValue: _i28.Future<_i10.BadgeDefinition?>.value(), ) - as _i29.Future<_i10.BadgeDefinition?>); + as _i28.Future<_i10.BadgeDefinition?>); @override - _i29.Future<_i10.BadgeDefinition?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.BadgeDefinition?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.BadgeDefinition?>.value(), + returnValue: _i28.Future<_i10.BadgeDefinition?>.value(), ) - as _i29.Future<_i10.BadgeDefinition?>); + as _i28.Future<_i10.BadgeDefinition?>); @override - _i29.Future<_i10.BadgeDefinition> getById(String? id) => + _i28.Future<_i10.BadgeDefinition> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.BadgeDefinition>.value( - _FakeBadgeDefinition_38(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.BadgeDefinition>.value( + _FakeBadgeDefinition_37(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.BadgeDefinition>); + as _i28.Future<_i10.BadgeDefinition>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag( + _i28.Future> findByTag( String? tag, String? value, ) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.BadgeDefinition>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [BadgeAwards]. /// /// See the documentation for Mockito's code generation for more information. -class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { +class MockBadgeAwards extends _i1.Mock implements _i39.BadgeAwards { MockBadgeAwards() { _i1.throwOnMissingStub(this); } @@ -3070,12 +3051,12 @@ class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.BadgeAward> get updates => + _i28.Stream<_i10.BadgeAward> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.BadgeAward>.empty(), + returnValue: _i28.Stream<_i10.BadgeAward>.empty(), ) - as _i29.Stream<_i10.BadgeAward>); + as _i28.Stream<_i10.BadgeAward>); @override void notifyUpdate(_i10.BadgeAward? event) => super.noSuchMethod( @@ -3084,22 +3065,22 @@ class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { ); @override - _i29.Future beforeUpsert(_i10.BadgeAward? event) => + _i28.Future beforeUpsert(_i10.BadgeAward? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.BadgeAward>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.BadgeAward>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.BadgeAward> subscribe( @@ -3170,16 +3151,16 @@ class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { as _i8.ExpandableSubscription<_i10.BadgeAward>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.BadgeAward>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -3193,45 +3174,45 @@ class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.BadgeAward>> upsert( + _i28.Future<_i9.UpsertResult<_i10.BadgeAward>> upsert( _i10.BadgeAward? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), - returnValue: _i29.Future<_i9.UpsertResult<_i10.BadgeAward>>.value( + returnValue: _i28.Future<_i9.UpsertResult<_i10.BadgeAward>>.value( _FakeUpsertResult_13<_i10.BadgeAward>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.BadgeAward>>); + as _i28.Future<_i9.UpsertResult<_i10.BadgeAward>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.BadgeAward? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.BadgeAward>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.BadgeAward?> getOne( + _i28.Future<_i10.BadgeAward?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -3242,45 +3223,45 @@ class MockBadgeAwards extends _i1.Mock implements _i40.BadgeAwards { [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.BadgeAward?>.value(), + returnValue: _i28.Future<_i10.BadgeAward?>.value(), ) - as _i29.Future<_i10.BadgeAward?>); + as _i28.Future<_i10.BadgeAward?>); @override - _i29.Future<_i10.BadgeAward?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.BadgeAward?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.BadgeAward?>.value(), + returnValue: _i28.Future<_i10.BadgeAward?>.value(), ) - as _i29.Future<_i10.BadgeAward?>); + as _i28.Future<_i10.BadgeAward?>); @override - _i29.Future<_i10.BadgeAward> getById(String? id) => + _i28.Future<_i10.BadgeAward> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.BadgeAward>.value( - _FakeBadgeAward_39(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.BadgeAward>.value( + _FakeBadgeAward_38(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.BadgeAward>); + as _i28.Future<_i10.BadgeAward>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.BadgeAward>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [Messaging]. @@ -3292,22 +3273,22 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { } @override - _i22.Threads get threads => + _i21.Threads get threads => (super.noSuchMethod( Invocation.getter(#threads), - returnValue: _FakeThreads_40(this, Invocation.getter(#threads)), + returnValue: _FakeThreads_39(this, Invocation.getter(#threads)), ) - as _i22.Threads); + as _i21.Threads); @override - _i29.Future<_i6.Nip01Event> getRumour( + _i28.Future<_i6.Nip01Event> getRumour( String? content, List>? tags, List? recipientPubkeys, ) => (super.noSuchMethod( Invocation.method(#getRumour, [content, tags, recipientPubkeys]), - returnValue: _i29.Future<_i6.Nip01Event>.value( + returnValue: _i28.Future<_i6.Nip01Event>.value( _FakeNip01Event_4( this, Invocation.method(#getRumour, [ @@ -3318,10 +3299,10 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { ), ), ) - as _i29.Future<_i6.Nip01Event>); + as _i28.Future<_i6.Nip01Event>); @override - _i29.Future<_i6.Nip01Event> getJsonRumour( + _i28.Future<_i6.Nip01Event> getJsonRumour( String? content, List>? tags, List? recipientPubkeys, { @@ -3333,7 +3314,7 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { [content, tags, recipientPubkeys], {#altText: altText}, ), - returnValue: _i29.Future<_i6.Nip01Event>.value( + returnValue: _i28.Future<_i6.Nip01Event>.value( _FakeNip01Event_4( this, Invocation.method( @@ -3344,18 +3325,18 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { ), ), ) - as _i29.Future<_i6.Nip01Event>); + as _i28.Future<_i6.Nip01Event>); @override - _i29.Future> recipientMessageRelays(String? recipientPubkey) => + _i28.Future> recipientMessageRelays(String? recipientPubkey) => (super.noSuchMethod( Invocation.method(#recipientMessageRelays, [recipientPubkey]), - returnValue: _i29.Future>.value([]), + returnValue: _i28.Future>.value([]), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i6.Nip01Event> broadcastTextAndAwait({ + _i28.Future<_i6.Nip01Event> broadcastTextAndAwait({ required String? content, required List>? tags, required List? recipientPubkeys, @@ -3366,7 +3347,7 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #tags: tags, #recipientPubkeys: recipientPubkeys, }), - returnValue: _i29.Future<_i6.Nip01Event>.value( + returnValue: _i28.Future<_i6.Nip01Event>.value( _FakeNip01Event_4( this, Invocation.method(#broadcastTextAndAwait, [], { @@ -3377,10 +3358,10 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { ), ), ) - as _i29.Future<_i6.Nip01Event>); + as _i28.Future<_i6.Nip01Event>); @override - _i29.Future>>> + _i28.Future>>> broadcastText({ required String? content, required List>? tags, @@ -3393,14 +3374,14 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #recipientPubkeys: recipientPubkeys, }), returnValue: - _i29.Future< - List<_i29.Future>> - >.value(<_i29.Future>>[]), + _i28.Future< + List<_i28.Future>> + >.value(<_i28.Future>>[]), ) - as _i29.Future>>>); + as _i28.Future>>>); @override - _i29.Future>>> + _i28.Future>>> broadcastTextAllowingExternalRelays({ required String? content, required List>? tags, @@ -3413,14 +3394,14 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #recipientPubkeys: recipientPubkeys, }), returnValue: - _i29.Future< - List<_i29.Future>> - >.value(<_i29.Future>>[]), + _i28.Future< + List<_i28.Future>> + >.value(<_i28.Future>>[]), ) - as _i29.Future>>>); + as _i28.Future>>>); @override - _i29.Future<_i6.Nip01Event> broadcastEventAndWait({ + _i28.Future<_i6.Nip01Event> broadcastEventAndWait({ required _i6.Nip01Event? event, required List>? tags, required List? recipientPubkeys, @@ -3431,7 +3412,7 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #tags: tags, #recipientPubkeys: recipientPubkeys, }), - returnValue: _i29.Future<_i6.Nip01Event>.value( + returnValue: _i28.Future<_i6.Nip01Event>.value( _FakeNip01Event_4( this, Invocation.method(#broadcastEventAndWait, [], { @@ -3442,10 +3423,10 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { ), ), ) - as _i29.Future<_i6.Nip01Event>); + as _i28.Future<_i6.Nip01Event>); @override - _i29.Future>>> + _i28.Future>>> broadcastEvent({ required _i6.Nip01Event? event, required List>? tags, @@ -3458,14 +3439,14 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #recipientPubkeys: recipientPubkeys, }), returnValue: - _i29.Future< - List<_i29.Future>> - >.value(<_i29.Future>>[]), + _i28.Future< + List<_i28.Future>> + >.value(<_i28.Future>>[]), ) - as _i29.Future>>>); + as _i28.Future>>>); @override - _i29.Future broadcastSeenReceipt({ + _i28.Future broadcastSeenReceipt({ required int? seenUntil, required List>? tags, required List? recipientPubkeys, @@ -3476,17 +3457,17 @@ class MockMessaging extends _i1.Mock implements _i13.Messaging { #tags: tags, #recipientPubkeys: recipientPubkeys, }), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); } /// A class which mocks [ReservationRequests]. /// /// See the documentation for Mockito's code generation for more information. class MockReservationRequests extends _i1.Mock - implements _i41.ReservationRequests { + implements _i40.ReservationRequests { MockReservationRequests() { _i1.throwOnMissingStub(this); } @@ -3512,24 +3493,24 @@ class MockReservationRequests extends _i1.Mock (super.noSuchMethod(Invocation.getter(#kind), returnValue: 0) as int); @override - _i29.Stream<_i10.Reservation> get updates => + _i28.Stream<_i10.Reservation> get updates => (super.noSuchMethod( Invocation.getter(#updates), - returnValue: _i29.Stream<_i10.Reservation>.empty(), + returnValue: _i28.Stream<_i10.Reservation>.empty(), ) - as _i29.Stream<_i10.Reservation>); + as _i28.Stream<_i10.Reservation>); @override - _i29.Future beforeUpsert(_i10.Reservation? event) => + _i28.Future beforeUpsert(_i10.Reservation? event) => (super.noSuchMethod( Invocation.method(#beforeUpsert, [event]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i10.Reservation> createReservationRequest({ + _i28.Future<_i10.Reservation> createReservationRequest({ required _i10.Listing? listing, required DateTime? startDate, required DateTime? endDate, @@ -3542,8 +3523,8 @@ class MockReservationRequests extends _i1.Mock #endDate: endDate, #amount: amount, }), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#createReservationRequest, [], { #listing: listing, @@ -3554,10 +3535,10 @@ class MockReservationRequests extends _i1.Mock ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future<_i10.Reservation> createCounterOffer({ + _i28.Future<_i10.Reservation> createCounterOffer({ required _i10.Listing? listing, required _i10.Reservation? previousRequest, required _i10.DenominatedAmount? amount, @@ -3570,8 +3551,8 @@ class MockReservationRequests extends _i1.Mock #amount: amount, #signerKeyPair: signerKeyPair, }), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#createCounterOffer, [], { #listing: listing, @@ -3582,10 +3563,10 @@ class MockReservationRequests extends _i1.Mock ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future<_i10.Reservation> createCancellation({ + _i28.Future<_i10.Reservation> createCancellation({ required _i10.Reservation? previousRequest, required _i5.KeyPair? signerKeyPair, }) => @@ -3594,8 +3575,8 @@ class MockReservationRequests extends _i1.Mock #previousRequest: previousRequest, #signerKeyPair: signerKeyPair, }), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29( + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28( this, Invocation.method(#createCancellation, [], { #previousRequest: previousRequest, @@ -3604,7 +3585,7 @@ class MockReservationRequests extends _i1.Mock ), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override void notifyUpdate(_i10.Reservation? event) => super.noSuchMethod( @@ -3613,13 +3594,13 @@ class MockReservationRequests extends _i1.Mock ); @override - _i29.Future afterUpsert(_i9.UpsertResult<_i10.Reservation>? result) => + _i28.Future afterUpsert(_i9.UpsertResult<_i10.Reservation>? result) => (super.noSuchMethod( Invocation.method(#afterUpsert, [result]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i7.StreamWithStatus<_i10.Reservation> subscribe( @@ -3690,16 +3671,16 @@ class MockReservationRequests extends _i1.Mock as _i8.ExpandableSubscription<_i10.Reservation>); @override - _i29.Future startExpandable( + _i28.Future startExpandable( _i8.ExpandableSubscription<_i10.Reservation>? subscription, _i7.StreamWithStatus<_i6.Filter>? filterSource, ) => (super.noSuchMethod( Invocation.method(#startExpandable, [subscription, filterSource]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override _i6.Filter kindFilter(_i6.Filter? filter) => @@ -3713,45 +3694,45 @@ class MockReservationRequests extends _i1.Mock as _i6.Filter); @override - _i29.Future<_i9.UpsertResult<_i10.Reservation>> upsert( + _i28.Future<_i9.UpsertResult<_i10.Reservation>> upsert( _i10.Reservation? event, { _i8.NostrEventSigner? signer, }) => (super.noSuchMethod( Invocation.method(#upsert, [event], {#signer: signer}), - returnValue: _i29.Future<_i9.UpsertResult<_i10.Reservation>>.value( + returnValue: _i28.Future<_i9.UpsertResult<_i10.Reservation>>.value( _FakeUpsertResult_13<_i10.Reservation>( this, Invocation.method(#upsert, [event], {#signer: signer}), ), ), ) - as _i29.Future<_i9.UpsertResult<_i10.Reservation>>); + as _i28.Future<_i9.UpsertResult<_i10.Reservation>>); @override - _i29.Future> delete( + _i28.Future> delete( _i10.Reservation? event, ) => (super.noSuchMethod( Invocation.method(#delete, [event]), - returnValue: _i29.Future>.value( - <_i31.RelayBroadcastResponse>[], + returnValue: _i28.Future>.value( + <_i30.RelayBroadcastResponse>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future> list(_i6.Filter? f, {String? name}) => + _i28.Future> list(_i6.Filter? f, {String? name}) => (super.noSuchMethod( Invocation.method(#list, [f], {#name: name}), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future<_i10.Reservation?> getOne( + _i28.Future<_i10.Reservation?> getOne( _i6.Filter? f, { bool? batch = true, bool? cacheRead = true, @@ -3762,69 +3743,69 @@ class MockReservationRequests extends _i1.Mock [f], {#batch: batch, #cacheRead: cacheRead}, ), - returnValue: _i29.Future<_i10.Reservation?>.value(), + returnValue: _i28.Future<_i10.Reservation?>.value(), ) - as _i29.Future<_i10.Reservation?>); + as _i28.Future<_i10.Reservation?>); @override - _i29.Future<_i10.Reservation?> getOneByAnchor(String? anchor) => + _i28.Future<_i10.Reservation?> getOneByAnchor(String? anchor) => (super.noSuchMethod( Invocation.method(#getOneByAnchor, [anchor]), - returnValue: _i29.Future<_i10.Reservation?>.value(), + returnValue: _i28.Future<_i10.Reservation?>.value(), ) - as _i29.Future<_i10.Reservation?>); + as _i28.Future<_i10.Reservation?>); @override - _i29.Future<_i10.Reservation> getById(String? id) => + _i28.Future<_i10.Reservation> getById(String? id) => (super.noSuchMethod( Invocation.method(#getById, [id]), - returnValue: _i29.Future<_i10.Reservation>.value( - _FakeReservation_29(this, Invocation.method(#getById, [id])), + returnValue: _i28.Future<_i10.Reservation>.value( + _FakeReservation_28(this, Invocation.method(#getById, [id])), ), ) - as _i29.Future<_i10.Reservation>); + as _i28.Future<_i10.Reservation>); @override - _i29.Future count() => + _i28.Future count() => (super.noSuchMethod( Invocation.method(#count, []), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> findByTag(String? tag, String? value) => + _i28.Future> findByTag(String? tag, String? value) => (super.noSuchMethod( Invocation.method(#findByTag, [tag, value]), - returnValue: _i29.Future>.value( + returnValue: _i28.Future>.value( <_i10.Reservation>[], ), ) - as _i29.Future>); + as _i28.Future>); } /// A class which mocks [Payments]. /// /// See the documentation for Mockito's code generation for more information. -class MockPayments extends _i1.Mock implements _i23.Payments { +class MockPayments extends _i1.Mock implements _i22.Payments { MockPayments() { _i1.throwOnMissingStub(this); } @override - _i29.Future getMyInvoice(int? amountSats, {String? description}) => + _i28.Future getMyInvoice(int? amountSats, {String? description}) => (super.noSuchMethod( Invocation.method( #getMyInvoice, [amountSats], {#description: description}, ), - returnValue: _i29.Future.value(), + returnValue: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future<_i23.CreatedLightningInvoice?> getMyInvoiceWithSource( + _i28.Future<_i22.CreatedLightningInvoice?> getMyInvoiceWithSource( int? amountSats, { String? description, }) => @@ -3834,19 +3815,19 @@ class MockPayments extends _i1.Mock implements _i23.Payments { [amountSats], {#description: description}, ), - returnValue: _i29.Future<_i23.CreatedLightningInvoice?>.value(), + returnValue: _i28.Future<_i22.CreatedLightningInvoice?>.value(), ) - as _i29.Future<_i23.CreatedLightningInvoice?>); + as _i28.Future<_i22.CreatedLightningInvoice?>); @override - _i29.Future<_i23.AutomaticInvoiceDestination> + _i28.Future<_i22.AutomaticInvoiceDestination> resolveAutomaticInvoiceDestination({bool? verifyLightningAddress = true}) => (super.noSuchMethod( Invocation.method(#resolveAutomaticInvoiceDestination, [], { #verifyLightningAddress: verifyLightningAddress, }), - returnValue: _i29.Future<_i23.AutomaticInvoiceDestination>.value( - _FakeAutomaticInvoiceDestination_41( + returnValue: _i28.Future<_i22.AutomaticInvoiceDestination>.value( + _FakeAutomaticInvoiceDestination_40( this, Invocation.method(#resolveAutomaticInvoiceDestination, [], { #verifyLightningAddress: verifyLightningAddress, @@ -3854,38 +3835,38 @@ class MockPayments extends _i1.Mock implements _i23.Payments { ), ), ) - as _i29.Future<_i23.AutomaticInvoiceDestination>); + as _i28.Future<_i22.AutomaticInvoiceDestination>); @override - _i25.PayOperation< - _i24.PayParameters, - _i24.ResolvedDetails, - _i24.CallbackDetails, - _i24.CompletedDetails + _i24.PayOperation< + _i23.PayParameters, + _i23.ResolvedDetails, + _i23.CallbackDetails, + _i23.CompletedDetails > - pay(_i24.PayParameters? params) => + pay(_i23.PayParameters? params) => (super.noSuchMethod( Invocation.method(#pay, [params]), returnValue: - _FakePayOperation_42< - _i24.PayParameters, - _i24.ResolvedDetails, - _i24.CallbackDetails, - _i24.CompletedDetails + _FakePayOperation_41< + _i23.PayParameters, + _i23.ResolvedDetails, + _i23.CallbackDetails, + _i23.CompletedDetails >(this, Invocation.method(#pay, [params])), ) - as _i25.PayOperation< - _i24.PayParameters, - _i24.ResolvedDetails, - _i24.CallbackDetails, - _i24.CompletedDetails + as _i24.PayOperation< + _i23.PayParameters, + _i23.ResolvedDetails, + _i23.CallbackDetails, + _i23.CompletedDetails >); } /// A class which mocks [Evm]. /// /// See the documentation for Mockito's code generation for more information. -class MockEvm extends _i1.Mock implements _i42.Evm { +class MockEvm extends _i1.Mock implements _i41.Evm { MockEvm() { _i1.throwOnMissingStub(this); } @@ -3899,94 +3880,94 @@ class MockEvm extends _i1.Mock implements _i42.Evm { as _i7.CustomLogger); @override - List<_i26.EvmChain> get configuredChains => + List<_i25.EvmChain> get configuredChains => (super.noSuchMethod( Invocation.getter(#configuredChains), - returnValue: <_i26.EvmChain>[], + returnValue: <_i25.EvmChain>[], ) - as List<_i26.EvmChain>); + as List<_i25.EvmChain>); @override - _i29.Future init() => + _i28.Future init() => (super.noSuchMethod( Invocation.method(#init, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i26.EvmChain getChainForEscrowService(_i10.EscrowService? service) => + _i25.EvmChain getChainForEscrowService(_i10.EscrowService? service) => (super.noSuchMethod( Invocation.method(#getChainForEscrowService, [service]), - returnValue: _FakeEvmChain_43( + returnValue: _FakeEvmChain_42( this, Invocation.method(#getChainForEscrowService, [service]), ), ) - as _i26.EvmChain); + as _i25.EvmChain); @override - _i26.EvmChain? getChainByChainId(int? chainId) => + _i25.EvmChain? getChainByChainId(int? chainId) => (super.noSuchMethod(Invocation.method(#getChainByChainId, [chainId])) - as _i26.EvmChain?); + as _i25.EvmChain?); @override - _i26.EvmChain? getChainById(String? id) => + _i25.EvmChain? getChainById(String? id) => (super.noSuchMethod(Invocation.method(#getChainById, [id])) - as _i26.EvmChain?); + as _i25.EvmChain?); @override - _i29.Future reset() => + _i28.Future reset() => (super.noSuchMethod( Invocation.method(#reset, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future dispose() => + _i28.Future dispose() => (super.noSuchMethod( Invocation.method(#dispose, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future> swapOutAll({ + _i28.Future> swapOutAll({ _i10.TokenAmount? minimumBalance, }) => (super.noSuchMethod( Invocation.method(#swapOutAll, [], { #minimumBalance: minimumBalance, }), - returnValue: _i29.Future>.value( - <_i43.EvmSwapOutOperation>[], + returnValue: _i28.Future>.value( + <_i42.EvmSwapOutOperation>[], ), ) - as _i29.Future>); + as _i28.Future>); @override - _i29.Future recoverStaleOperations({ + _i28.Future recoverStaleOperations({ bool? isBackground = false, - _i44.OnBackgroundProgress? onProgress, + _i43.OnBackgroundProgress? onProgress, }) => (super.noSuchMethod( Invocation.method(#recoverStaleOperations, [], { #isBackground: isBackground, #onProgress: onProgress, }), - returnValue: _i29.Future.value(0), + returnValue: _i28.Future.value(0), ) - as _i29.Future); + as _i28.Future); } /// A class which mocks [Relays]. /// /// See the documentation for Mockito's code generation for more information. -class MockRelays extends _i1.Mock implements _i45.Relays { +class MockRelays extends _i1.Mock implements _i44.Relays { MockRelays() { _i1.throwOnMissingStub(this); } @@ -4008,89 +3989,89 @@ class MockRelays extends _i1.Mock implements _i45.Relays { as _i6.Ndk); @override - _i27.RelayStorage get relayStorage => + _i26.RelayStorage get relayStorage => (super.noSuchMethod( Invocation.getter(#relayStorage), - returnValue: _FakeRelayStorage_44( + returnValue: _FakeRelayStorage_43( this, Invocation.getter(#relayStorage), ), ) - as _i27.RelayStorage); + as _i26.RelayStorage); @override - _i29.Future relayHintFor(String? pubkey) => + _i28.Future relayHintFor(String? pubkey) => (super.noSuchMethod( Invocation.method(#relayHintFor, [pubkey]), - returnValue: _i29.Future.value( - _i28.dummyValue( + returnValue: _i28.Future.value( + _i27.dummyValue( this, Invocation.method(#relayHintFor, [pubkey]), ), ), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future add(String? url) => + _i28.Future add(String? url) => (super.noSuchMethod( Invocation.method(#add, [url]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future remove(String? url) => + _i28.Future remove(String? url) => (super.noSuchMethod( Invocation.method(#remove, [url]), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future startSeedRelays() => + _i28.Future startSeedRelays() => (super.noSuchMethod( Invocation.method(#startSeedRelays, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future awaitCoreRelay({ + _i28.Future awaitCoreRelay({ Duration? timeout = const Duration(seconds: 30), }) => (super.noSuchMethod( Invocation.method(#awaitCoreRelay, [], {#timeout: timeout}), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Stream>> connectivity() => + _i28.Stream>> connectivity() => (super.noSuchMethod( Invocation.method(#connectivity, []), returnValue: - _i29.Stream< - Map> + _i28.Stream< + Map> >.empty(), ) - as _i29.Stream>>); + as _i28.Stream>>); @override - _i29.Future reconnectNow() => + _i28.Future reconnectNow() => (super.noSuchMethod( Invocation.method(#reconnectNow, []), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future ensureConnected( + _i28.Future ensureConnected( String? url, { Duration? timeout = const Duration(seconds: 10), Duration? pollInterval = const Duration(milliseconds: 200), @@ -4101,20 +4082,20 @@ class MockRelays extends _i1.Mock implements _i45.Relays { [url], {#timeout: timeout, #pollInterval: pollInterval}, ), - returnValue: _i29.Future.value(false), + returnValue: _i28.Future.value(false), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future loadNip65Hints(String? pubkey) => + _i28.Future loadNip65Hints(String? pubkey) => (super.noSuchMethod( Invocation.method(#loadNip65Hints, [pubkey]), - returnValue: _i29.Future.value(false), + returnValue: _i28.Future.value(false), ) - as _i29.Future); + as _i28.Future); @override - _i29.Future publishNip65({ + _i28.Future publishNip65({ required String? hostrRelay, required String? pubkey, }) => @@ -4123,8 +4104,8 @@ class MockRelays extends _i1.Mock implements _i45.Relays { #hostrRelay: hostrRelay, #pubkey: pubkey, }), - returnValue: _i29.Future.value(), - returnValueForMissingStub: _i29.Future.value(), + returnValue: _i28.Future.value(), + returnValueForMissingStub: _i28.Future.value(), ) - as _i29.Future); + as _i28.Future); } diff --git a/hostr_sdk/lib/runtime.dart b/hostr_sdk/lib/runtime.dart index a09d0621..fd36be02 100644 --- a/hostr_sdk/lib/runtime.dart +++ b/hostr_sdk/lib/runtime.dart @@ -91,10 +91,9 @@ class HostrSession { Listings get listings => hostr.listings; LnurlUseCase get lnurl => hostr.lnurl; Location get location => hostr.location; - Reservations get reservations => hostr.reservations; - ReservationGroups get reservationGroups => hostr.reservationGroups; - ReservationTransitions get reservationTransitions => - hostr.reservationTransitions; + Reservations get orderWorkflows => hostr.orderWorkflows; + OrderGroupVerification get orderGroupVerification => + hostr.orderGroupVerification; GiftWraps get giftWraps => hostr.giftWraps; DmRelays get dmRelays => hostr.dmRelays; EscrowUseCase get escrow => hostr.escrow; diff --git a/hostr_sdk/lib/seed/pipeline/seed_factory.dart b/hostr_sdk/lib/seed/pipeline/seed_factory.dart index 1da27cbc..2bbbecce 100644 --- a/hostr_sdk/lib/seed/pipeline/seed_factory.dart +++ b/hostr_sdk/lib/seed/pipeline/seed_factory.dart @@ -11,7 +11,7 @@ import 'stages/build_badges.dart' as stage_badges; import 'stages/build_listings.dart' as stage_listings; import 'stages/build_messages.dart' as stage_messages; import 'stages/build_profiles.dart' as stage_profiles; -import 'stages/build_reservation_transitions.dart' as stage_transitions; +import 'stages/build_order_transitions.dart' as stage_transitions; import 'stages/build_reviews.dart' as stage_reviews; import 'stages/build_threads.dart' as stage_threads; import 'stages/build_users.dart' as stage_users; @@ -139,12 +139,11 @@ class SeedFactory { factory: _entities, ); - List buildReservationTransitions( - List threads, - ) => stage_transitions.buildReservationTransitions( - threads: threads, - factory: _entities, - ); + List buildOrderTransitions(List threads) => + stage_transitions.buildOrderTransitions( + threads: threads, + factory: _entities, + ); Future> buildReviews(List threads) => stage_reviews .buildReviews(ctx: _ctx, threads: threads, factory: _entities); @@ -198,7 +197,7 @@ class SeedFactory { final reservationRequests = threads .map((t) => t.request) .toList(growable: false); - final reservationTransitions = buildReservationTransitions(threads); + final orderTransitions = buildOrderTransitions(threads); final messages = await buildMessages(threads); final escrowSelectedMessages = await buildEscrowSelectedMessages(threads); @@ -214,7 +213,7 @@ class SeedFactory { escrowMethods: escrowMethods, threads: threads, reservationRequests: reservationRequests, - reservationTransitions: reservationTransitions, + orderTransitions: orderTransitions, threadMessages: [...messages, ...escrowSelectedMessages], reservations: const [], // no outcomes — all pending zapReceipts: const [], diff --git a/hostr_sdk/lib/seed/pipeline/seed_pipeline_models.dart b/hostr_sdk/lib/seed/pipeline/seed_pipeline_models.dart index 86553b83..bb6c8916 100644 --- a/hostr_sdk/lib/seed/pipeline/seed_pipeline_models.dart +++ b/hostr_sdk/lib/seed/pipeline/seed_pipeline_models.dart @@ -124,7 +124,7 @@ class SeedPipelineData { final List escrowMethods; final List threads; final List reservationRequests; - final List reservationTransitions; + final List orderTransitions; final List threadMessages; final List reservations; final List zapReceipts; @@ -141,7 +141,7 @@ class SeedPipelineData { required this.escrowMethods, required this.threads, required this.reservationRequests, - required this.reservationTransitions, + required this.orderTransitions, required this.threadMessages, required this.reservations, required this.zapReceipts, @@ -158,7 +158,7 @@ class SeedPipelineData { ...listings, // reservationRequests are intentionally excluded — negotiate-stage // events must only appear gift-wrapped (present in threadMessages). - ...reservationTransitions, + ...orderTransitions, ...threadMessages, ...zapReceipts, ...reservations, @@ -206,7 +206,7 @@ class SeedPipelineData { escrowThreads: escrowThreads, zapThreads: zapThreads, reservationRequests: reservationRequests.length, - reservationTransitions: reservationTransitions.length, + orderTransitions: orderTransitions.length, messages: threadMessages.length, reservations: reservations.length, zapReceipts: zapReceipts.length, @@ -235,7 +235,7 @@ class SeedSummary { final int escrowThreads; final int zapThreads; final int reservationRequests; - final int reservationTransitions; + final int orderTransitions; final int messages; final int reservations; final int zapReceipts; @@ -259,7 +259,7 @@ class SeedSummary { required this.escrowThreads, required this.zapThreads, required this.reservationRequests, - required this.reservationTransitions, + required this.orderTransitions, required this.messages, required this.reservations, required this.zapReceipts, @@ -284,7 +284,7 @@ class SeedSummary { 'escrowThreads': escrowThreads, 'zapThreads': zapThreads, 'reservationRequests': reservationRequests, - 'reservationTransitions': reservationTransitions, + 'orderTransitions': orderTransitions, 'messages': messages, 'reservations': reservations, 'zapReceipts': zapReceipts, diff --git a/hostr_sdk/lib/seed/pipeline/seeder.dart b/hostr_sdk/lib/seed/pipeline/seeder.dart index d40bd203..f9837792 100644 --- a/hostr_sdk/lib/seed/pipeline/seeder.dart +++ b/hostr_sdk/lib/seed/pipeline/seeder.dart @@ -185,8 +185,8 @@ class Seeder { } // Transitions (depends on reservations being set). - final reservationTransitions = factory.buildReservationTransitions(threads); - for (final t in reservationTransitions) { + final orderTransitions = factory.buildOrderTransitions(threads); + for (final t in orderTransitions) { await sink.publish(t); } @@ -236,7 +236,7 @@ class Seeder { escrowMethods: escrowMethods, threads: threads, reservationRequests: reservationRequests, - reservationTransitions: reservationTransitions, + orderTransitions: orderTransitions, threadMessages: threadMessages, reservations: reservations, zapReceipts: zapReceipts, diff --git a/hostr_sdk/lib/seed/pipeline/stages/build_reservation_transitions.dart b/hostr_sdk/lib/seed/pipeline/stages/build_order_transitions.dart similarity index 87% rename from hostr_sdk/lib/seed/pipeline/stages/build_reservation_transitions.dart rename to hostr_sdk/lib/seed/pipeline/stages/build_order_transitions.dart index d06166d3..92ee9c63 100644 --- a/hostr_sdk/lib/seed/pipeline/stages/build_reservation_transitions.dart +++ b/hostr_sdk/lib/seed/pipeline/stages/build_order_transitions.dart @@ -3,13 +3,13 @@ import 'package:models/main.dart'; import '../entity_factory.dart'; import '../seed_pipeline_models.dart'; -/// Build deterministic [ReservationTransition] events for seeded threads. +/// Build deterministic order transition events for seeded threads. /// /// Emits transitions for: -/// - reservation request creation (guest, negotiate -> negotiate) -/// - finalized reservation creation/update (guest/host, negotiate -> commit) +/// - order request creation (guest, negotiate -> negotiate) +/// - finalized order creation/update (guest/host, negotiate -> commit) /// - cancellation updates (host/guest, * -> cancel) -List buildReservationTransitions({ +List buildOrderTransitions({ required List threads, EntityFactory? factory, }) { diff --git a/hostr_sdk/lib/usecase/background_worker/background_worker.dart b/hostr_sdk/lib/usecase/background_worker/background_worker.dart index 1211cd15..dd47860a 100644 --- a/hostr_sdk/lib/usecase/background_worker/background_worker.dart +++ b/hostr_sdk/lib/usecase/background_worker/background_worker.dart @@ -14,7 +14,7 @@ import '../evm/operations/operation_state_store.dart'; import '../heartbeat/heartbeat.dart'; import '../listings/listings.dart'; import '../metadata/metadata.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; +import '../order_groups/order_group_participant_resolver.dart'; import '../user_subscriptions/user_subscriptions.dart'; /// A single notification to show or update in the OS notification tray. diff --git a/hostr_sdk/lib/usecase/calendar/calendar.dart b/hostr_sdk/lib/usecase/calendar/calendar.dart index f579e4d3..fcab092e 100644 --- a/hostr_sdk/lib/usecase/calendar/calendar.dart +++ b/hostr_sdk/lib/usecase/calendar/calendar.dart @@ -7,7 +7,7 @@ import 'package:models/main.dart'; import '../../util/custom_logger.dart'; import '../listings/listings.dart'; import '../metadata/metadata.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; +import '../order_groups/order_group_participant_resolver.dart'; import '../user_subscriptions/user_subscriptions.dart'; abstract class CalendarPort { diff --git a/hostr_sdk/lib/usecase/escrow/escrow_verification.dart b/hostr_sdk/lib/usecase/escrow/escrow_verification.dart index 0878c22d..1f7183c0 100644 --- a/hostr_sdk/lib/usecase/escrow/escrow_verification.dart +++ b/hostr_sdk/lib/usecase/escrow/escrow_verification.dart @@ -31,7 +31,7 @@ class EscrowVerificationResult { /// matching on-chain trade with the correct amount. /// /// This is a stateless utility that can be used by: -/// - [ReservationGroups] when validating buyer-only groups +/// - [OrderGroupVerification] when validating buyer-only groups /// - [TradeAudit] when auditing a specific trade /// /// It does NOT validate Nostr-level proof structure (signatures, listing diff --git a/hostr_sdk/lib/usecase/escrow_daemon/escrow_daemon.dart b/hostr_sdk/lib/usecase/escrow_daemon/escrow_daemon.dart index 7e7f7f69..d7bb8a77 100644 --- a/hostr_sdk/lib/usecase/escrow_daemon/escrow_daemon.dart +++ b/hostr_sdk/lib/usecase/escrow_daemon/escrow_daemon.dart @@ -22,8 +22,8 @@ import '../listings/listings.dart'; import '../messaging/messaging.dart'; import '../metadata/metadata.dart'; import '../requests/requests.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; -import '../reservation_groups/reservation_groups.dart'; +import '../order_groups/order_group_participant_resolver.dart'; +import '../order_groups/order_group_verification.dart'; import '../reservations/reservation_participant_keyring.dart'; import '../reservations/reservation_participant_tags.dart'; import '../reservations/reservations.dart'; @@ -438,7 +438,7 @@ class EscrowDaemon { // ── Reservation auto-confirmation state ───────────────────────────────── late final EscrowReservationNotifier _reservationNotifier; - final Map _reservationGroups = {}; + final Map _orderGroups = {}; final Map _reservationRetryTimers = {}; PublishSubject? _reservationRetryTradeIds; List _legacyDmBootstrapRelays = const []; @@ -721,8 +721,8 @@ class EscrowDaemon { } /// All reservation groups the escrow is involved in. - Map get reservationGroups => - Map.unmodifiable(_reservationGroups); + Map get orderGroups => + Map.unmodifiable(_orderGroups); @visibleForTesting static Stream reservationListenerEvents( @@ -737,7 +737,7 @@ class EscrowDaemon { required bool forceValidateSelfSigned, required EscrowVerification escrowVerification, }) { - return ReservationGroups.verifyGroupOnChain( + return OrderGroupVerification.verifyGroupOnChain( group, forceValidateSelfSigned: forceValidateSelfSigned, escrowVerification: escrowVerification, @@ -983,7 +983,7 @@ class EscrowDaemon { Future _processReservationTradeId(String tradeId) async { try { - final groups = await _queryReservationGroupsForTrade(tradeId); + final groups = await _queryOrderGroupsForTrade(tradeId); for (final group in groups) { await _processGroup(group); } @@ -993,13 +993,13 @@ class EscrowDaemon { } } - Future> _queryReservationGroupsForTrade( + Future> _queryOrderGroupsForTrade( String tradeId, ) async { final escrowPubkey = _auth.activeKeyPair!.publicKey; final reservations = await _reservations.getByTradeId(tradeId); final groups = - Reservations.toReservationGroups(reservations: reservations).values + Reservations.toOrderGroups(reservations: reservations).values .where( (group) => reservationGroupInvolvesEscrow(group, escrowPubkey), ) @@ -1007,7 +1007,7 @@ class EscrowDaemon { ..sort((a, b) => a.groupId.compareTo(b.groupId)); for (final group in groups) { - _reservationGroups[group.groupId] = group; + _orderGroups[group.groupId] = group; } return groups; } @@ -1056,7 +1056,7 @@ class EscrowDaemon { if (latest != null) { final latestEscrowReservation = latest.escrowReservation; if (latestEscrowReservation != null) { - _reservationGroups[latest.groupId] = latest; + _orderGroups[latest.groupId] = latest; if (latestEscrowReservation.stage == ReservationStage.cancel) { await _reservationNotifier.notifyCancellation(latest); } else if (latestEscrowReservation.stage == @@ -1099,8 +1099,9 @@ class EscrowDaemon { // Update local group so we don't re-process. final groupId = rawReservationGroupId(reservation); - _reservationGroups[groupId] = (_reservationGroups[groupId] ?? group) - .addReservation(reservation); + _orderGroups[groupId] = (_orderGroups[groupId] ?? group).addReservation( + reservation, + ); _logger.i('✓ Published escrow CONFIRM for trade=${group.tradeId}'); } @@ -1109,7 +1110,7 @@ class EscrowDaemon { ReservationGroup group, ) async { final reservations = await _reservations.getByTradeId(group.tradeId); - final groups = Reservations.toReservationGroups(reservations: reservations); + final groups = Reservations.toOrderGroups(reservations: reservations); final escrowPubkey = _auth.activeKeyPair!.publicKey; final latest = groups[group.groupId] ?? @@ -1117,7 +1118,7 @@ class EscrowDaemon { return reservationGroupInvolvesEscrow(candidate, escrowPubkey); }).firstOrNull; if (latest != null) { - _reservationGroups[latest.groupId] = latest; + _orderGroups[latest.groupId] = latest; } return latest; } @@ -1132,8 +1133,9 @@ class EscrowDaemon { // Update local group so we don't re-process. final groupId = rawReservationGroupId(reservation); - _reservationGroups[groupId] = (_reservationGroups[groupId] ?? group) - .addReservation(reservation); + _orderGroups[groupId] = (_orderGroups[groupId] ?? group).addReservation( + reservation, + ); _logger.i('✗ Published escrow CANCEL for trade=${group.tradeId}'); } diff --git a/hostr_sdk/lib/usecase/main.dart b/hostr_sdk/lib/usecase/main.dart index f730cc81..600b983a 100644 --- a/hostr_sdk/lib/usecase/main.dart +++ b/hostr_sdk/lib/usecase/main.dart @@ -27,10 +27,9 @@ export 'nwc/main.dart'; export 'payments/main.dart'; export 'relays/relays.dart'; export 'requests/requests.dart'; -export 'reservation_groups/reservation_group_participant_resolver.dart'; -export 'reservation_groups/reservation_groups.dart'; +export 'order_groups/order_group_participant_resolver.dart'; +export 'order_groups/order_group_verification.dart'; export 'reservation_requests/reservation_requests.dart'; -export 'reservation_transitions/reservation_transitions.dart'; export 'reservations/reservation_participant_keyring.dart'; export 'reservations/reservation_participant_tags.dart'; export 'reservations/reservation_participant_authorization.dart'; diff --git a/hostr_sdk/lib/usecase/messaging/escrow_trade_thread_resolver.dart b/hostr_sdk/lib/usecase/messaging/escrow_trade_thread_resolver.dart index 2c8892e1..3413d1e7 100644 --- a/hostr_sdk/lib/usecase/messaging/escrow_trade_thread_resolver.dart +++ b/hostr_sdk/lib/usecase/messaging/escrow_trade_thread_resolver.dart @@ -4,7 +4,7 @@ import 'package:models/main.dart'; import '../../util/main.dart'; import '../auth/auth.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; +import '../order_groups/order_group_participant_resolver.dart'; import '../reservations/reservation_participant_keyring.dart'; import '../reservations/reservations.dart'; import '../trade_account_allocator/trade_account_allocator.dart'; diff --git a/hostr_sdk/lib/usecase/reservation_groups/reservation_group_participant_resolver.dart b/hostr_sdk/lib/usecase/order_groups/order_group_participant_resolver.dart similarity index 100% rename from hostr_sdk/lib/usecase/reservation_groups/reservation_group_participant_resolver.dart rename to hostr_sdk/lib/usecase/order_groups/order_group_participant_resolver.dart diff --git a/hostr_sdk/lib/usecase/reservation_groups/reservation_groups.dart b/hostr_sdk/lib/usecase/order_groups/order_group_verification.dart similarity index 98% rename from hostr_sdk/lib/usecase/reservation_groups/reservation_groups.dart rename to hostr_sdk/lib/usecase/order_groups/order_group_verification.dart index 9b2e835c..9ff1fd51 100644 --- a/hostr_sdk/lib/usecase/reservation_groups/reservation_groups.dart +++ b/hostr_sdk/lib/usecase/order_groups/order_group_verification.dart @@ -12,10 +12,10 @@ import '../reservations/reservation_participant_tags.dart'; import '../reservations/reservations.dart'; /// Dependencies resolved for a single reservation-group verification. -class ReservationGroupDeps { +class OrderGroupDeps { final Listing listing; - const ReservationGroupDeps({required this.listing}); + const OrderGroupDeps({required this.listing}); } /// Use case that groups raw [Reservation] events into [ReservationGroup]s @@ -32,7 +32,7 @@ class ReservationGroupDeps { /// 3. Buyer-only (self-signed) → validate payment proof via /// [Reservation.validate]. @Singleton() -class ReservationGroups { +class OrderGroupVerification { final Reservations _reservations; final CustomLogger _logger; final Evm _evm; @@ -43,7 +43,7 @@ class ReservationGroups { logger: _logger, ); - ReservationGroups({ + OrderGroupVerification({ required Reservations reservations, required CustomLogger logger, required Evm evm, @@ -93,7 +93,7 @@ class ReservationGroups { kListingRefTag: [listingAnchor], }, ), - name: 'ReservationGroups-verified', + name: 'OrderGroupVerification-verified', ); return _buildValidatedStream( source: source, @@ -121,7 +121,7 @@ class ReservationGroups { kListingRefTag: [listingAnchor], }, ), - name: 'ReservationGroups-query', + name: 'OrderGroupVerification-query', ); return _buildValidatedStream( source: source, diff --git a/hostr_sdk/lib/usecase/reservation_requests/reservation_requests.dart b/hostr_sdk/lib/usecase/reservation_requests/reservation_requests.dart index 372ed793..3211779e 100644 --- a/hostr_sdk/lib/usecase/reservation_requests/reservation_requests.dart +++ b/hostr_sdk/lib/usecase/reservation_requests/reservation_requests.dart @@ -1,6 +1,7 @@ import 'package:crypto/crypto.dart' as crypto; import 'package:injectable/injectable.dart'; import 'package:models/main.dart'; +import 'package:ndk/ndk.dart' show MarketplaceOrder; import 'package:ndk/shared/nips/nip01/key_pair.dart'; import '../../util/coinlib_gift_wrap.dart'; @@ -31,11 +32,7 @@ class ReservationRequests extends CrudUseCase { @override Future beforeUpsert(Reservation event) async { - if (event.stage == ReservationStage.negotiate) { - throw StateError( - 'Negotiate-stage reservations must be sent as private messages, not broadcast.', - ); - } + MarketplaceOrder.fromEvent(event).ensureCanBroadcast(); } Future _signReservation({ diff --git a/hostr_sdk/lib/usecase/reservation_transitions/reservation_transitions.dart b/hostr_sdk/lib/usecase/reservation_transitions/reservation_transitions.dart deleted file mode 100644 index 8983ea86..00000000 --- a/hostr_sdk/lib/usecase/reservation_transitions/reservation_transitions.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'package:injectable/injectable.dart'; -import 'package:models/main.dart'; -import 'package:ndk/ndk.dart'; -import 'package:ndk/shared/nips/nip01/key_pair.dart'; - -import '../../util/main.dart'; -import '../crud.usecase.dart'; - -/// CRUD use-case for append-only [ReservationTransition] events. -/// -/// Every reservation stage change (negotiate ↔ counter-offer, negotiate → -/// commit, * → cancel, seller-ack) MUST be recorded as a transition so -/// relays and auditing clients can reconstruct the full history. -@Singleton() -class ReservationTransitions extends CrudUseCase { - final Ndk _ndk; - - ReservationTransitions({ - required super.requests, - required super.logger, - required Ndk ndk, - }) : _ndk = ndk, - super(kind: ReservationTransition.kinds[0]); - - /// Broadcast a transition event and return it. - /// - /// [reservation] — the reservation being transitioned. - /// [transitionType] — what kind of transition this is. - /// [fromStage] — the stage before the transition. - /// [toStage] — the stage after the transition. - /// [commitTermsHash] — the commit-terms hash at the time of transition. - /// [reason] — optional human-readable note (e.g. cancellation reason). - /// [updatedFields] — snapshot of changed fields for counter-offers. - /// [prevTransitionId] — event id of the previous transition in the chain. - Future record({ - required Reservation reservation, - required ReservationTransitionType transitionType, - required ReservationStage fromStage, - required ReservationStage toStage, - KeyPair? signerKeyPair, - String? commitTermsHash, - String? reason, - Map? updatedFields, - String? prevTransitionId, - }) async { - final tradeId = reservation.getDtag() ?? ''; - final privateKey = signerKeyPair?.privateKey; - final pubkey = privateKey != null && privateKey.isNotEmpty - ? signerKeyPair!.publicKey - : _ndk.accounts.getPublicKey()!; - final effectivePrevTransitionId = - prevTransitionId ?? - await _resolvePreviousTransitionId(tradeId: tradeId, pubkey: pubkey); - final tags = >[ - if (tradeId.isNotEmpty) ['d', tradeId], - if (tradeId.isNotEmpty) ['t', tradeId], - ['e', reservation.id], - if (effectivePrevTransitionId != null) - ['prev', effectivePrevTransitionId], - if (reservation.parsedTags.listingAnchor.isNotEmpty) - [kListingRefTag, reservation.parsedTags.listingAnchor], - ]; - - final unsigned = Nip01Event( - kind: kNostrKindReservationTransition, - pubKey: pubkey, - tags: tags, - content: ReservationTransitionContent( - transitionType: transitionType, - fromStage: fromStage, - toStage: toStage, - commitTermsHash: commitTermsHash ?? reservation.commitHash(), - reason: reason, - updatedFields: updatedFields, - ).toString(), - ); - final transition = ReservationTransition.fromNostrEvent(unsigned); - final result = await upsert( - transition, - signer: privateKey != null && privateKey.isNotEmpty - ? (event) async => Nip01Utils.signWithPrivateKey( - event: event, - privateKey: privateKey, - ) - : null, - ); - return result.event; - } - - Future _resolvePreviousTransitionId({ - required String tradeId, - required String pubkey, - }) async { - if (tradeId.isEmpty) return null; - - final existing = (await getForReservation( - tradeId, - )).where((transition) => transition.pubKey == pubkey).toList(); - if (existing.isEmpty) return null; - - final chain = resolveStateTransitionChain(existing); - if (!chain.validation.isValid) { - throw StateError( - 'Cannot append reservation transition: existing transition chain is ' - 'invalid (${chain.validation.reason})', - ); - } - - return chain.transitions.last.id; - } - - /// Query all transitions for a given trade id (`d` tag). - Future> getForReservation(String tradeId) { - return list( - Filter(kinds: ReservationTransition.kinds, dTags: [tradeId]), - name: 'reservation-transitions-get-$tradeId', - ); - } - - /// Subscribe to live transitions for a given trade id (`d` tag). - StreamWithStatus subscribeForReservation( - String tradeId, - ) { - return subscribe( - Filter(kinds: ReservationTransition.kinds, dTags: [tradeId]), - name: 'reservation-transitions-$tradeId', - ); - } -} diff --git a/hostr_sdk/lib/usecase/reservations/reservation_participant_tags.dart b/hostr_sdk/lib/usecase/reservations/reservation_participant_tags.dart index 8ce92615..b92def1c 100644 --- a/hostr_sdk/lib/usecase/reservations/reservation_participant_tags.dart +++ b/hostr_sdk/lib/usecase/reservations/reservation_participant_tags.dart @@ -1,4 +1,5 @@ import 'package:models/main.dart'; +import 'package:ndk/ndk.dart' show MarketplaceOrder, MarketplaceOrderGroup; import 'package:ndk/shared/nips/nip01/key_pair.dart'; typedef ReservationParticipantAuthorizationSigner = @@ -195,11 +196,13 @@ Set resolvedReservationGroupParticipantSet({ } String rawReservationGroupId(Reservation reservation) { - return ReservationGroup.groupIdFromEvent(reservation); + return MarketplaceOrderGroup.groupIdFromOrder( + MarketplaceOrder.fromEvent(reservation), + ); } String rawReservationGroupIdForGroup(ReservationGroup group) { - return ReservationGroup.groupIdForParticipants( + return MarketplaceOrderGroup.groupIdForParticipants( tradeId: group.tradeId, participants: rawReservationGroupParticipantSet(group), ); @@ -213,7 +216,7 @@ String resolvedReservationGroupId({ if (tradeId == null || tradeId.isEmpty) { throw StateError('Cannot derive reservation group id without trade id'); } - return ReservationGroup.groupIdForParticipants( + return MarketplaceOrderGroup.groupIdForParticipants( tradeId: tradeId, participants: resolvedReservationParticipantSet( reservation: reservation, @@ -226,7 +229,7 @@ String resolvedReservationGroupIdForGroup({ required ReservationGroup group, Iterable resolvedProofs = const [], }) { - return ReservationGroup.groupIdForParticipants( + return MarketplaceOrderGroup.groupIdForParticipants( tradeId: group.tradeId, participants: resolvedReservationGroupParticipantSet( group: group, diff --git a/hostr_sdk/lib/usecase/reservations/reservations.dart b/hostr_sdk/lib/usecase/reservations/reservations.dart index 954b85fd..8d2d8dee 100644 --- a/hostr_sdk/lib/usecase/reservations/reservations.dart +++ b/hostr_sdk/lib/usecase/reservations/reservations.dart @@ -15,7 +15,6 @@ import '../crud.usecase.dart'; import '../listings/listings.dart'; import '../messaging/messaging.dart'; import '../relays/relays.dart'; -import '../reservation_transitions/reservation_transitions.dart'; import 'reservation_participant_authorization_resolver.dart'; import 'reservation_participant_tags.dart'; @@ -37,7 +36,6 @@ class Reservations extends CrudUseCase implements CanVerify { final Messaging _messaging; final Auth _auth; - final ReservationTransitions _transitions; final Listings _listings; final Relays _relays; late final ReservationParticipantAuthorizationResolver @@ -45,7 +43,6 @@ class Reservations extends CrudUseCase ReservationParticipantAuthorizationResolver(logger: logger); Messaging get messaging => _messaging; Auth get auth => _auth; - ReservationTransitions get transitions => _transitions; Listings get listings => _listings; StreamWithStatus? _myReservations; StreamSubscription? _myReservationsSubscription; @@ -54,12 +51,10 @@ class Reservations extends CrudUseCase required super.logger, required Messaging messaging, required Auth auth, - required ReservationTransitions transitions, required Listings listings, required Relays relays, }) : _messaging = messaging, _auth = auth, - _transitions = transitions, _listings = listings, _relays = relays, super(kind: Reservation.kinds[0]); @@ -71,11 +66,7 @@ class Reservations extends CrudUseCase @override Future beforeUpsert(Reservation event) async { - if (event.stage == ReservationStage.negotiate) { - throw StateError( - 'Negotiate-stage reservations must be sent as private messages, not broadcast.', - ); - } + MarketplaceOrder.fromEvent(event).ensureCanBroadcast(); } Future _signReservation({ @@ -99,6 +90,31 @@ class Reservations extends CrudUseCase return reservation.signAs(signerKeyPair, Reservation.fromNostrEvent); } + EventSigner? _transitionSignerFor(KeyPair? signerKeyPair) { + final keyPair = signerKeyPair; + if (keyPair == null) return null; + final privateKey = keyPair.privateKey; + if (privateKey == null || privateKey.isEmpty) return null; + return Bip340EventSigner( + privateKey: privateKey, + publicKey: keyPair.publicKey, + ); + } + + MarketplaceOrderStage _marketplaceStage(ReservationStage stage) { + return MarketplaceOrderStage.values.firstWhere( + (value) => value.name == stage.name, + ); + } + + MarketplaceOrderTransitionType _marketplaceTransitionType( + ReservationTransitionType type, + ) { + return MarketplaceOrderTransitionType.values.firstWhere( + (value) => value.name == type.name, + ); + } + /// Query all reservations for a given trade id (d-tag). Future> getByTradeId(String tradeId) { logger.d('Fetching reservations for tradeId: $tradeId'); @@ -224,34 +240,34 @@ class Reservations extends CrudUseCase /// /// Each group's role-based getters (sellerReservation, buyerReservation, /// escrowReservation) are computed from the flat list automatically. - static Map toReservationGroups({ + static Map toOrderGroups({ required List reservations, }) { - final Map> grouped = {}; - - for (final reservation in reservations) { - final groupId = rawReservationGroupId(reservation); - grouped.putIfAbsent(groupId, () => []); - // Replace any existing reservation from the same pubkey - grouped[groupId]!.removeWhere((r) => r.pubKey == reservation.pubKey); - grouped[groupId]!.add(reservation); - } + final groups = groupMarketplaceOrders( + orders: reservations.map(MarketplaceOrder.fromEvent), + ); - return grouped.map( - (groupId, list) => - MapEntry(groupId, ReservationGroup(reservations: list)), + return groups.map( + (groupId, group) => MapEntry( + groupId, + ReservationGroup( + reservations: group.orders.map(Reservation.fromNostrEvent).toList(), + confirmedCommitted: group.confirmedCommitted, + ), + ), ); } /// Queries all reservations for [listing] and returns them grouped as /// [ReservationGroup] by trade id (`d` tag). - Future> queryReservationGroups({ + Future> queryOrderGroups({ required Listing listing, }) async { - final reservations = await getListingReservations( - listingAnchor: listing.anchor!, - ); - return toReservationGroups(reservations: reservations); + final orders = await requests.ndk.marketplace.orders + .queryByListing(listingAnchor: listing.anchor!) + .future; + final reservations = orders.map(Reservation.fromNostrEvent).toList(); + return toOrderGroups(reservations: reservations); } Map groupByThread(List reservations) { @@ -570,7 +586,7 @@ class Reservations extends CrudUseCase /// /// All public mutation methods that advance a reservation through its /// lifecycle ([accept], [createSelfSigned], [cancel], [createBlocked]) MUST - /// use this instead of calling [upsert] + [transitions.record] separately, + /// use this instead of calling [upsert] + transition recording separately, /// enforcing the invariant that no reservation is broadcast without a /// transition record. Future> _upsertWithTransition({ @@ -583,12 +599,12 @@ class Reservations extends CrudUseCase String? reason, }) async { final result = await upsert(reservation); - await transitions.record( - reservation: reservation, - transitionType: transitionType, - fromStage: fromStage, - toStage: toStage, - signerKeyPair: signerKeyPair, + await requests.ndk.marketplace.orderTransitions.record( + order: MarketplaceOrder.fromEvent(reservation), + transitionType: _marketplaceTransitionType(transitionType), + fromStage: _marketplaceStage(fromStage), + toStage: _marketplaceStage(toStage), + customSigner: _transitionSignerFor(signerKeyPair), commitTermsHash: commitTermsHash, reason: reason, ); diff --git a/hostr_sdk/lib/usecase/reviews/reviews.dart b/hostr_sdk/lib/usecase/reviews/reviews.dart index 16aadad8..462c5d0d 100644 --- a/hostr_sdk/lib/usecase/reviews/reviews.dart +++ b/hostr_sdk/lib/usecase/reviews/reviews.dart @@ -5,7 +5,7 @@ import '../can_verify.dart'; import '../crud.usecase.dart'; import '../escrow/escrow_verification.dart'; import '../listings/listings.dart'; -import '../reservation_groups/reservation_groups.dart'; +import '../order_groups/order_group_verification.dart'; import '../reservations/reservation_participant_tags.dart'; import '../reservations/reservations.dart'; @@ -134,7 +134,7 @@ class Reviews extends CrudUseCase with CanVerify { final validatedGroup = groupReservations.isEmpty ? null - : await ReservationGroups.verifyGroupOnChain( + : await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: groupReservations), escrowVerification: _escrowVerification, ); diff --git a/hostr_sdk/lib/usecase/trade_audit/trade_audit.dart b/hostr_sdk/lib/usecase/trade_audit/trade_audit.dart index fc5939c6..87184399 100644 --- a/hostr_sdk/lib/usecase/trade_audit/trade_audit.dart +++ b/hostr_sdk/lib/usecase/trade_audit/trade_audit.dart @@ -1,11 +1,11 @@ import 'package:injectable/injectable.dart'; import 'package:models/main.dart'; +import 'package:ndk/ndk.dart' show Ndk; import '../../util/main.dart'; import '../escrow/escrow_verification.dart'; import '../evm/evm.dart'; import '../listings/listings.dart'; -import '../reservation_transitions/reservation_transitions.dart'; import '../reservations/reservations.dart'; /// Audit result for one side of a trade (buyer or seller). @@ -138,12 +138,12 @@ class TradeAuditResult { @Singleton() class TradeAudit { final Reservations _reservations; - final ReservationTransitions _transitions; + final Ndk _ndk; final Listings _listings; final CustomLogger _logger; final Evm _evm; Reservations get reservations => _reservations; - ReservationTransitions get transitions => _transitions; + Ndk get ndk => _ndk; Listings get listings => _listings; CustomLogger get logger => _logger; Evm get evm => _evm; @@ -156,12 +156,12 @@ class TradeAudit { TradeAudit({ required Reservations reservations, - required ReservationTransitions transitions, + required Ndk ndk, required Listings listings, required CustomLogger logger, required Evm evm, }) : _reservations = reservations, - _transitions = transitions, + _ndk = ndk, _listings = listings, _logger = logger, _evm = evm; @@ -173,7 +173,13 @@ class TradeAudit { // 1. Fetch reservation snapshots and transitions in parallel. final results = await Future.wait([ reservations.getByTradeId(tradeId), - transitions.getForReservation(tradeId), + ndk.marketplace.orderTransitions + .queryByTradeId(tradeId) + .future + .then( + (transitions) => + transitions.map(ReservationTransition.fromNostrEvent).toList(), + ), ]); final allReservations = results[0] as List; final allTransitions = results[1] as List; diff --git a/hostr_sdk/lib/usecase/trades/actions/reservation.dart b/hostr_sdk/lib/usecase/trades/actions/reservation.dart index fd42e6b0..d52be99a 100644 --- a/hostr_sdk/lib/usecase/trades/actions/reservation.dart +++ b/hostr_sdk/lib/usecase/trades/actions/reservation.dart @@ -52,10 +52,7 @@ class ReservationActions { final keyPair = await trade.activeKeyPair(); await reservations.cancel( - trade.currentReservationGroups - .whereType>() - .first - .event, + trade.currentOrderGroups.whereType>().first.event, keyPair, ); } diff --git a/hostr_sdk/lib/usecase/trades/actions/trade_action_resolver.dart b/hostr_sdk/lib/usecase/trades/actions/trade_action_resolver.dart index ef1a8a23..a7dd5db3 100644 --- a/hostr_sdk/lib/usecase/trades/actions/trade_action_resolver.dart +++ b/hostr_sdk/lib/usecase/trades/actions/trade_action_resolver.dart @@ -86,7 +86,7 @@ class TradeActionResolver { final overlapLock = allReservationsLoaded ? resolveOverlapLock( ourReservationDTag: tradeId, - allListingReservationGroups: validAllListingPairs, + allListingOrderGroups: validAllListingPairs, startDate: start, endDate: end, ) @@ -167,7 +167,7 @@ TradeAvailability _resolveAvailability({ } OverlapLock resolveOverlapLock({ - required List allListingReservationGroups, + required List allListingOrderGroups, required DateTime? startDate, required DateTime? endDate, required String ourReservationDTag, @@ -177,7 +177,7 @@ OverlapLock resolveOverlapLock({ return (isLoading: false, isBlocked: false, reason: null); } - final overlapsOtherCommitment = allListingReservationGroups.any((group) { + final overlapsOtherCommitment = allListingOrderGroups.any((group) { if (group.cancelled) { return false; } diff --git a/hostr_sdk/lib/usecase/trades/book_and_pay/book_and_pay_operation.dart b/hostr_sdk/lib/usecase/trades/book_and_pay/book_and_pay_operation.dart index da1de7cc..de4ed0b8 100644 --- a/hostr_sdk/lib/usecase/trades/book_and_pay/book_and_pay_operation.dart +++ b/hostr_sdk/lib/usecase/trades/book_and_pay/book_and_pay_operation.dart @@ -76,7 +76,7 @@ class BookAndPayOperation extends Cubit { try { emit(BookAndPayValidating(listingAnchor: input.listingAnchor)); - await _userSubscriptions.start(validateReservationGroups: false); + await _userSubscriptions.start(validateOrderGroups: false); await _paymentProofOrchestrator.start(); await _accountSeedStore.ensureReady(); await _evm.init(); @@ -258,7 +258,7 @@ class BookAndPayOperation extends Cubit { } Future _assertAvailable(Listing listing, BookAndPayInput input) async { - final groups = await _reservations.queryReservationGroups(listing: listing); + final groups = await _reservations.queryOrderGroups(listing: listing); if (!Listing.isAvailable(input.start, input.end, groups.values.toList())) { throw StateError('Listing is not available for those dates.'); } diff --git a/hostr_sdk/lib/usecase/trades/trade.dart b/hostr_sdk/lib/usecase/trades/trade.dart index e1872b8a..d9787ab5 100644 --- a/hostr_sdk/lib/usecase/trades/trade.dart +++ b/hostr_sdk/lib/usecase/trades/trade.dart @@ -17,8 +17,8 @@ import '../messaging/thread/state.dart'; import '../messaging/thread/thread.dart'; import '../messaging/threads.dart'; import '../metadata/metadata.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; -import '../reservation_groups/reservation_groups.dart'; +import '../order_groups/order_group_participant_resolver.dart'; +import '../order_groups/order_group_verification.dart'; import '../reservation_requests/reservation_requests.dart'; import '../reservations/reservations.dart'; import '../trade_account_allocator/trade_account_allocator.dart'; @@ -83,7 +83,7 @@ class Trade extends Cubit { final MetadataUseCase _metadata; final IdentityClaimsUseCase _identityClaims; final UserSubscriptions _userSubscriptions; - final ReservationGroups _reservationGroups; + final OrderGroupVerification _orderGroupVerification; final Threads _threads; final TradeAccountAllocator _tradeAccountAllocator; final ReservationRequests _reservationRequests; @@ -153,7 +153,7 @@ class Trade extends Cubit { required MetadataUseCase metadata, required IdentityClaimsUseCase identityClaims, required UserSubscriptions userSubscriptions, - required ReservationGroups reservationGroups, + required OrderGroupVerification orderGroupVerification, required Threads threads, required TradeAccountAllocator tradeAccountAllocator, required ReservationRequests reservationRequests, @@ -164,7 +164,7 @@ class Trade extends Cubit { _metadata = metadata, _identityClaims = identityClaims, _userSubscriptions = userSubscriptions, - _reservationGroups = reservationGroups, + _orderGroupVerification = orderGroupVerification, _threads = threads, _tradeAccountAllocator = tradeAccountAllocator, _reservationRequests = reservationRequests, @@ -181,8 +181,7 @@ class Trade extends Cubit { ), myReviews$ = userSubscriptions.myReviews$, super(const TradeInitialising()) { - resolvedReservationGroup$ = userSubscriptions - .allMyResolvedReservationGroups$ + resolvedReservationGroup$ = userSubscriptions.allMyResolvedOrderGroups$ .where(_matchesResolvedReservationGroup); reservationGroup$ = resolvedReservationGroup$.map( (item) => item.validation, @@ -398,7 +397,7 @@ class Trade extends Cubit { final hostProfile = _hostProfile; final sellerEvmAddress = _sellerEvmAddress; - allListingReservations$ = _reservationGroups.queryVerified( + allListingReservations$ = _orderGroupVerification.queryVerified( listingAnchor: listingAnchor, forceValidatePredicate: (group) => group.tradeId == tradeId, ); @@ -523,7 +522,7 @@ class Trade extends Cubit { final overlapLock = allListingReservationsLoaded ? resolveOverlapLock( ourReservationDTag: tradeId, - allListingReservationGroups: validAllListingPairs, + allListingOrderGroups: validAllListingPairs, startDate: start, endDate: end, ) @@ -696,7 +695,7 @@ class Trade extends Cubit { // ── Public API ───────────────────────────────────────────────────── /// Current reservation pair status list (for action execution). - List> get currentReservationGroups => + List> get currentOrderGroups => _bootstrapped ? reservationGroup$.items : const []; Future activeKeyPair() => _logger.span('activeKeyPair', () async { diff --git a/hostr_sdk/lib/usecase/user_subscriptions/user_subscriptions.dart b/hostr_sdk/lib/usecase/user_subscriptions/user_subscriptions.dart index 44c8e59e..6508d906 100644 --- a/hostr_sdk/lib/usecase/user_subscriptions/user_subscriptions.dart +++ b/hostr_sdk/lib/usecase/user_subscriptions/user_subscriptions.dart @@ -14,9 +14,8 @@ import '../gift_wraps/gift_wraps.dart'; import '../heartbeat/heartbeat.dart'; import '../messaging/threads.dart'; import '../requests/requests.dart'; -import '../reservation_groups/reservation_group_participant_resolver.dart'; -import '../reservation_groups/reservation_groups.dart'; -import '../reservation_transitions/reservation_transitions.dart'; +import '../order_groups/order_group_participant_resolver.dart'; +import '../order_groups/order_group_verification.dart'; import '../reservations/reservation_participant_keyring.dart'; import '../reservations/reservations.dart'; import '../reviews/reviews.dart'; @@ -53,8 +52,7 @@ class UserSubscriptions { final GiftWraps _giftWraps; final Heartbeats _heartbeats; final Reservations _reservations; - final ReservationTransitions _transitions; - final ReservationGroups _reservationGroups; + final OrderGroupVerification _orderGroupVerification; final Reviews _reviews; final Zaps _zaps; @@ -66,8 +64,7 @@ class UserSubscriptions { required GiftWraps giftWraps, required Heartbeats heartbeats, required Reservations reservations, - required ReservationTransitions transitions, - required ReservationGroups reservationGroups, + required OrderGroupVerification orderGroupVerification, required Reviews reviews, required Zaps zaps, required EscrowUseCase escrow, @@ -76,8 +73,7 @@ class UserSubscriptions { _giftWraps = giftWraps, _heartbeats = heartbeats, _reservations = reservations, - _transitions = transitions, - _reservationGroups = reservationGroups, + _orderGroupVerification = orderGroupVerification, _reviews = reviews, _zaps = zaps, _escrow = escrow, @@ -96,9 +92,9 @@ class UserSubscriptions { /// Validated reservation groups derived from [allMyReservations$]. /// Each group is grouped by trade ID and validated (proof-checked) via - /// [ReservationGroups.verifyFromSource]. Per-item stream — each emission + /// [OrderGroupVerification.verifyFromSource]. Per-item stream — each emission /// is a single [Validation] (upserted by group ID). - final StreamWithStatus> allMyReservationGroups$ = + final StreamWithStatus> allMyOrderGroups$ = StreamWithStatus(); /// Reservation groups plus participant-set resolution metadata. This stream @@ -106,7 +102,7 @@ class UserSubscriptions { /// group ids used to match private trade keys back to real conversation /// participants. final StreamWithStatus - allMyResolvedReservationGroups$ = StreamWithStatus(); + allMyResolvedOrderGroups$ = StreamWithStatus(); /// Reservation groups where the current user is the **guest** (not the host). final StreamWithStatus> myTrips$ = @@ -146,7 +142,11 @@ class UserSubscriptions { /// All reservation transitions across every trade the user is in. late final ExpandableSubscription allTransitions$ = - _transitions.createExpandable(name: 'user-transitions'); + ExpandableSubscription.idle( + requests: _reservations.requests, + logger: _logger, + name: 'ReservationTransition-user-transitions', + ); /// All heartbeat events discovered for counterparties in known threads. late final ExpandableSubscription allHeartbeats$ = @@ -169,9 +169,9 @@ class UserSubscriptions { StreamWithStatus(); // Intermediate derived sources created in start(), held for cleanup. - StreamWithStatus>? _reservationGroupsSource; + StreamWithStatus>? _orderGroupsSource; StreamWithStatus? - _resolvedReservationGroupsSource; + _resolvedOrderGroupsSource; StreamWithStatus>? _tripsSource; StreamWithStatus? _resolvedTripsSource; @@ -216,7 +216,7 @@ class UserSubscriptions { } Future start({ - bool validateReservationGroups = true, + bool validateOrderGroups = true, }) => _logger.span('start', () async { if (_started) return; _started = true; @@ -246,23 +246,24 @@ class UserSubscriptions { _reservationFilterSource!, ); - _reservationGroupsSource = _reservationGroups.verifyFromSource( + _orderGroupsSource = _orderGroupVerification.verifyFromSource( source: allMyReservations$.stream, - validate: validateReservationGroups, + validate: validateOrderGroups, + ); + allMyOrderGroups$.pipeFrom(_orderGroupsSource!); + _resolvedOrderGroupsSource = _orderGroupsSource!.resolveParticipantSets( + resolver: _buildParticipantResolver(), ); - allMyReservationGroups$.pipeFrom(_reservationGroupsSource!); - _resolvedReservationGroupsSource = _reservationGroupsSource! - .resolveParticipantSets(resolver: _buildParticipantResolver()); - allMyResolvedReservationGroups$.pipeFrom(_resolvedReservationGroupsSource!); + allMyResolvedOrderGroups$.pipeFrom(_resolvedOrderGroupsSource!); - _tripsSource = allMyReservationGroups$.where( + _tripsSource = allMyOrderGroups$.where( (item) => item.event.sellerPubkey != myPubkey, ); myTrips$.pipeFrom(_tripsSource!); _myTripsListSource = myTrips$.accumulateByKey((v) => v.event.tradeId); myTripsList$.pipeFrom(_myTripsListSource!); - _resolvedTripsSource = allMyResolvedReservationGroups$.where( + _resolvedTripsSource = allMyResolvedOrderGroups$.where( (item) => item.group.sellerPubkey != myPubkey, ); myResolvedTrips$.pipeFrom(_resolvedTripsSource!); @@ -271,14 +272,14 @@ class UserSubscriptions { ); myResolvedTripsList$.pipeFrom(_myResolvedTripsListSource!); - _hostingsSource = allMyReservationGroups$.where( + _hostingsSource = allMyOrderGroups$.where( (item) => item.event.sellerPubkey == myPubkey, ); myHostings$.pipeFrom(_hostingsSource!); _myHostingsListSource = myHostings$.accumulateByKey((v) => v.event.tradeId); myHostingsList$.pipeFrom(_myHostingsListSource!); - _resolvedHostingsSource = allMyResolvedReservationGroups$.where( + _resolvedHostingsSource = allMyResolvedOrderGroups$.where( (item) => item.group.sellerPubkey == myPubkey, ); myResolvedHostings$.pipeFrom(_resolvedHostingsSource!); @@ -287,10 +288,7 @@ class UserSubscriptions { ); myResolvedHostingsList$.pipeFrom(_myResolvedHostingsListSource!); - await _transitions.startExpandable( - allTransitions$, - _transitionFilterSource!, - ); + await allTransitions$.restart(_transitionFilterSource!); await _heartbeats.startExpandable(allHeartbeats$, _heartbeatFilterSource!); @@ -351,10 +349,10 @@ class UserSubscriptions { _resolvedTripsSource = null; await _tripsSource?.close(); _tripsSource = null; - await _resolvedReservationGroupsSource?.close(); - _resolvedReservationGroupsSource = null; - await _reservationGroupsSource?.close(); - _reservationGroupsSource = null; + await _resolvedOrderGroupsSource?.close(); + _resolvedOrderGroupsSource = null; + await _orderGroupsSource?.close(); + _orderGroupsSource = null; await _reviewsSource?.close(); _reviewsSource = null; @@ -369,8 +367,8 @@ class UserSubscriptions { await myResolvedTrips$.reset(); await myTripsList$.reset(); await myTrips$.reset(); - await allMyResolvedReservationGroups$.reset(); - await allMyReservationGroups$.reset(); + await allMyResolvedOrderGroups$.reset(); + await allMyOrderGroups$.reset(); await allMyReservations$.reset(); await allTransitions$.reset(); await allHeartbeats$.reset(); @@ -415,8 +413,8 @@ class UserSubscriptions { await myResolvedHostings$.close(); await myHostingsList$.close(); await myHostings$.close(); - await allMyResolvedReservationGroups$.close(); - await allMyReservationGroups$.close(); + await allMyResolvedOrderGroups$.close(); + await allMyOrderGroups$.close(); await paymentEvents$.close(); await latestHeartbeats$.close(); await giftwraps$.close(); @@ -520,7 +518,10 @@ class UserSubscriptions { void _emitTransitionFilter() => _logger.spanSync('_emitTransitionFilter', () { if (_knownTradeIds.isEmpty) return; - final filter = Filter(dTags: _knownTradeIds.toList()); + final filter = Filter( + kinds: ReservationTransition.kinds, + dTags: _knownTradeIds.toList(), + ); _logger.d('emitting transition filter #d=$_knownTradeIds'); _transitionFilterSource?.add(filter); }); diff --git a/hostr_sdk/pubspec.lock b/hostr_sdk/pubspec.lock index 6bbc0b96..b699471f 100644 --- a/hostr_sdk/pubspec.lock +++ b/hostr_sdk/pubspec.lock @@ -692,8 +692,8 @@ packages: dependency: "direct main" description: path: "packages/ndk" - ref: "codex/hostr-ndk-fixes-upstream-master" - resolved-ref: "85f5ca2d3791b56149caaac09a0877b658f56d5a" + ref: "feat/ndk-marketplace" + resolved-ref: "3e3bf19ae4535d726059ab78e366c82414802d98" url: "https://github.com/sudonym-btc/ndk.git" source: git version: "0.8.2-dev.8" diff --git a/hostr_sdk/pubspec.yaml b/hostr_sdk/pubspec.yaml index 8b14de4a..668272a3 100644 --- a/hostr_sdk/pubspec.yaml +++ b/hostr_sdk/pubspec.yaml @@ -68,7 +68,7 @@ dependency_overrides: ndk: git: url: https://github.com/sudonym-btc/ndk.git - ref: codex/hostr-ndk-fixes-upstream-master + ref: feat/ndk-marketplace path: packages/ndk freezed_annotation: ^3.1.0 web3dart_builders: diff --git a/hostr_sdk/test/integration/usecase/reservation/validation/reservation_groups_test.dart b/hostr_sdk/test/integration/usecase/order/validation/order_groups_test.dart similarity index 95% rename from hostr_sdk/test/integration/usecase/reservation/validation/reservation_groups_test.dart rename to hostr_sdk/test/integration/usecase/order/validation/order_groups_test.dart index 0bd2567f..d62b1531 100644 --- a/hostr_sdk/test/integration/usecase/reservation/validation/reservation_groups_test.dart +++ b/hostr_sdk/test/integration/usecase/order/validation/order_groups_test.dart @@ -1,4 +1,4 @@ -/// Integration tests for [ReservationGroups] verification against a real +/// Integration tests for [OrderGroupVerification] verification against a real /// Anvil (Foundry) chain and Nostr relay. /// /// These tests exercise: @@ -14,7 +14,7 @@ /// - Anvil running on https://arbitrum.hostr.development (chain-id 412346) /// - Nostr relay at wss://relay.hostr.development /// - MultiEscrow contract deployed in escrow/contracts/contract-addresses.json -/// Run: `cd hostr_sdk && dart test test/integration/reservation_groups_test.dart` +/// Run: `cd hostr_sdk && dart test test/integration/order_groups_test.dart` @Tags(['integration', 'docker']) library; @@ -343,7 +343,7 @@ void main() { setUpAll(() async { harness = await IntegrationTestHarness.create( - name: 'hostr_reservation_groups_it', + name: 'hostr_order_groups_it', logLevel: Level.all, ); }); @@ -365,7 +365,7 @@ void main() { final nego = _buildNegotiate(listing: listing, buyer: buyer); final pair = ReservationGroup(reservations: [nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -379,7 +379,7 @@ void main() { final pair = ReservationGroup(reservations: [ack, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -396,7 +396,7 @@ void main() { final pair = ReservationGroup(reservations: [ack]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -410,7 +410,7 @@ void main() { final pair = ReservationGroup(reservations: [cancelled]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.buyerCancelled, isTrue); }); @@ -430,7 +430,7 @@ void main() { final pair = ReservationGroup(reservations: [cancelled, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.sellerCancelled, isTrue); }); @@ -452,7 +452,7 @@ void main() { reservations: [sellerCancelled, buyerCancelled], ); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.sellerCancelled, isTrue); expect((result as Valid).event.buyerCancelled, isTrue); @@ -474,7 +474,7 @@ void main() { final pair = ReservationGroup(reservations: [ack, cancelledBuyer]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.buyerCancelled, isTrue); }); @@ -495,7 +495,7 @@ void main() { final pair = ReservationGroup(reservations: [cancelledSeller, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.sellerCancelled, isTrue); }); @@ -503,7 +503,7 @@ void main() { test('empty pair (both null) → Invalid', () { final pair = ReservationGroup(); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('No reservation found')); }); @@ -673,7 +673,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -818,7 +818,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -845,7 +845,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -868,7 +868,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('Amount insufficient')); }); @@ -905,7 +905,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('recipient does not match')); }); @@ -936,7 +936,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('profile does not match')); }); @@ -964,7 +964,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('LNURL does not match')); }); @@ -987,7 +987,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect( (result as Invalid).reason, @@ -1030,7 +1030,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -1045,7 +1045,7 @@ void main() { // No proof attached — should definitely be invalid final pair = ReservationGroup(reservations: [nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -1087,7 +1087,7 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); // Documenting current behavior: proof validation passes regardless // of allowSelfSignedReservation flag. expect(result, isA>()); @@ -1111,7 +1111,7 @@ void main() { // No seller ack, no proof final pair = ReservationGroup(reservations: [nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -1134,7 +1134,7 @@ void main() { final pair = ReservationGroup(reservations: [ack, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -1173,15 +1173,15 @@ void main() { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); }); - // ─── Group 7: toReservationGroups grouping → verifyGroup pipeline ─────── + // ─── Group 7: toOrderGroups grouping → verifyGroup pipeline ─────── - group('toReservationGroups + verifyGroup pipeline', () { + group('toOrderGroups + verifyGroup pipeline', () { late Listing listing; late Nip01Event hosterProfile; @@ -1225,12 +1225,12 @@ void main() { salt: 'pair-3', ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, nego2, cancelled2, nego3], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final validCount = results.whereType>().length; @@ -1286,12 +1286,12 @@ void main() { salt: 'mixed-3', ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, commit2, nego3], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final validCount = results.whereType>().length; @@ -1339,7 +1339,7 @@ void main() { signer: host, ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [ nego1, ack1, @@ -1351,7 +1351,7 @@ void main() { ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final activeCount = results diff --git a/hostr_sdk/test/integration/usecase/reservations/payment_proof_orchestrator_escrow_fund_test.dart b/hostr_sdk/test/integration/usecase/reservations/payment_proof_orchestrator_escrow_fund_test.dart index 441d2689..317c022e 100644 --- a/hostr_sdk/test/integration/usecase/reservations/payment_proof_orchestrator_escrow_fund_test.dart +++ b/hostr_sdk/test/integration/usecase/reservations/payment_proof_orchestrator_escrow_fund_test.dart @@ -184,7 +184,7 @@ Future _runSignedInPaymentProofCase({ final proofCompleter = Completer(); final proofPublishCompleter = Completer(); - final updatesSub = hostr.reservations.updates.listen((reservation) { + final updatesSub = hostr.orderWorkflows.updates.listen((reservation) { if (_isBuyerEscrowProofReservation( reservation: reservation, tradeId: prepared.tradeId, @@ -831,7 +831,7 @@ Future _expectProofReadableFromRelay({ final deadline = DateTime.now().add(const Duration(seconds: 45)); var lastSeen = const []; while (DateTime.now().isBefore(deadline)) { - lastSeen = await hostr.reservations.getByTradeId(tradeId); + lastSeen = await hostr.orderWorkflows.getByTradeId(tradeId); if (lastSeen.any( (reservation) => _isBuyerEscrowProofReservation( @@ -922,7 +922,7 @@ Future _resetSession(Hostr hostr) async { await hostr.userSubscriptions.reset(); await hostr.messaging.threads.reset(); await hostr.nwc.reset(); - await hostr.reservations.reset(); + await hostr.orderWorkflows.reset(); await hostr.auth.logout(); await hostr.ndk.relays.closeAllTransports(); } diff --git a/hostr_sdk/test/support/fakes.dart b/hostr_sdk/test/support/fakes.dart index c682bb31..f459ac83 100644 --- a/hostr_sdk/test/support/fakes.dart +++ b/hostr_sdk/test/support/fakes.dart @@ -11,7 +11,6 @@ import 'package:hostr_sdk/usecase/messaging/thread.dart'; import 'package:hostr_sdk/usecase/messaging/threads.dart'; import 'package:hostr_sdk/usecase/relays/relays.dart'; import 'package:hostr_sdk/usecase/requests/requests.dart' as hostr_requests; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart'; import 'package:hostr_sdk/util/main.dart'; import 'package:mockito/mockito.dart'; import 'package:ndk/ndk.dart' show Filter, Ndk, Nip01Event; @@ -27,9 +26,6 @@ class FakeMessaging extends Fake implements Messaging { /// No-op fake for [Auth]. class FakeAuth extends Fake implements Auth {} -/// No-op fake for [ReservationTransitions]. -class FakeTransitions extends Fake implements ReservationTransitions {} - /// In-memory fake relay source for reservation / event subscriptions. /// /// Supports `subscribe` returning a manually-controlled [StreamWithStatus], diff --git a/hostr_sdk/test/unit/seed/reservation_participant_proofs_test.dart b/hostr_sdk/test/unit/seed/reservation_participant_proofs_test.dart index 794f5234..f0c648d4 100644 --- a/hostr_sdk/test/unit/seed/reservation_participant_proofs_test.dart +++ b/hostr_sdk/test/unit/seed/reservation_participant_proofs_test.dart @@ -3,7 +3,7 @@ library; import 'package:hostr_sdk/seed/seed.dart'; import 'package:hostr_sdk/usecase/messaging/threads.dart'; -import 'package:hostr_sdk/usecase/reservation_groups/reservation_group_participant_resolver.dart'; +import 'package:hostr_sdk/usecase/order_groups/order_group_participant_resolver.dart'; import 'package:hostr_sdk/usecase/reservations/reservation_participant_keyring.dart'; import 'package:hostr_sdk/usecase/reservations/reservations.dart'; import 'package:models/main.dart'; @@ -86,7 +86,7 @@ void main() { request.pubKey, ); - final groups = Reservations.toReservationGroups( + final groups = Reservations.toOrderGroups( reservations: [request, hostCommit], ); expect(groups, hasLength(1)); diff --git a/hostr_sdk/test/unit/usecase/background_worker/background_worker_test.dart b/hostr_sdk/test/unit/usecase/background_worker/background_worker_test.dart index 8b0cc785..5dfcdb20 100644 --- a/hostr_sdk/test/unit/usecase/background_worker/background_worker_test.dart +++ b/hostr_sdk/test/unit/usecase/background_worker/background_worker_test.dart @@ -12,7 +12,7 @@ import 'package:hostr_sdk/usecase/evm/operations/operation_state_store.dart'; import 'package:hostr_sdk/usecase/heartbeat/heartbeat.dart'; import 'package:hostr_sdk/usecase/listings/listings.dart'; import 'package:hostr_sdk/usecase/metadata/metadata.dart'; -import 'package:hostr_sdk/usecase/reservation_groups/reservation_group_participant_resolver.dart'; +import 'package:hostr_sdk/usecase/order_groups/order_group_participant_resolver.dart'; import 'package:hostr_sdk/usecase/user_subscriptions/user_subscriptions.dart'; import 'package:hostr_sdk/util/main.dart'; import 'package:mockito/mockito.dart'; @@ -95,7 +95,7 @@ class _FakeUserSubscriptions extends Fake implements UserSubscriptions { } @override - Future start({bool validateReservationGroups = true}) async { + Future start({bool validateOrderGroups = true}) async { startCount++; } } diff --git a/hostr_sdk/test/unit/usecase/reservation_groups/reservation_group_participant_resolver_test.dart b/hostr_sdk/test/unit/usecase/order_groups/order_group_participant_resolver_test.dart similarity index 99% rename from hostr_sdk/test/unit/usecase/reservation_groups/reservation_group_participant_resolver_test.dart rename to hostr_sdk/test/unit/usecase/order_groups/order_group_participant_resolver_test.dart index 426041b3..5a9bb159 100644 --- a/hostr_sdk/test/unit/usecase/reservation_groups/reservation_group_participant_resolver_test.dart +++ b/hostr_sdk/test/unit/usecase/order_groups/order_group_participant_resolver_test.dart @@ -2,7 +2,7 @@ library; import 'package:hostr_sdk/usecase/messaging/threads.dart'; -import 'package:hostr_sdk/usecase/reservation_groups/reservation_group_participant_resolver.dart'; +import 'package:hostr_sdk/usecase/order_groups/order_group_participant_resolver.dart'; import 'package:hostr_sdk/usecase/reservations/reservation_participant_keyring.dart'; import 'package:hostr_sdk/usecase/reservations/reservation_participant_tags.dart'; import 'package:hostr_sdk/util/main.dart'; diff --git a/hostr_sdk/test/unit/usecase/reservations/cancel_confirm_test.dart b/hostr_sdk/test/unit/usecase/reservations/cancel_confirm_test.dart index bfe5b408..31dd5924 100644 --- a/hostr_sdk/test/unit/usecase/reservations/cancel_confirm_test.dart +++ b/hostr_sdk/test/unit/usecase/reservations/cancel_confirm_test.dart @@ -14,10 +14,11 @@ @Tags(['unit']) library; +import 'dart:async'; + import 'package:hostr_sdk/seed/seed.dart'; import 'package:hostr_sdk/usecase/auth/auth.dart'; import 'package:hostr_sdk/usecase/requests/requests.dart'; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart'; import 'package:hostr_sdk/usecase/reservations/reservations.dart'; import 'package:hostr_sdk/util/main.dart'; import 'package:mockito/mockito.dart'; @@ -25,7 +26,22 @@ import 'package:models/main.dart'; import 'package:models/stubs/main.dart'; import 'package:ndk/entities.dart' show RelayBroadcastResponse; import 'package:ndk/ndk.dart' - show Accounts, Filter, Ndk, Nip01Event, Nip01Utils; + show + Accounts, + Bip340EventSigner, + EventSigner, + Filter, + Marketplace, + MarketplaceOrder, + MarketplaceOrderStage, + MarketplaceOrderTransition, + MarketplaceOrderTransitionContent, + MarketplaceOrderTransitionPublishResult, + MarketplaceOrderTransitionType, + MarketplaceOrderTransitionsUsecase, + Ndk, + NdkBroadcastResponse, + Nip01Event; import 'package:ndk/shared/nips/nip01/key_pair.dart'; import 'package:test/test.dart'; @@ -37,7 +53,10 @@ final _f = EntityFactory(); class _FakeRequests extends Fake implements Requests { final List broadcastedEvents = []; - final Ndk _ndk = _FakeNdk(); + final _FakeNdk _ndk = _FakeNdk(); + + _RecordingMarketplaceTransitions get recordedTransitions => + _ndk.recordedTransitions; @override Ndk get ndk => _ndk; @@ -111,9 +130,26 @@ class _FakeAccounts extends Fake implements Accounts { class _FakeNdk extends Fake implements Ndk { final Accounts _accounts = _FakeAccounts(); + final _FakeMarketplace _marketplace = _FakeMarketplace(); + + _RecordingMarketplaceTransitions get recordedTransitions => + _marketplace.recordedTransitions; @override Accounts get accounts => _accounts; + + @override + Marketplace get marketplace => _marketplace; +} + +class _FakeMarketplace extends Fake implements Marketplace { + final _RecordingMarketplaceTransitions _orderTransitions = + _RecordingMarketplaceTransitions(); + + _RecordingMarketplaceTransitions get recordedTransitions => _orderTransitions; + + @override + MarketplaceOrderTransitionsUsecase get orderTransitions => _orderTransitions; } // ─── Fake Auth ─────────────────────────────────────────────────────────────── @@ -126,59 +162,70 @@ class _FakeAuth extends Fake implements Auth { KeyPair getActiveKey() => _key; } -// ─── Fake Transitions ──────────────────────────────────────────────────────── +// ─── Fake NDK Marketplace Transitions ──────────────────────────────────────── -class _RecordingTransitions extends Fake implements ReservationTransitions { +class _RecordingMarketplaceTransitions extends Fake + implements MarketplaceOrderTransitionsUsecase { final List< ({ - ReservationTransitionType type, - ReservationStage from, - ReservationStage to, + MarketplaceOrderTransitionType type, + MarketplaceOrderStage from, + MarketplaceOrderStage to, String? commitTermsHash, String? reason, - KeyPair? signerKeyPair, + String signerPubkey, }) > recorded = []; @override - Future record({ - required Reservation reservation, - required ReservationTransitionType transitionType, - required ReservationStage fromStage, - required ReservationStage toStage, - KeyPair? signerKeyPair, + Future record({ + required MarketplaceOrder order, + required MarketplaceOrderTransitionType transitionType, + required MarketplaceOrderStage fromStage, + required MarketplaceOrderStage toStage, + EventSigner? customSigner, + Iterable? specificRelays, String? commitTermsHash, String? reason, Map? updatedFields, String? prevTransitionId, }) async { + final signer = + customSigner ?? + Bip340EventSigner( + privateKey: MockKeys.hoster.privateKey!, + publicKey: MockKeys.hoster.publicKey, + ); recorded.add(( type: transitionType, from: fromStage, to: toStage, commitTermsHash: commitTermsHash, reason: reason, - signerKeyPair: signerKeyPair, + signerPubkey: signer.getPublicKey(), )); - final unsigned = Nip01Event( - kind: kNostrKindReservationTransition, - pubKey: reservation.pubKey, - tags: [ - ['d', reservation.getDtag() ?? ''], - ], - content: ReservationTransitionContent( + final unsigned = MarketplaceOrderTransition.create( + pubKey: signer.getPublicKey(), + order: order, + prevTransitionId: prevTransitionId, + content: MarketplaceOrderTransitionContent( transitionType: transitionType, fromStage: fromStage, toStage: toStage, commitTermsHash: commitTermsHash, reason: reason, - ).toString(), + updatedFields: updatedFields, + ), ); - return ReservationTransition.fromNostrEvent( - Nip01Utils.signWithPrivateKey( - event: unsigned, - privateKey: MockKeys.hoster.privateKey!, + final signed = MarketplaceOrderTransition.fromEvent( + await signer.sign(unsigned), + ); + return MarketplaceOrderTransitionPublishResult( + transition: signed, + broadcast: NdkBroadcastResponse( + publishEvent: signed, + broadcastDoneStream: Stream.value([_successfulBroadcastResponse()]), ), ); } @@ -289,18 +336,17 @@ ReservationGroup _buildNegotiateGroup({required String tradeId}) { void main() { late _FakeRequests requests; - late _RecordingTransitions transitions; + late _RecordingMarketplaceTransitions transitions; late Reservations reservations; setUp(() { requests = _FakeRequests(); - transitions = _RecordingTransitions(); + transitions = requests.recordedTransitions; reservations = Reservations( requests: requests as dynamic, logger: CustomLogger(), messaging: FakeMessaging(), auth: _FakeAuth(MockKeys.hoster), - transitions: transitions, listings: FakeListings(), relays: FakeRelays(), ); @@ -373,8 +419,8 @@ void main() { expect(transitions.recorded, hasLength(1)); final t = transitions.recorded.first; - expect(t.type, ReservationTransitionType.cancel); - expect(t.to, ReservationStage.cancel); + expect(t.type, MarketplaceOrderTransitionType.cancel); + expect(t.to, MarketplaceOrderStage.cancel); }, ); @@ -386,7 +432,10 @@ void main() { await reservations.cancel(group, MockKeys.hoster); expect(transitions.recorded, hasLength(1)); - expect(transitions.recorded.first.signerKeyPair, MockKeys.hoster); + expect( + transitions.recorded.first.signerPubkey, + MockKeys.hoster.publicKey, + ); }, ); @@ -397,9 +446,9 @@ void main() { expect(transitions.recorded, hasLength(1)); final t = transitions.recorded.first; - expect(t.type, ReservationTransitionType.cancel); - expect(t.from, ReservationStage.negotiate); - expect(t.to, ReservationStage.cancel); + expect(t.type, MarketplaceOrderTransitionType.cancel); + expect(t.from, MarketplaceOrderStage.negotiate); + expect(t.to, MarketplaceOrderStage.cancel); }); test('throws if group is already cancelled', () async { @@ -515,9 +564,9 @@ void main() { expect(transitions.recorded, hasLength(1)); final t = transitions.recorded.first; - expect(t.type, ReservationTransitionType.confirm); - expect(t.from, ReservationStage.commit); - expect(t.to, ReservationStage.commit); + expect(t.type, MarketplaceOrderTransitionType.confirm); + expect(t.from, MarketplaceOrderStage.commit); + expect(t.to, MarketplaceOrderStage.commit); }, ); diff --git a/hostr_sdk/test/unit/usecase/reservations/listing_availability_test.dart b/hostr_sdk/test/unit/usecase/reservations/listing_availability_test.dart index c56d444a..83db84b1 100644 --- a/hostr_sdk/test/unit/usecase/reservations/listing_availability_test.dart +++ b/hostr_sdk/test/unit/usecase/reservations/listing_availability_test.dart @@ -70,7 +70,6 @@ void main() { logger: CustomLogger(), messaging: FakeMessaging(), auth: FakeAuth(), - transitions: FakeTransitions(), listings: Listings( requests: relay, logger: CustomLogger(), diff --git a/hostr_sdk/test/unit/usecase/reservations/reservation_groups_test.dart b/hostr_sdk/test/unit/usecase/reservations/order_groups_test.dart similarity index 93% rename from hostr_sdk/test/unit/usecase/reservations/reservation_groups_test.dart rename to hostr_sdk/test/unit/usecase/reservations/order_groups_test.dart index 1700671a..52c0d2cf 100644 --- a/hostr_sdk/test/unit/usecase/reservations/reservation_groups_test.dart +++ b/hostr_sdk/test/unit/usecase/reservations/order_groups_test.dart @@ -1,6 +1,6 @@ -/// Tests for the [ReservationGroups] usecase — specifically the static -/// [ReservationGroups.verifyGroup] function and the -/// [Reservations.toReservationGroups] grouping. +/// Tests for the [OrderGroupVerification] usecase — specifically the static +/// [OrderGroupVerification.verifyGroup] function and the +/// [Reservations.toOrderGroups] grouping. /// /// Covers: /// - Seller-confirmed pair → Valid @@ -20,7 +20,7 @@ import 'dart:convert'; import 'package:hostr_sdk/usecase/escrow/escrow_verification.dart'; import 'package:hostr_sdk/seed/seed.dart'; import 'package:hostr_sdk/usecase/evm/evm.dart'; -import 'package:hostr_sdk/usecase/reservation_groups/reservation_groups.dart'; +import 'package:hostr_sdk/usecase/order_groups/order_group_verification.dart'; import 'package:hostr_sdk/usecase/reservations/reservations.dart'; import 'package:hostr_sdk/util/main.dart'; import 'package:mockito/mockito.dart'; @@ -400,7 +400,7 @@ Future _buildEscrowCommit({ void main() async { final listing = _listing(); - group('toReservationGroups', () { + group('toOrderGroups', () { test('groups buyer and seller by trade id (d-tag)', () async { final buyer = MockKeys.guest; final nego = await _negotiate(listing: listing, buyer: buyer); @@ -410,7 +410,7 @@ void main() async { seller: MockKeys.hoster, ); - final pairs = Reservations.toReservationGroups(reservations: [nego, ack]); + final pairs = Reservations.toOrderGroups(reservations: [nego, ack]); expect(pairs.length, 1); final pair = pairs.values.first; @@ -440,7 +440,7 @@ void main() async { seller: MockKeys.hoster, ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, nego2, ack1], ); @@ -451,7 +451,7 @@ void main() async { final buyer = MockKeys.guest; final nego = await _negotiate(listing: listing, buyer: buyer); - final pairs = Reservations.toReservationGroups(reservations: [nego]); + final pairs = Reservations.toOrderGroups(reservations: [nego]); expect(pairs.length, 1); final pair = pairs.values.first; @@ -460,7 +460,7 @@ void main() async { }); test('empty list produces empty map', () { - final pairs = Reservations.toReservationGroups(reservations: []); + final pairs = Reservations.toOrderGroups(reservations: []); expect(pairs, isEmpty); }); @@ -478,7 +478,7 @@ void main() async { final pair = ReservationGroup(reservations: [ack, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -494,7 +494,7 @@ void main() async { final pair = ReservationGroup(reservations: [ack]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -520,7 +520,7 @@ void main() async { final pair = ReservationGroup(reservations: [nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -540,7 +540,7 @@ void main() async { final pair = ReservationGroup(reservations: [cancelled, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.sellerCancelled, isTrue); }); @@ -556,7 +556,7 @@ void main() async { final pair = ReservationGroup(reservations: [cancelled]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.buyerCancelled, isTrue); }); @@ -579,7 +579,7 @@ void main() async { reservations: [sellerCancelled, buyerCancelled], ); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Valid).event.sellerCancelled, isTrue); expect((result as Valid).event.buyerCancelled, isTrue); @@ -588,7 +588,7 @@ void main() async { test('empty pair (both null) → Invalid', () { final pair = ReservationGroup(); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('No reservation found')); }); @@ -621,12 +621,12 @@ void main() async { signer: buyer2, ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, nego2, cancelled2], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final valid = results.whereType>().length; @@ -671,12 +671,12 @@ void main() async { signer: buyer2, ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, cancelled2], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .whereType>(); // All verified pairs are Valid; callers filter out cancelled ones. @@ -699,11 +699,11 @@ void main() async { final pair = ReservationGroup(reservations: [ack, nego]); // Default: seller confirmation makes it valid. - final defaultResult = ReservationGroups.verifyGroup(pair); + final defaultResult = OrderGroupVerification.verifyGroup(pair); expect(defaultResult, isA>()); // Forced: buyer negotiate has no proof → Invalid. - final forcedResult = ReservationGroups.verifyGroup( + final forcedResult = OrderGroupVerification.verifyGroup( pair, forceValidateSelfSigned: true, ); @@ -723,7 +723,7 @@ void main() async { final pair = ReservationGroup(reservations: [ack]); - final result = ReservationGroups.verifyGroup( + final result = OrderGroupVerification.verifyGroup( pair, forceValidateSelfSigned: true, ); @@ -742,7 +742,7 @@ void main() async { final pair = ReservationGroup(reservations: [ack, nego]); - final result = ReservationGroups.verifyGroup( + final result = OrderGroupVerification.verifyGroup( pair, forceValidateSelfSigned: false, ); @@ -760,7 +760,7 @@ void main() async { final pair = ReservationGroup(reservations: [cancelled]); - final result = ReservationGroups.verifyGroup( + final result = OrderGroupVerification.verifyGroup( pair, forceValidateSelfSigned: true, ); @@ -771,7 +771,7 @@ void main() async { test('forceValidateSelfSigned=true: empty pair (both null) → Invalid', () { final pair = ReservationGroup(); - final result = ReservationGroups.verifyGroup( + final result = OrderGroupVerification.verifyGroup( pair, forceValidateSelfSigned: true, ); @@ -820,7 +820,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -848,7 +848,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); @@ -871,7 +871,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('Amount insufficient')); }); @@ -906,7 +906,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('recipient does not match')); }); @@ -936,7 +936,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('profile does not match')); }); @@ -964,7 +964,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect((result as Invalid).reason, contains('LNURL does not match')); }); @@ -987,7 +987,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); expect( (result as Invalid).reason, @@ -1016,7 +1016,7 @@ void main() async { proof: _buildEscrowPaymentProof(listing: listing), ); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [commit]), forceValidateSelfSigned: true, escrowVerification: _StubEscrowVerification( @@ -1056,7 +1056,7 @@ void main() async { signer: MockKeys.guest, ); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [cancel]), forceValidateSelfSigned: true, escrowVerification: _StubEscrowVerification( @@ -1094,7 +1094,7 @@ void main() async { listing: listing, ); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [buyerCommit, escrowCommit]), forceValidateSelfSigned: true, ); @@ -1131,7 +1131,7 @@ void main() async { ); final verifier = _StubEscrowVerification(); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [buyerCommit, escrowCommit]), escrowVerification: verifier, ); @@ -1158,7 +1158,7 @@ void main() async { seller: MockKeys.hoster, ); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [sellerAck, negotiate]), ); @@ -1180,7 +1180,7 @@ void main() async { salt: 'confirmed-nego-only', ); - final result = await ReservationGroups.verifyGroupOnChain( + final result = await OrderGroupVerification.verifyGroupOnChain( ReservationGroup(reservations: [negotiate]), forceValidateSelfSigned: false, ); @@ -1228,7 +1228,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -1243,7 +1243,7 @@ void main() async { final nego = await _buildNegotiate(listing: listing, buyer: buyer); final pair = ReservationGroup(reservations: [nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -1283,7 +1283,7 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }); }); @@ -1312,7 +1312,7 @@ void main() async { final pair = ReservationGroup(reservations: [ack, nego]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); @@ -1352,15 +1352,15 @@ void main() async { ); final pair = ReservationGroup(reservations: [commit]); - final result = ReservationGroups.verifyGroup(pair); + final result = OrderGroupVerification.verifyGroup(pair); expect(result, isA>()); }, ); }); - // ─── Group 7: Pipeline (toReservationGroups → verifyGroup) ─────────────── + // ─── Group 7: Pipeline (toOrderGroups → verifyGroup) ─────────────── - group('toReservationGroups + verifyGroup pipeline (with proofs)', () { + group('toOrderGroups + verifyGroup pipeline (with proofs)', () { final host = MockKeys.hoster; final buyer = MockKeys.guest; final buyer2 = MockKeys.reviewer; @@ -1405,12 +1405,12 @@ void main() async { salt: 'pair-3', ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, nego2, cancelled2, nego3], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final validCount = results.whereType>().length; @@ -1465,12 +1465,12 @@ void main() async { salt: 'mixed-3', ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [nego1, ack1, commit2, nego3], ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final validCount = results.whereType>().length; @@ -1518,7 +1518,7 @@ void main() async { signer: host, ); - final pairs = Reservations.toReservationGroups( + final pairs = Reservations.toOrderGroups( reservations: [ nego1, ack1, @@ -1530,7 +1530,7 @@ void main() async { ); final results = pairs.values - .map((pair) => ReservationGroups.verifyGroup(pair)) + .map((pair) => OrderGroupVerification.verifyGroup(pair)) .toList(); final activeCount = results @@ -1594,15 +1594,15 @@ void main() async { ); final group = ReservationGroup.fromReservation(negotiate); - expect(ReservationGroups.verifyGroup(group), isA()); + expect(OrderGroupVerification.verifyGroup(group), isA()); final source = StreamWithStatus(); - final reservationGroups = ReservationGroups( + final orderGroups = OrderGroupVerification( reservations: _FakeReservations(), logger: CustomLogger(), evm: _FakeEvm(), ); - final validationStream = reservationGroups.verifyFromSource( + final validationStream = orderGroups.verifyFromSource( source: source, validate: false, ); diff --git a/hostr_sdk/test/unit/usecase/reservations/reservation_transitions_test.dart b/hostr_sdk/test/unit/usecase/reservations/reservation_transitions_test.dart deleted file mode 100644 index 0d2370df..00000000 --- a/hostr_sdk/test/unit/usecase/reservations/reservation_transitions_test.dart +++ /dev/null @@ -1,341 +0,0 @@ -@Tags(['unit']) -library; - -import 'package:hostr_sdk/seed/seed.dart'; -import 'package:hostr_sdk/usecase/requests/requests.dart' as hostr_requests; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart'; -import 'package:hostr_sdk/util/main.dart'; -import 'package:mockito/mockito.dart'; -import 'package:models/main.dart'; -import 'package:models/stubs/main.dart'; -import 'package:ndk/domain_layer/entities/broadcast_state.dart' - show RelayBroadcastResponse; -import 'package:ndk/ndk.dart' - show Accounts, Filter, Ndk, Nip01Event, Nip01Utils; -import 'package:ndk/shared/nips/nip01/key_pair.dart'; -import 'package:test/test.dart'; - -// ── Fakes ────────────────────────────────────────────────────────────── - -class _FakeAccounts extends Fake implements Accounts { - int signCalls = 0; - - @override - String? getPublicKey() => MockKeys.guest.publicKey; - - @override - Future sign(Nip01Event event) async { - signCalls += 1; - return Nip01Utils.signWithPrivateKey( - event: event, - privateKey: MockKeys.guest.privateKey!, - ); - } -} - -class _FakeNdk extends Fake implements Ndk { - final _FakeAccounts fakeAccounts = _FakeAccounts(); - - @override - Accounts get accounts => fakeAccounts; -} - -class _FakeRequests extends Fake implements hostr_requests.Requests { - final hostr_requests.NostrEventSigner? defaultSigner; - final _source = StreamWithStatus(); - final List broadcasted = []; - final List queryResults = []; - final List queries = []; - final List subscriptions = []; - - _FakeRequests({this.defaultSigner}); - - @override - StreamWithStatus subscribe({ - required Filter filter, - List? relays, - String? name, - bool setSinceOnLiveFilter = true, - }) { - subscriptions.add(filter); - return _source as StreamWithStatus; - } - - @override - Stream query({ - required Filter filter, - List? relays, - Duration? timeout, - String? name, - bool cacheRead = true, - bool cacheWrite = true, - }) { - queries.add(filter); - return Stream.fromIterable(queryResults.whereType()); - } - - @override - Future broadcastEvent({ - required Nip01Event event, - List? relays, - hostr_requests.NostrEventSigner? signer, - }) async { - var eventToBroadcast = event.sig == null - ? await ((signer ?? defaultSigner)?.call(event) ?? Future.value(event)) - : event; - if (eventToBroadcast.sig != null && eventToBroadcast.id.isEmpty) { - eventToBroadcast = eventToBroadcast.copyWith( - id: Nip01Utils.calculateId(eventToBroadcast), - ); - } - broadcasted.add(eventToBroadcast); - return hostr_requests.BroadcastResult( - event: eventToBroadcast, - responses: [_successfulBroadcastResponse()], - ); - } - - void emit(ReservationTransition t) => _source.add(t); - void emitStatus(StreamStatus s) => _source.addStatus(s); - Future close() => _source.close(); -} - -RelayBroadcastResponse _successfulBroadcastResponse() { - return RelayBroadcastResponse( - relayUrl: 'wss://relay.test', - okReceived: true, - broadcastSuccessful: true, - ); -} - -// ── Helpers ──────────────────────────────────────────────────────────── - -final _f = EntityFactory(); -final _testListing = EntityFactory().listing( - dTag: 'test-listing', - signer: MockKeys.hoster, -); - -Future _makeReservation({ - String dTag = 'trade-1', - Listing? listing, - KeyPair? signer, -}) => _f.reservation( - listing: listing ?? _testListing, - dTag: dTag, - signerOverride: signer ?? MockKeys.guest, - stage: ReservationStage.negotiate, - start: DateTime(2026, 2, 1), - end: DateTime(2026, 2, 3), - createdAt: DateTime(2026, 1, 1).millisecondsSinceEpoch ~/ 1000, -); - -// ── Tests ────────────────────────────────────────────────────────────── - -void main() { - late _FakeRequests relay; - late _FakeNdk ndk; - late ReservationTransitions usecase; - - setUp(() { - ndk = _FakeNdk(); - relay = _FakeRequests(defaultSigner: ndk.fakeAccounts.sign); - usecase = ReservationTransitions( - requests: relay, - logger: CustomLogger(), - ndk: ndk, - ); - }); - - tearDown(() async { - await relay.close(); - }); - - group('ReservationTransitions', () { - group('record()', () { - test('broadcasts a transition event with correct kind', () async { - final reservation = await _makeReservation(dTag: 'trade-1'); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.commit, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.commit, - commitTermsHash: 'hash-abc', - ); - - expect(result, isA()); - expect(result.kind, kNostrKindReservationTransition); - expect(relay.broadcasted, hasLength(1)); - }); - - test( - 'uses provided local signer without asking ndk accounts to sign', - () async { - final reservation = await _makeReservation( - dTag: 'trade-local-signer', - signer: MockKeys.hoster, - ); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.cancel, - fromStage: ReservationStage.commit, - toStage: ReservationStage.cancel, - signerKeyPair: MockKeys.hoster, - ); - - expect(ndk.fakeAccounts.signCalls, 0); - expect(result.pubKey, MockKeys.hoster.publicKey); - expect(result.valid(), isTrue); - expect(relay.broadcasted, hasLength(1)); - }, - ); - - test('transition content round-trips correctly', () async { - final reservation = await _makeReservation(dTag: 'trade-2'); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.cancel, - fromStage: ReservationStage.commit, - toStage: ReservationStage.cancel, - reason: 'Changed plans', - ); - - expect(result.transitionType, ReservationTransitionType.cancel); - expect(result.fromStage, ReservationStage.commit); - expect(result.toStage, ReservationStage.cancel); - expect(result.reason, 'Changed plans'); - }); - - test('includes d-tag, t-tag, e-tag, listing-ref tags', () async { - final myListing = _f.listing( - dTag: 'my-listing', - signer: MockKeys.hoster, - ); - final reservation = await _makeReservation( - dTag: 'trade-3', - listing: myListing, - ); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.commit, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.commit, - ); - - expect(result.parsedTags.tradeId, 'trade-3'); - expect(result.parsedTags.getTags('d'), contains('trade-3')); - expect(result.parsedTags.getTags('t'), contains('trade-3')); - expect(result.parsedTags.reservationEventId, reservation.id); - expect(result.parsedTags.listingAnchor, myListing.anchor); - }); - - test('falls back to legacy t-tag when d-tag is missing', () { - final transition = ReservationTransition.fromNostrEvent( - Nip01Utils.signWithPrivateKey( - event: Nip01Event( - kind: kNostrKindReservationTransition, - pubKey: MockKeys.guest.publicKey, - tags: const [ - ['t', 'legacy-trade'], - ['e', 'reservation-id'], - ], - content: ReservationTransitionContent( - transitionType: ReservationTransitionType.commit, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.commit, - ).toString(), - ), - privateKey: MockKeys.guest.privateKey!, - ), - ); - - expect(transition.parsedTags.tradeId, 'legacy-trade'); - }); - - test('includes prev tag when prevTransitionId is provided', () async { - final reservation = await _makeReservation(dTag: 'trade-4'); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.counterOffer, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.negotiate, - prevTransitionId: 'prev-event-id', - ); - - expect(result.parsedTags.prevTransitionId, 'prev-event-id'); - }); - - test('omits prev tag when prevTransitionId is null', () async { - final reservation = await _makeReservation(dTag: 'trade-5'); - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.commit, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.commit, - ); - - expect(result.parsedTags.prevTransitionId, isNull); - }); - - test('fills prev tag from existing participant transition', () async { - final reservation = await _makeReservation(dTag: 'trade-5b'); - - final first = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.counterOffer, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.negotiate, - ); - relay.queryResults.add(first); - - final second = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.commit, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.commit, - ); - - expect(second.parsedTags.prevTransitionId, first.id); - }); - - test('includes updatedFields for counter-offers', () async { - final reservation = await _makeReservation(dTag: 'trade-6'); - final updates = {'start': '2026-03-01', 'quantity': 2}; - - final result = await usecase.record( - reservation: reservation, - transitionType: ReservationTransitionType.counterOffer, - fromStage: ReservationStage.negotiate, - toStage: ReservationStage.negotiate, - updatedFields: updates, - ); - - expect(result.updatedFields, updates); - }); - }); - - group('getForReservation()', () { - test('queries with correct filter kind and d-tag', () async { - final result = await usecase.getForReservation('trade-id-abc'); - expect(result, isA>()); - expect(relay.queries.single.kinds, ReservationTransition.kinds); - expect(relay.queries.single.dTags, ['trade-id-abc']); - }); - }); - - group('subscribeForReservation()', () { - test('returns a StreamWithStatus', () { - final stream = usecase.subscribeForReservation('trade-id-xyz'); - expect(stream, isA>()); - expect(relay.subscriptions.single.kinds, ReservationTransition.kinds); - expect(relay.subscriptions.single.dTags, ['trade-id-xyz']); - }); - }); - }); -} diff --git a/hostr_sdk/test/unit/usecase/reservations/trade_identity_preservation_test.dart b/hostr_sdk/test/unit/usecase/reservations/trade_identity_preservation_test.dart index 2e0bbb1b..5e6535c3 100644 --- a/hostr_sdk/test/unit/usecase/reservations/trade_identity_preservation_test.dart +++ b/hostr_sdk/test/unit/usecase/reservations/trade_identity_preservation_test.dart @@ -8,7 +8,6 @@ import 'package:hostr_sdk/usecase/auth/auth.dart'; import 'package:hostr_sdk/usecase/deterministic_keys/deterministic_keys.dart'; import 'package:hostr_sdk/usecase/requests/requests.dart'; import 'package:hostr_sdk/usecase/reservation_requests/reservation_requests.dart'; -import 'package:hostr_sdk/usecase/reservation_transitions/reservation_transitions.dart'; import 'package:hostr_sdk/usecase/reservations/reservations.dart'; import 'package:hostr_sdk/usecase/trade_account_allocator/trade_account_allocator.dart'; import 'package:hostr_sdk/util/main.dart'; @@ -17,7 +16,23 @@ import 'package:models/main.dart'; import 'package:models/stubs/main.dart'; import 'package:ndk/entities.dart' show RelayBroadcastResponse; import 'package:ndk/ndk.dart' - show Accounts, Filter, Ndk, Nip01Event, Nip01Utils; + show + Accounts, + Bip340EventSigner, + EventSigner, + Filter, + Marketplace, + MarketplaceOrder, + MarketplaceOrderStage, + MarketplaceOrderTransition, + MarketplaceOrderTransitionContent, + MarketplaceOrderTransitionPublishResult, + MarketplaceOrderTransitionType, + MarketplaceOrderTransitionsUsecase, + Ndk, + NdkBroadcastResponse, + Nip01Event, + Nip01Utils; import 'package:ndk/shared/nips/nip01/key_pair.dart'; import 'package:test/test.dart'; @@ -33,7 +48,10 @@ class _FakeRequests extends Fake implements Requests { ); final List broadcastedEvents = []; - final Ndk _ndk; + final _FakeNdk _ndk; + + _FakeMarketplaceOrderTransitions get recordedTransitions => + _ndk.recordedTransitions; @override Ndk get ndk => _ndk; @@ -104,12 +122,29 @@ class _FakeNdk extends Fake implements Ndk { final String? activePubkey; final String? signingPrivateKey; + late final _FakeMarketplace _marketplace = _FakeMarketplace(); + + _FakeMarketplaceOrderTransitions get recordedTransitions => + _marketplace.recordedTransitions; @override Accounts get accounts => _FakeAccounts( activePubkey: activePubkey, signingPrivateKey: signingPrivateKey, ); + + @override + Marketplace get marketplace => _marketplace; +} + +class _FakeMarketplace extends Fake implements Marketplace { + final _FakeMarketplaceOrderTransitions _orderTransitions = + _FakeMarketplaceOrderTransitions(); + + _FakeMarketplaceOrderTransitions get recordedTransitions => _orderTransitions; + + @override + MarketplaceOrderTransitionsUsecase get orderTransitions => _orderTransitions; } class _FakeAuth extends Fake implements Auth { @@ -142,43 +177,51 @@ class _FakeTradeAccountAllocator extends Fake implements TradeAccountAllocator { Future reserveNextTradeIndex() async => 7; } -class _FakeReservationTransitions extends Fake - implements ReservationTransitions { +class _FakeMarketplaceOrderTransitions extends Fake + implements MarketplaceOrderTransitionsUsecase { int recordCalls = 0; @override - Future record({ - required Reservation reservation, - required ReservationTransitionType transitionType, - required ReservationStage fromStage, - required ReservationStage toStage, - KeyPair? signerKeyPair, + Future record({ + required MarketplaceOrder order, + required MarketplaceOrderTransitionType transitionType, + required MarketplaceOrderStage fromStage, + required MarketplaceOrderStage toStage, + EventSigner? customSigner, + Iterable? specificRelays, String? commitTermsHash, String? reason, Map? updatedFields, String? prevTransitionId, }) async { recordCalls += 1; - final unsigned = Nip01Event( - kind: kNostrKindReservationTransition, - pubKey: reservation.pubKey, - tags: [ - ['d', reservation.getDtag() ?? ''], - ], - content: ReservationTransitionContent( + final signer = + customSigner ?? + Bip340EventSigner( + privateKey: MockKeys.guest.privateKey!, + publicKey: MockKeys.guest.publicKey, + ); + final unsigned = MarketplaceOrderTransition.create( + pubKey: signer.getPublicKey(), + order: order, + prevTransitionId: prevTransitionId, + content: MarketplaceOrderTransitionContent( transitionType: transitionType, fromStage: fromStage, toStage: toStage, commitTermsHash: commitTermsHash, reason: reason, updatedFields: updatedFields, - ).toString(), + ), ); - - return ReservationTransition.fromNostrEvent( - Nip01Utils.signWithPrivateKey( - event: unsigned, - privateKey: MockKeys.hoster.privateKey!, + final signed = MarketplaceOrderTransition.fromEvent( + await signer.sign(unsigned), + ); + return MarketplaceOrderTransitionPublishResult( + transition: signed, + broadcast: NdkBroadcastResponse( + publishEvent: signed, + broadcastDoneStream: Stream.value([_successfulBroadcastResponse()]), ), ); } @@ -203,13 +246,13 @@ void main() { late _FakeAuth auth; late ReservationRequests reservationRequests; late Reservations reservations; - late _FakeReservationTransitions transitions; + late _FakeMarketplaceOrderTransitions transitions; late _FakeTradeAccountAllocator tradeAccountAllocator; setUp(() { requests = _FakeRequests(); auth = _FakeAuth(MockKeys.guest); - transitions = _FakeReservationTransitions(); + transitions = requests.recordedTransitions; tradeAccountAllocator = _FakeTradeAccountAllocator(); reservationRequests = ReservationRequests( @@ -225,7 +268,6 @@ void main() { logger: CustomLogger(), messaging: FakeMessaging(), auth: auth, - transitions: transitions, listings: FakeListings(), relays: FakeRelays(), ); diff --git a/hostr_sdk/test/unit/usecase/reviews/review_verification_test.dart b/hostr_sdk/test/unit/usecase/reviews/review_verification_test.dart index 09333179..6b68d12e 100644 --- a/hostr_sdk/test/unit/usecase/reviews/review_verification_test.dart +++ b/hostr_sdk/test/unit/usecase/reviews/review_verification_test.dart @@ -377,7 +377,6 @@ void main() { logger: logger, messaging: FakeMessaging(), auth: FakeAuth(), - transitions: FakeTransitions(), listings: listings, relays: FakeRelays(), ); diff --git a/hostr_sdk/test/unit/usecase/startup/startup_profiles_test.dart b/hostr_sdk/test/unit/usecase/startup/startup_profiles_test.dart index bcbe5a46..e3dae9ec 100644 --- a/hostr_sdk/test/unit/usecase/startup/startup_profiles_test.dart +++ b/hostr_sdk/test/unit/usecase/startup/startup_profiles_test.dart @@ -424,7 +424,7 @@ class _FakeUserSubscriptions extends Fake implements UserSubscriptions { ValueStream get isLive => _isLive; @override - Future start({bool validateReservationGroups = true}) async { + Future start({bool validateOrderGroups = true}) async { starts += 1; } } diff --git a/models/lib/nostr/event.dart b/models/lib/nostr/event.dart index 62a1f211..c50225ff 100644 --- a/models/lib/nostr/event.dart +++ b/models/lib/nostr/event.dart @@ -16,8 +16,7 @@ abstract class Event extends Nip01Event { Nip01Event e, { EventTagsParser? tagParser, List> requiredTags = const [], - }) - : tagParser = tagParser ?? ((tags) => EventTags(tags) as TagsType), + }) : tagParser = tagParser ?? ((tags) => EventTags(tags) as TagsType), parsedTags = (tagParser ?? ((tags) => EventTags(tags) as TagsType))( requireRequiredTags(e, requiredTags).tags, ), diff --git a/models/lib/nostr/listing.dart b/models/lib/nostr/listing.dart index 89c95b10..9aac9555 100644 --- a/models/lib/nostr/listing.dart +++ b/models/lib/nostr/listing.dart @@ -462,9 +462,9 @@ class Listing extends Event with ListingTagRead { static bool isAvailable( DateTime start, DateTime end, - List reservationGroups, + List orderGroups, ) { - for (final group in reservationGroups) { + for (final group in orderGroups) { if (group.cancelled) continue; if (group.stage != ReservationStage.commit) continue;