this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Wire ShareDialog to SDK via resolveRecipient + share

+49 -19
+9 -16
apps/web/src/components/cabinet/ShareDialog.tsx
··· 67 67 setStatus("sharing"); 68 68 69 69 // Core handles: fetch document → unwrap key → wrap to recipient → create grant 70 - await getActiveFileManager().share( 71 - documentUri, 72 - recipient.did, 73 - recipient.publicKey, 74 - "read", 75 - null, 76 - ); 70 + await getActiveFileManager().share(documentUri, recipient.did, recipient.publicKey, "read"); 77 71 } catch (resolveError) { 78 72 if (resolveError instanceof RecipientNotReadyError) { 79 73 // REMOVE: pending share needs core domain method (Opake::create_pending_share) ··· 87 81 throw resolveError; 88 82 } 89 83 90 - // Optimistically mark the item as shared in the store 91 - const { items } = useDocumentsStore.getState(); 92 - const item = items[documentUri]; 93 - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: Record lookup 94 - if (item) { 95 - useDocumentsStore.setState((state) => ({ 96 - items: { ...state.items, [documentUri]: { ...item, status: "shared" as const } }, 97 - })); 98 - } 84 + // Optimistically mark the item as shared in the store. `items` is 85 + // an array of FileItems for the current directory — find by URI, 86 + // replace in place. SSE / directory reload will reconcile later. 87 + useDocumentsStore.setState((state) => ({ 88 + items: state.items.map((item) => 89 + item.uri === documentUri ? { ...item, status: "shared" as const } : item, 90 + ), 91 + })); 99 92 100 93 setStatus("done"); 101 94 toastSuccess(`Shared "${documentName}" with ${handle}`);
+40 -3
apps/web/src/lib/sharing.ts
··· 1 - // Stubbed — sharing not yet implemented 1 + // Recipient resolution for the share flow. 2 + // 3 + // Wraps `opake.resolveIdentity` with a distinct error type for the 4 + // "not yet on Opake" case — the UI wants to handle those gracefully 5 + // via a pending-share queue instead of blocking with a raw error. 6 + 7 + import { getOpake } from "@/stores/auth"; 8 + import type { ResolvedIdentity } from "@opake/sdk"; 2 9 10 + /** 11 + * Thrown when a recipient has a valid handle/DID but hasn't published 12 + * an X25519 public key yet (no identity record on their PDS). The 13 + * caller should enqueue a pending share in this case rather than 14 + * failing the whole flow. 15 + */ 3 16 export class RecipientNotReadyError extends Error { 4 17 constructor(message: string) { 5 18 super(message); ··· 7 20 } 8 21 } 9 22 10 - export async function resolveRecipient(_handle: string) { 11 - throw new Error("Sharing not implemented"); 23 + /** 24 + * Resolve a recipient handle or DID to their identity (DID + public key). 25 + * 26 + * @throws RecipientNotReadyError if the recipient has no published identity. 27 + * @throws Error (generic) on network or resolution failure. 28 + */ 29 + export async function resolveRecipient(handle: string): Promise<ResolvedIdentity> { 30 + const identity = await getOpake() 31 + .resolveIdentity(handle) 32 + .catch((err: unknown) => { 33 + const message = err instanceof Error ? err.message : String(err); 34 + // The SDK throws a generic error when the identity record is absent — 35 + // sniff the message to decide whether to raise the "not ready" error. 36 + if (/publicKey|public key|not found|no identity/i.test(message)) { 37 + throw new RecipientNotReadyError(message); 38 + } 39 + throw err; 40 + }); 41 + 42 + if (identity.publicKey.length === 0) { 43 + throw new RecipientNotReadyError( 44 + `${handle} has an account but hasn't published a public key yet.`, 45 + ); 46 + } 47 + 48 + return identity; 12 49 }