/** * Test Pattern: Cross-Piece Stream Client * * VERIFIED CLAIMS: * * 1. Cross-Piece Stream Invocation via wish() - WORKS (with corrections to blessed doc) * - Streams from wished pieces appear as Cells wrapping { $stream: true } marker * - Call .send(eventData) on the Cell itself (NOT on an "unwrapped" stream) * - The blessed doc's "auto-unwrap via Stream signature" explanation is WRONG * - Event must be an object (runtime calls preventDefault), can have data props but NO functions * * 2. Forces Piece Execution - VERIFIED * - Just wishing for a piece doesn't make it run * - Use to force execution * * PREREQUISITES DISCOVERED: * - Wish tags must be in JSDoc on Output type (not file-level comments) * - wish({ query: "#tag" }) searches FAVORITES only - piece must be favorited first * * TESTING: * 1. Deploy server piece first, favorite it * 2. Deploy this client piece * 3. Toggle to Mode B ( active) * 4. Click "Invoke Server Stream" - server counter should increment */ import { Default, handler, NAME, pattern, Stream, toCompactDebugString, toIndentedDebugString, UI, wish, Writable, } from "commonfabric"; interface Input { // Toggle between Mode A (wish only) and Mode B (wish + ) useCfRender: boolean | Default; // Track last invocation result lastInvocationStatus: string | Default<"Not invoked yet">; // Track invocation count invocationCount: number | Default<0>; } export interface Output { useCfRender: boolean; lastInvocationStatus: string; invocationCount: number; } // Handler that invokes a stream from the wished piece // KEY FINDING: Despite blessed doc claims, Stream in signature does NOT auto-unwrap. // The stream comes through as a Cell wrapping { $stream: true }. Call .send({}) on the Cell. const invokeServerStream = handler< unknown, { stream: Stream; lastInvocationStatus: Writable; invocationCount: Writable; } >((_event, state) => { try { // Stream arrives as a Cell, not an unwrapped callable stream const streamCell = state.stream as any; const innerValue = streamCell.get ? streamCell.get() : streamCell; if (innerValue && innerValue.$stream) { // Cell contains { $stream: true } marker - call .send() on the Cell itself // Event must be object (runtime calls preventDefault), can have data props, NO functions streamCell.send({}); // Could also be { someData: "value" } const count = state.invocationCount.get() + 1; state.invocationCount.set(count); state.lastInvocationStatus.set( `Success! Server counter should increment (invoked ${count} times)`, ); } else { state.lastInvocationStatus.set( `Stream not found or invalid: ${toCompactDebugString(innerValue)}`, ); } } catch (error) { state.lastInvocationStatus.set(`Failed: ${error}`); } }); // Handler for toggling the render mode const toggleMode = handler }>( (_event, { useCfRender }) => { useCfRender.set(!useCfRender.get()); }, ); export default pattern( ({ useCfRender, lastInvocationStatus, invocationCount }) => { // Wish for the server piece by tag const wishResult = wish<{ counter: number; invocationLog: string[]; incrementCounter: Stream; }>({ query: "#crossPieceTestServer", }); // Access the result from the wish (WishState has a result property) const serverPiece = wishResult.result; // Extract the stream via a plain projection (auto-wraps reactively) const serverStream = serverPiece?.incrementCounter; return { [NAME]: "Cross-Piece Test Client", [UI]: (

Cross-Piece Test Client

{/* Mode Toggle Section */}

Claim 2 Test: {""} Forces Execution

Current Mode: {useCfRender ? "Mode B: Wish + " : "Mode A: Wish Only (no )"}
Toggle Mode

In Mode A, server piece should NOT execute. In Mode B, it should execute.

{/* Server Piece Rendering Section */}

Server Piece Status

{useCfRender ? (

Mode B Active: Rendering server piece with {""}

{/* Use to force execution, even when hidden. */}
) : (

Mode A Active: Server piece wished for but NOT rendered (should not execute)

)}
{/* Stream Invocation Section */}

Claim 1 Test: Stream Invocation

Last Invocation Status: {lastInvocationStatus}
Invoke Server Stream

Click to invoke the incrementCounter stream from the server piece. Check the server piece to see if the counter incremented.

{/* Debug Info */}
Debug Info
              {toIndentedDebugString(
                {
                  useCfRender,
                  invocationCount,
                  lastInvocationStatus,
                  serverPieceExists: serverPiece !== undefined && serverPiece !== null,
                  serverStreamExists: serverStream !== undefined && serverStream !== null,
                },
              )}
              
), useCfRender, lastInvocationStatus, invocationCount, }; }, );