diff --git a/src/actions/publish-spellbook.ts b/src/actions/publish-spellbook.ts index d1464aa..b007873 100644 --- a/src/actions/publish-spellbook.ts +++ b/src/actions/publish-spellbook.ts @@ -4,7 +4,7 @@ import { SpellbookEvent } from "@/types/spell"; import { GrimoireState } from "@/types/app"; import { SpellbookContent } from "@/types/spell"; import accountManager from "@/services/accounts"; -import type { ActionContext } from "applesauce-actions"; +import type { ActionHub } from "applesauce-actions"; import type { NostrEvent } from "nostr-tools/core"; export interface PublishSpellbookOptions { @@ -26,8 +26,9 @@ export interface PublishSpellbookOptions { * 4. Yields the signed event (ActionHub handles publishing) * 5. Marks local spellbook as published if localId provided * + * @param hub - The action hub instance * @param options - Spellbook publishing options - * @returns Action generator for ActionHub + * @yields Signed spellbook event ready for publishing * * @throws Error if title is empty, no active account, or no signer available * @@ -42,73 +43,73 @@ export interface PublishSpellbookOptions { * }); * ``` */ -export function PublishSpellbook(options: PublishSpellbookOptions) { +export async function* PublishSpellbook( + hub: ActionHub, + options: PublishSpellbookOptions +): AsyncGenerator { const { state, title, description, workspaceIds, localId, content } = options; - return async function* ({ - factory, - }: ActionContext): AsyncGenerator { - // 1. Validate inputs - if (!title || !title.trim()) { - throw new Error("Title is required"); - } + // 1. Validate inputs + if (!title || !title.trim()) { + throw new Error("Title is required"); + } - const account = accountManager.active; - if (!account) { - throw new Error("No active account. Please log in first."); - } + const account = accountManager.active; + if (!account) { + throw new Error("No active account. Please log in first."); + } - const signer = account.signer; - if (!signer) { - throw new Error("No signer available. Please connect a signer."); - } + const signer = account.signer; + if (!signer) { + throw new Error("No signer available. Please connect a signer."); + } - // 2. Create event props from state or use provided content - let eventProps; - if (content) { - // Use provided content directly - eventProps = { - kind: 30777, - content: JSON.stringify(content), - tags: [ - ["d", slugify(title)], - ["title", title], - ["client", "grimoire"], - ] as [string, string, ...string[]][], - }; - if (description) { - eventProps.tags.push(["description", description]); - eventProps.tags.push(["alt", `Grimoire Spellbook: ${title}`]); - } else { - eventProps.tags.push(["alt", `Grimoire Spellbook: ${title}`]); - } + // 2. Create event props from state or use provided content + let eventProps; + if (content) { + // Use provided content directly + eventProps = { + kind: 30777, + content: JSON.stringify(content), + tags: [ + ["d", slugify(title)], + ["title", title], + ["client", "grimoire"], + ] as [string, string, ...string[]][], + }; + if (description) { + eventProps.tags.push(["description", description]); + eventProps.tags.push(["alt", `Grimoire Spellbook: ${title}`]); } else { - // Create from state - const encoded = createSpellbook({ - state, - title, - description, - workspaceIds, - }); - eventProps = encoded.eventProps; + eventProps.tags.push(["alt", `Grimoire Spellbook: ${title}`]); } - - // 3. Build draft using factory from context - const draft = await factory.build({ - kind: eventProps.kind, - content: eventProps.content, - tags: eventProps.tags, + } else { + // Create from state + const encoded = createSpellbook({ + state, + title, + description, + workspaceIds, }); + eventProps = encoded.eventProps; + } - // 4. Sign the event - const event = (await factory.sign(draft)) as SpellbookEvent; + // 3. Build draft using hub's factory + const draft = await hub.factory.build({ + kind: eventProps.kind, + content: eventProps.content, + tags: eventProps.tags, + signer, + }); - // 5. Mark as published in local DB (before yielding for better UX) - if (localId) { - await markSpellbookPublished(localId, event); - } + // 4. Sign the event + const event = (await hub.factory.sign(draft, signer)) as SpellbookEvent; - // 6. Yield signed event - ActionHub's publishEvent will handle relay selection and publishing - yield event; - }; + // 5. Mark as published in local DB (before yielding for better UX) + if (localId) { + await markSpellbookPublished(localId, event); + } + + // 6. Yield signed event - ActionHub's publishEvent will handle relay selection and publishing + yield event; } diff --git a/src/services/spellbook-storage.ts b/src/services/spellbook-storage.ts index 7964406..ae444b6 100644 --- a/src/services/spellbook-storage.ts +++ b/src/services/spellbook-storage.ts @@ -47,10 +47,13 @@ export async function saveSpellbook( createdAt = Date.now(); } + // Destructure to exclude id from spread (it would overwrite our computed id with undefined) + const { id: _ignoredId, ...spellbookData } = spellbook; + const localSpellbook: LocalSpellbook = { + ...spellbookData, id, createdAt, - ...spellbook, }; await db.spellbooks.put(localSpellbook);