@proposeflow/react
v0.1.2
Published
React utilities for ProposeFlow - server components and hooks for human-in-the-loop AI
Maintainers
Readme
@proposeflow/react
React utilities for ProposeFlow, optimized for React Server Components.
Installation
npm install @proposeflow/react
# or
pnpm add @proposeflow/reactQuick Start
// lib/proposeflow.ts
import { createProposeFlow, z } from '@proposeflow/react/server';
export const pf = createProposeFlow({
schemas: {
recipe: z.object({
title: z.string(),
ingredients: z.array(z.string()),
steps: z.array(z.string()),
}),
task: z.object({
title: z.string(),
dueDate: z.string(),
}),
},
schemaSync: 'hash', // Use content-based versioning
autoRegisterSchemas: true, // Auto-register on first generate()
});// app/recipes/page.tsx (Server Component)
import { pf } from '@/lib/proposeflow';
export default async function RecipesPage() {
const { data: proposals } = await pf.listProposals();
return (
<ul>
{proposals.map((p) => {
if (p.schemaName === 'recipe') {
// p.generatedObject is typed as Recipe
return <li key={p.id}>{p.generatedObject.title}</li>;
}
return null;
})}
</ul>
);
}API Reference
createProposeFlow(config)
Create a typed ProposeFlow server instance with request deduplication.
const pf = createProposeFlow({
apiKey?: string; // Uses PROPOSEFLOW_API_KEY env var if not set
baseUrl?: string; // Uses PROPOSEFLOW_API_URL or localhost:3001
schemas: {
[name: string]: ZodSchema;
};
schemaSync?: 'live' | 'hash'; // Schema resolution mode (default: 'live')
autoRegisterSchemas?: boolean; // Auto-register schemas (default: false)
});Schema Sync Modes
'live'(default): Uses schema pointers to resolve the current "live" version'hash': Uses content-based hashing to lock to a specific schema version
With autoRegisterSchemas: true, schemas are automatically registered on the first
generate() call. This eliminates manual registration and keeps schemas in sync
with your code.
Methods
// Get a proposal (cached per request)
const proposal = await pf.getProposal(id);
// List proposals (cached per request)
const { data, nextCursor } = await pf.listProposals({
status?: 'pending' | 'approved' | 'rejected' | 'regenerating';
schemaId?: string;
limit?: number;
cursor?: string;
});
// Generate a new proposal (not cached)
const { proposal, generation } = await pf.generate('recipe', {
input: 'A quick pasta dish',
metadata: { userId: 'user_123' },
});
// Record a decision
const decision = await pf.decide(proposalId, {
action: 'approve',
edits: { servings: 4 },
});
// Regenerate with feedback
const { proposal } = await pf.regenerate(proposalId, 'Make it vegetarian');
// Register an event
await pf.registerEvent('user.action', {
object: { schema: 'recipe', id: recipeId },
metadata: { action: 'viewed' },
});Features
Request Deduplication
Read operations (getProposal, listProposals) are automatically cached within a single request using React's cache(). Multiple components calling the same method with the same arguments will only make one API call.
Server-Only
The /server export is marked with server-only and will cause a build error if imported in a Client Component. This ensures API keys are never exposed to the browser.
Type Safety
When using Zod schemas, all proposal objects are fully typed:
const { data } = await pf.listProposals();
for (const proposal of data) {
if (proposal.schemaName === 'recipe') {
// TypeScript knows this is a Recipe
console.log(proposal.generatedObject.title);
}
}Exports
// Server utilities (use in Server Components only)
import { createProposeFlow, z } from '@proposeflow/react/server';
// Client utilities (coming soon)
import { ... } from '@proposeflow/react';Development
# Build
pnpm build
# Watch mode
pnpm dev
# Type check
pnpm typecheck