Add Nextra API contract (TypeScript + Pydantic)
Defines shared API contract between frontend and backend: - types.ts: TypeScript interfaces for Next.js frontend - models.py: Matching Pydantic models for FastAPI backend Covers: User, Flow, Trigger, Execution, WasmModule, Marketplace, ProjectMemory, and pagination/error types. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a6cd3ce7e8
commit
03516bb9f7
2 changed files with 815 additions and 0 deletions
475
docs/nextra-api-contract/models.py
Normal file
475
docs/nextra-api-contract/models.py
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
"""
|
||||
Nextra API Contract - Pydantic Models
|
||||
|
||||
These models define the API contract between frontend and backend.
|
||||
They match the TypeScript types in types.ts.
|
||||
|
||||
Usage:
|
||||
from nextra.api.models import Flow, CreateFlowRequest
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any, Generic, Literal, TypeVar
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Common Types
|
||||
# =============================================================================
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel, Generic[T]):
|
||||
"""Paginated list response."""
|
||||
|
||||
items: list[T]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int = Field(alias="pageSize")
|
||||
has_more: bool = Field(alias="hasMore")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class ApiError(BaseModel):
|
||||
"""API error response."""
|
||||
|
||||
code: str
|
||||
message: str
|
||||
details: dict[str, Any] | None = None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# User (synced from Clerk)
|
||||
# =============================================================================
|
||||
|
||||
class Tier(str, Enum):
|
||||
FREE = "free"
|
||||
PAID = "paid"
|
||||
PRO = "pro"
|
||||
ENTERPRISE = "enterprise"
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
"""User account (synced from Clerk)."""
|
||||
|
||||
id: UUID
|
||||
clerk_id: str = Field(alias="clerkId")
|
||||
email: str
|
||||
name: str | None = None
|
||||
avatar_url: str | None = Field(default=None, alias="avatarUrl")
|
||||
tier: Tier = Tier.FREE
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Flows
|
||||
# =============================================================================
|
||||
|
||||
class FlowStatus(str, Enum):
|
||||
STOPPED = "stopped"
|
||||
STARTING = "starting"
|
||||
RUNNING = "running"
|
||||
STOPPING = "stopping"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
class CanvasNode(BaseModel):
|
||||
"""A node in the React Flow canvas."""
|
||||
|
||||
id: str
|
||||
type: str
|
||||
position: dict[str, float]
|
||||
data: dict[str, Any]
|
||||
|
||||
|
||||
class CanvasEdge(BaseModel):
|
||||
"""An edge connecting nodes in the canvas."""
|
||||
|
||||
id: str
|
||||
source: str
|
||||
target: str
|
||||
source_handle: str | None = Field(default=None, alias="sourceHandle")
|
||||
target_handle: str | None = Field(default=None, alias="targetHandle")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class CanvasState(BaseModel):
|
||||
"""React Flow canvas state."""
|
||||
|
||||
nodes: list[CanvasNode]
|
||||
edges: list[CanvasEdge]
|
||||
viewport: dict[str, float]
|
||||
|
||||
|
||||
class Flow(BaseModel):
|
||||
"""A user's workflow/flow."""
|
||||
|
||||
id: UUID
|
||||
user_id: UUID = Field(alias="userId")
|
||||
name: str
|
||||
description: str | None = None
|
||||
organism_yaml: str = Field(alias="organismYaml")
|
||||
canvas_state: CanvasState | None = Field(default=None, alias="canvasState")
|
||||
status: FlowStatus = FlowStatus.STOPPED
|
||||
container_id: str | None = Field(default=None, alias="containerId")
|
||||
error_message: str | None = Field(default=None, alias="errorMessage")
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class FlowSummary(BaseModel):
|
||||
"""Abbreviated flow for list views."""
|
||||
|
||||
id: UUID
|
||||
name: str
|
||||
description: str | None = None
|
||||
status: FlowStatus
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class CreateFlowRequest(BaseModel):
|
||||
"""Request to create a new flow."""
|
||||
|
||||
name: str = Field(min_length=1, max_length=100)
|
||||
description: str | None = Field(default=None, max_length=500)
|
||||
organism_yaml: str | None = Field(default=None, alias="organismYaml")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class UpdateFlowRequest(BaseModel):
|
||||
"""Request to update a flow."""
|
||||
|
||||
name: str | None = Field(default=None, min_length=1, max_length=100)
|
||||
description: str | None = Field(default=None, max_length=500)
|
||||
organism_yaml: str | None = Field(default=None, alias="organismYaml")
|
||||
canvas_state: CanvasState | None = Field(default=None, alias="canvasState")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Triggers
|
||||
# =============================================================================
|
||||
|
||||
class TriggerType(str, Enum):
|
||||
WEBHOOK = "webhook"
|
||||
SCHEDULE = "schedule"
|
||||
MANUAL = "manual"
|
||||
|
||||
|
||||
class WebhookTriggerConfig(BaseModel):
|
||||
"""Config for webhook triggers."""
|
||||
|
||||
type: Literal["webhook"] = "webhook"
|
||||
|
||||
|
||||
class ScheduleTriggerConfig(BaseModel):
|
||||
"""Config for scheduled triggers."""
|
||||
|
||||
type: Literal["schedule"] = "schedule"
|
||||
cron: str = Field(description="Cron expression")
|
||||
timezone: str = "UTC"
|
||||
|
||||
|
||||
class ManualTriggerConfig(BaseModel):
|
||||
"""Config for manual triggers."""
|
||||
|
||||
type: Literal["manual"] = "manual"
|
||||
|
||||
|
||||
TriggerConfig = WebhookTriggerConfig | ScheduleTriggerConfig | ManualTriggerConfig
|
||||
|
||||
|
||||
class Trigger(BaseModel):
|
||||
"""A trigger that can start a flow."""
|
||||
|
||||
id: UUID
|
||||
flow_id: UUID = Field(alias="flowId")
|
||||
type: TriggerType
|
||||
name: str
|
||||
config: TriggerConfig
|
||||
webhook_token: str | None = Field(default=None, alias="webhookToken")
|
||||
webhook_url: str | None = Field(default=None, alias="webhookUrl")
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class CreateTriggerRequest(BaseModel):
|
||||
"""Request to create a trigger."""
|
||||
|
||||
type: TriggerType
|
||||
name: str = Field(min_length=1, max_length=100)
|
||||
config: TriggerConfig
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Executions
|
||||
# =============================================================================
|
||||
|
||||
class ExecutionStatus(str, Enum):
|
||||
RUNNING = "running"
|
||||
SUCCESS = "success"
|
||||
ERROR = "error"
|
||||
TIMEOUT = "timeout"
|
||||
|
||||
|
||||
class Execution(BaseModel):
|
||||
"""A single execution/run of a flow."""
|
||||
|
||||
id: UUID
|
||||
flow_id: UUID = Field(alias="flowId")
|
||||
trigger_id: UUID | None = Field(default=None, alias="triggerId")
|
||||
trigger_type: TriggerType = Field(alias="triggerType")
|
||||
status: ExecutionStatus
|
||||
started_at: datetime = Field(alias="startedAt")
|
||||
completed_at: datetime | None = Field(default=None, alias="completedAt")
|
||||
duration_ms: int | None = Field(default=None, alias="durationMs")
|
||||
error_message: str | None = Field(default=None, alias="errorMessage")
|
||||
input_payload: str | None = Field(default=None, alias="inputPayload")
|
||||
output_payload: str | None = Field(default=None, alias="outputPayload")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class ExecutionSummary(BaseModel):
|
||||
"""Abbreviated execution for list views."""
|
||||
|
||||
id: UUID
|
||||
status: ExecutionStatus
|
||||
trigger_type: TriggerType = Field(alias="triggerType")
|
||||
started_at: datetime = Field(alias="startedAt")
|
||||
duration_ms: int | None = Field(default=None, alias="durationMs")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# WASM Modules (Pro+)
|
||||
# =============================================================================
|
||||
|
||||
class WasmModule(BaseModel):
|
||||
"""A custom WASM module."""
|
||||
|
||||
id: UUID
|
||||
user_id: UUID = Field(alias="userId")
|
||||
name: str
|
||||
description: str | None = None
|
||||
wit_interface: str | None = Field(default=None, alias="witInterface")
|
||||
size_bytes: int = Field(alias="sizeBytes")
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class WasmModuleSummary(BaseModel):
|
||||
"""Abbreviated module for list views."""
|
||||
|
||||
id: UUID
|
||||
name: str
|
||||
description: str | None = None
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class CreateWasmModuleRequest(BaseModel):
|
||||
"""Request to create a WASM module (file uploaded separately)."""
|
||||
|
||||
name: str = Field(min_length=1, max_length=100)
|
||||
description: str | None = Field(default=None, max_length=500)
|
||||
wit_interface: str | None = Field(default=None, alias="witInterface")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Marketplace
|
||||
# =============================================================================
|
||||
|
||||
class MarketplaceListingType(str, Enum):
|
||||
TOOL = "tool"
|
||||
FLOW = "flow"
|
||||
|
||||
|
||||
class ToolContent(BaseModel):
|
||||
"""Content for a tool listing."""
|
||||
|
||||
type: Literal["tool"] = "tool"
|
||||
wasm_module_id: UUID = Field(alias="wasmModuleId")
|
||||
wit_interface: str = Field(alias="witInterface")
|
||||
example_usage: str = Field(alias="exampleUsage")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class FlowTemplateContent(BaseModel):
|
||||
"""Content for a flow template listing."""
|
||||
|
||||
type: Literal["flow"] = "flow"
|
||||
organism_yaml: str = Field(alias="organismYaml")
|
||||
canvas_state: CanvasState = Field(alias="canvasState")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
MarketplaceContent = ToolContent | FlowTemplateContent
|
||||
|
||||
|
||||
class MarketplaceListing(BaseModel):
|
||||
"""A marketplace listing (tool or flow template)."""
|
||||
|
||||
id: UUID
|
||||
author_id: UUID = Field(alias="authorId")
|
||||
author_name: str = Field(alias="authorName")
|
||||
type: MarketplaceListingType
|
||||
name: str
|
||||
description: str
|
||||
category: str
|
||||
tags: list[str]
|
||||
downloads: int = 0
|
||||
rating: float | None = None
|
||||
content: MarketplaceContent
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class MarketplaceListingSummary(BaseModel):
|
||||
"""Abbreviated listing for browse views."""
|
||||
|
||||
id: UUID
|
||||
author_name: str = Field(alias="authorName")
|
||||
type: MarketplaceListingType
|
||||
name: str
|
||||
description: str
|
||||
category: str
|
||||
downloads: int
|
||||
rating: float | None = None
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class PublishToMarketplaceRequest(BaseModel):
|
||||
"""Request to publish to marketplace."""
|
||||
|
||||
type: MarketplaceListingType
|
||||
name: str = Field(min_length=1, max_length=100)
|
||||
description: str = Field(min_length=10, max_length=2000)
|
||||
category: str
|
||||
tags: list[str] = Field(default_factory=list, max_length=10)
|
||||
content: MarketplaceContent
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Project Memory (Pro+)
|
||||
# =============================================================================
|
||||
|
||||
class ProjectMemory(BaseModel):
|
||||
"""Project memory status for a flow."""
|
||||
|
||||
flow_id: UUID = Field(alias="flowId")
|
||||
enabled: bool = False
|
||||
used_bytes: int = Field(default=0, alias="usedBytes")
|
||||
max_bytes: int = Field(alias="maxBytes")
|
||||
keys: list[str] = Field(default_factory=list)
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class MemoryEntry(BaseModel):
|
||||
"""A single memory entry."""
|
||||
|
||||
key: str
|
||||
value: str # JSON string
|
||||
size_bytes: int = Field(alias="sizeBytes")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Logs
|
||||
# =============================================================================
|
||||
|
||||
class LogLevel(str, Enum):
|
||||
DEBUG = "debug"
|
||||
INFO = "info"
|
||||
WARNING = "warning"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
class LogEntry(BaseModel):
|
||||
"""A log entry from a running flow."""
|
||||
|
||||
timestamp: datetime
|
||||
level: LogLevel
|
||||
message: str
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Stats
|
||||
# =============================================================================
|
||||
|
||||
class FlowStats(BaseModel):
|
||||
"""Statistics for a single flow."""
|
||||
|
||||
flow_id: UUID = Field(alias="flowId")
|
||||
executions_total: int = Field(alias="executionsTotal")
|
||||
executions_success: int = Field(alias="executionsSuccess")
|
||||
executions_error: int = Field(alias="executionsError")
|
||||
avg_duration_ms: float = Field(alias="avgDurationMs")
|
||||
last_executed_at: datetime | None = Field(default=None, alias="lastExecutedAt")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
class UsageStats(BaseModel):
|
||||
"""Usage statistics for billing/limits."""
|
||||
|
||||
user_id: UUID = Field(alias="userId")
|
||||
period: Literal["day", "month"]
|
||||
flow_count: int = Field(alias="flowCount")
|
||||
execution_count: int = Field(alias="executionCount")
|
||||
execution_limit: int = Field(alias="executionLimit")
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
340
docs/nextra-api-contract/types.ts
Normal file
340
docs/nextra-api-contract/types.ts
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/**
|
||||
* Nextra API Contract - TypeScript Types
|
||||
*
|
||||
* These types define the API contract between frontend and backend.
|
||||
* The FastAPI backend uses matching Pydantic models.
|
||||
*
|
||||
* Usage in frontend:
|
||||
* import type { Flow, CreateFlowRequest } from '@/types/api';
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// Common Types
|
||||
// =============================================================================
|
||||
|
||||
export type UUID = string;
|
||||
export type ISODateTime = string;
|
||||
|
||||
// =============================================================================
|
||||
// User (synced from Clerk)
|
||||
// =============================================================================
|
||||
|
||||
export interface User {
|
||||
id: UUID;
|
||||
clerkId: string;
|
||||
email: string;
|
||||
name: string | null;
|
||||
avatarUrl: string | null;
|
||||
tier: 'free' | 'paid' | 'pro' | 'enterprise';
|
||||
createdAt: ISODateTime;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Flows
|
||||
// =============================================================================
|
||||
|
||||
export type FlowStatus = 'stopped' | 'starting' | 'running' | 'stopping' | 'error';
|
||||
|
||||
export interface Flow {
|
||||
id: UUID;
|
||||
userId: UUID;
|
||||
name: string;
|
||||
description: string | null;
|
||||
organismYaml: string;
|
||||
canvasState: CanvasState | null;
|
||||
status: FlowStatus;
|
||||
containerId: string | null;
|
||||
errorMessage: string | null;
|
||||
createdAt: ISODateTime;
|
||||
updatedAt: ISODateTime;
|
||||
}
|
||||
|
||||
export interface FlowSummary {
|
||||
id: UUID;
|
||||
name: string;
|
||||
description: string | null;
|
||||
status: FlowStatus;
|
||||
updatedAt: ISODateTime;
|
||||
}
|
||||
|
||||
export interface CreateFlowRequest {
|
||||
name: string;
|
||||
description?: string;
|
||||
organismYaml?: string; // Default template if not provided
|
||||
}
|
||||
|
||||
export interface UpdateFlowRequest {
|
||||
name?: string;
|
||||
description?: string;
|
||||
organismYaml?: string;
|
||||
canvasState?: CanvasState;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Canvas State (React Flow)
|
||||
// =============================================================================
|
||||
|
||||
export interface CanvasState {
|
||||
nodes: CanvasNode[];
|
||||
edges: CanvasEdge[];
|
||||
viewport: { x: number; y: number; zoom: number };
|
||||
}
|
||||
|
||||
export interface CanvasNode {
|
||||
id: string;
|
||||
type: NodeType;
|
||||
position: { x: number; y: number };
|
||||
data: NodeData;
|
||||
}
|
||||
|
||||
export type NodeType =
|
||||
| 'trigger'
|
||||
| 'llmCall'
|
||||
| 'httpRequest'
|
||||
| 'codeBlock'
|
||||
| 'conditional'
|
||||
| 'output'
|
||||
| 'custom';
|
||||
|
||||
export interface NodeData {
|
||||
name: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
handler?: string;
|
||||
payloadClass?: string;
|
||||
isAgent?: boolean;
|
||||
config?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface CanvasEdge {
|
||||
id: string;
|
||||
source: string;
|
||||
target: string;
|
||||
sourceHandle?: string;
|
||||
targetHandle?: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Triggers
|
||||
// =============================================================================
|
||||
|
||||
export type TriggerType = 'webhook' | 'schedule' | 'manual';
|
||||
|
||||
export interface Trigger {
|
||||
id: UUID;
|
||||
flowId: UUID;
|
||||
type: TriggerType;
|
||||
name: string;
|
||||
config: TriggerConfig;
|
||||
webhookToken?: string; // Only for webhook triggers
|
||||
webhookUrl?: string; // Full URL for webhook triggers
|
||||
createdAt: ISODateTime;
|
||||
}
|
||||
|
||||
export type TriggerConfig =
|
||||
| WebhookTriggerConfig
|
||||
| ScheduleTriggerConfig
|
||||
| ManualTriggerConfig;
|
||||
|
||||
export interface WebhookTriggerConfig {
|
||||
type: 'webhook';
|
||||
}
|
||||
|
||||
export interface ScheduleTriggerConfig {
|
||||
type: 'schedule';
|
||||
cron: string; // Cron expression
|
||||
timezone?: string; // Default: UTC
|
||||
}
|
||||
|
||||
export interface ManualTriggerConfig {
|
||||
type: 'manual';
|
||||
}
|
||||
|
||||
export interface CreateTriggerRequest {
|
||||
type: TriggerType;
|
||||
name: string;
|
||||
config: TriggerConfig;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Executions (Run History)
|
||||
// =============================================================================
|
||||
|
||||
export type ExecutionStatus = 'running' | 'success' | 'error' | 'timeout';
|
||||
|
||||
export interface Execution {
|
||||
id: UUID;
|
||||
flowId: UUID;
|
||||
triggerId: UUID | null;
|
||||
triggerType: TriggerType;
|
||||
status: ExecutionStatus;
|
||||
startedAt: ISODateTime;
|
||||
completedAt: ISODateTime | null;
|
||||
durationMs: number | null;
|
||||
errorMessage: string | null;
|
||||
inputPayload: string | null; // JSON string
|
||||
outputPayload: string | null; // JSON string
|
||||
}
|
||||
|
||||
export interface ExecutionSummary {
|
||||
id: UUID;
|
||||
status: ExecutionStatus;
|
||||
triggerType: TriggerType;
|
||||
startedAt: ISODateTime;
|
||||
durationMs: number | null;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// WASM Modules (Pro+)
|
||||
// =============================================================================
|
||||
|
||||
export interface WasmModule {
|
||||
id: UUID;
|
||||
userId: UUID;
|
||||
name: string;
|
||||
description: string | null;
|
||||
witInterface: string | null;
|
||||
sizeBytes: number;
|
||||
createdAt: ISODateTime;
|
||||
updatedAt: ISODateTime;
|
||||
}
|
||||
|
||||
export interface WasmModuleSummary {
|
||||
id: UUID;
|
||||
name: string;
|
||||
description: string | null;
|
||||
createdAt: ISODateTime;
|
||||
}
|
||||
|
||||
export interface CreateWasmModuleRequest {
|
||||
name: string;
|
||||
description?: string;
|
||||
witInterface?: string;
|
||||
// Actual .wasm file uploaded separately via multipart
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Marketplace
|
||||
// =============================================================================
|
||||
|
||||
export type MarketplaceListingType = 'tool' | 'flow';
|
||||
|
||||
export interface MarketplaceListing {
|
||||
id: UUID;
|
||||
authorId: UUID;
|
||||
authorName: string;
|
||||
type: MarketplaceListingType;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
tags: string[];
|
||||
downloads: number;
|
||||
rating: number | null;
|
||||
content: MarketplaceContent;
|
||||
createdAt: ISODateTime;
|
||||
updatedAt: ISODateTime;
|
||||
}
|
||||
|
||||
export interface MarketplaceListingSummary {
|
||||
id: UUID;
|
||||
authorName: string;
|
||||
type: MarketplaceListingType;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
downloads: number;
|
||||
rating: number | null;
|
||||
}
|
||||
|
||||
export type MarketplaceContent = ToolContent | FlowTemplateContent;
|
||||
|
||||
export interface ToolContent {
|
||||
type: 'tool';
|
||||
wasmModuleId: UUID;
|
||||
witInterface: string;
|
||||
exampleUsage: string;
|
||||
}
|
||||
|
||||
export interface FlowTemplateContent {
|
||||
type: 'flow';
|
||||
organismYaml: string;
|
||||
canvasState: CanvasState;
|
||||
}
|
||||
|
||||
export interface PublishToMarketplaceRequest {
|
||||
type: MarketplaceListingType;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
tags: string[];
|
||||
content: MarketplaceContent;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Project Memory (Pro+, opt-in)
|
||||
// =============================================================================
|
||||
|
||||
export interface ProjectMemory {
|
||||
flowId: UUID;
|
||||
enabled: boolean;
|
||||
usedBytes: number;
|
||||
maxBytes: number;
|
||||
keys: string[];
|
||||
}
|
||||
|
||||
export interface MemoryEntry {
|
||||
key: string;
|
||||
value: string; // JSON string
|
||||
sizeBytes: number;
|
||||
updatedAt: ISODateTime;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// API Responses
|
||||
// =============================================================================
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
items: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
export interface ApiError {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Flow Logs (streaming)
|
||||
// =============================================================================
|
||||
|
||||
export interface LogEntry {
|
||||
timestamp: ISODateTime;
|
||||
level: 'debug' | 'info' | 'warning' | 'error';
|
||||
message: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Stats & Analytics
|
||||
// =============================================================================
|
||||
|
||||
export interface FlowStats {
|
||||
flowId: UUID;
|
||||
executionsTotal: number;
|
||||
executionsSuccess: number;
|
||||
executionsError: number;
|
||||
avgDurationMs: number;
|
||||
lastExecutedAt: ISODateTime | null;
|
||||
}
|
||||
|
||||
export interface UsageStats {
|
||||
userId: UUID;
|
||||
period: 'day' | 'month';
|
||||
flowCount: number;
|
||||
executionCount: number;
|
||||
executionLimit: number;
|
||||
}
|
||||
Loading…
Reference in a new issue