From 7a364e6736243fffc4bd9d4e8ab8b717df212a2d Mon Sep 17 00:00:00 2001 From: agent-company Date: Thu, 26 Mar 2026 10:26:06 +0000 Subject: [PATCH] feat: add OpenAPI TypeScript client generation setup Add openapi-typescript devDependency and npm scripts for generating typed TypeScript schema from the FastAPI OpenAPI spec. Include a static openapi.json snapshot for offline generation. - npm run generate: fetch schema from running backend and generate types - npm run generate:local: generate types from the bundled openapi.json Closes leeworks-agents/SPARC#26 Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/package.json | 3 + frontend/src/api/openapi.json | 1086 +++++++++++++++++++++++++++++++++ 2 files changed, 1089 insertions(+) create mode 100644 frontend/src/api/openapi.json diff --git a/frontend/package.json b/frontend/package.json index b99eee1..70a7c52 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,6 +7,8 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", + "generate": "openapi-typescript http://localhost:8000/api/openapi.json -o src/api/schema.d.ts", + "generate:local": "openapi-typescript src/api/openapi.json -o src/api/schema.d.ts", "preview": "vite preview" }, "dependencies": { @@ -30,6 +32,7 @@ "globals": "^15.8.0", "postcss": "^8.4.39", "tailwindcss": "^3.4.4", + "openapi-typescript": "^7.0.0", "typescript": "~5.5.3", "typescript-eslint": "^8.0.0", "vite": "^5.3.3" diff --git a/frontend/src/api/openapi.json b/frontend/src/api/openapi.json new file mode 100644 index 0000000..3a9d364 --- /dev/null +++ b/frontend/src/api/openapi.json @@ -0,0 +1,1086 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "SPARC API", + "description": "Semiconductor Patent & Analytics Report Core - Patent portfolio analysis using AI", + "version": "1.0.0" + }, + "paths": { + "/auth/register": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Register", + "description": "Register a new user.\n\nThe first registered user automatically becomes an admin.", + "operationId": "register_auth_register_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/auth/login": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Login", + "description": "Authenticate user and return JWT tokens.", + "operationId": "login_auth_login_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/auth/refresh": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Refresh Token", + "description": "Refresh access token using refresh token.", + "operationId": "refresh_token_auth_refresh_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefreshRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/auth/me": { + "get": { + "tags": [ + "Auth" + ], + "summary": "Get Me", + "description": "Get current authenticated user.", + "operationId": "get_me_auth_me_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponse" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + } + ] + } + }, + "/admin/users": { + "get": { + "tags": [ + "Admin" + ], + "summary": "List Users", + "description": "List all users (admin only).", + "operationId": "list_users_admin_users_get", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 1000, + "minimum": 1, + "default": 100, + "title": "Limit" + } + }, + { + "name": "offset", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 0, + "default": 0, + "title": "Offset" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserResponse" + }, + "title": "Response List Users Admin Users Get" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/admin/users/{user_id}/role": { + "patch": { + "tags": [ + "Admin" + ], + "summary": "Update User Role", + "description": "Update a user's role (admin only).", + "operationId": "update_user_role_admin_users__user_id__role_patch", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "User Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRoleRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/admin/users/{user_id}": { + "delete": { + "tags": [ + "Admin" + ], + "summary": "Delete User", + "description": "Delete a user (admin only).", + "operationId": "delete_user_admin_users__user_id__delete", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "User Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/analytics": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get Analytics", + "description": "Get analytics data (authenticated users only).", + "operationId": "get_analytics_analytics_get", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 365, + "minimum": 1, + "default": 30, + "title": "Days" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnalyticsResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/health": { + "get": { + "tags": [ + "System" + ], + "summary": "Health Check", + "description": "Check API health status.", + "operationId": "health_check_health_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + } + } + } + } + }, + "/analyze/{company_name}": { + "get": { + "tags": [ + "Analysis" + ], + "summary": "Analyze Company", + "description": "Analyze a single company's patent portfolio.\n\nThis endpoint retrieves recent patents for the specified company,\nparses them, and uses AI to generate a comprehensive analysis.\n\nArgs:\n company_name: Name of the company to analyze (e.g., \"nvidia\", \"intel\")\n\nReturns:\n Analysis results including patent count, AI insights, and success status", + "operationId": "analyze_company_analyze__company_name__get", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "company_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Company Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompanyAnalysisResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/analyze/batch": { + "post": { + "tags": [ + "Analysis" + ], + "summary": "Analyze Companies Batch", + "description": "Analyze multiple companies' patent portfolios.\n\nProcesses companies concurrently for improved performance.\nLimited to 20 companies per request.\n\nArgs:\n request: List of company names and optional worker count\n\nReturns:\n Batch results with individual company analyses and summary statistics", + "operationId": "analyze_companies_batch_analyze_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchAnalysisRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchAnalysisResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + } + ] + } + }, + "/analyze/batch/async": { + "post": { + "tags": [ + "Analysis" + ], + "summary": "Analyze Companies Async", + "description": "Start an asynchronous batch analysis job.\n\nReturns immediately with a job ID that can be used to poll for status.\nUseful for large batch analyses that may take a long time.\n\nArgs:\n request: List of company names and optional worker count\n\nReturns:\n Job status with job_id for polling", + "operationId": "analyze_companies_async_analyze_batch_async_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchAnalysisRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobStatus" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + } + ] + } + }, + "/jobs/{job_id}": { + "get": { + "tags": [ + "Jobs" + ], + "summary": "Get Job Status", + "description": "Get the status of a background analysis job.\n\nArgs:\n job_id: The job ID returned from the async batch endpoint\n\nReturns:\n Current job status including progress and results when complete", + "operationId": "get_job_status_jobs__job_id__get", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "job_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Job Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobStatus" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/jobs": { + "get": { + "tags": [ + "Jobs" + ], + "summary": "List Jobs", + "description": "List all analysis jobs.\n\nArgs:\n status: Optional filter by job status\n limit: Maximum number of jobs to return (default 10, max 100)\n\nReturns:\n List of job statuses", + "operationId": "list_jobs_jobs_get", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Filter by status: pending, running, completed, failed", + "title": "Status" + }, + "description": "Filter by status: pending, running, completed, failed" + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "default": 10, + "title": "Limit" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JobStatus" + }, + "title": "Response List Jobs Jobs Get" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AnalyticsResponse": { + "properties": { + "total_messages": { + "type": "integer", + "title": "Total Messages" + }, + "by_company": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array", + "title": "By Company" + }, + "by_type": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array", + "title": "By Type" + }, + "period_days": { + "type": "integer", + "title": "Period Days" + } + }, + "type": "object", + "required": [ + "total_messages", + "by_company", + "by_type", + "period_days" + ], + "title": "AnalyticsResponse", + "description": "Analytics response model." + }, + "BatchAnalysisRequest": { + "properties": { + "companies": { + "items": { + "type": "string" + }, + "type": "array", + "maxItems": 20, + "minItems": 1, + "title": "Companies", + "description": "List of company names to analyze" + }, + "max_workers": { + "type": "integer", + "maximum": 5.0, + "minimum": 1.0, + "title": "Max Workers", + "description": "Max concurrent analyses", + "default": 3 + } + }, + "type": "object", + "required": [ + "companies" + ], + "title": "BatchAnalysisRequest", + "description": "Request model for batch company analysis." + }, + "BatchAnalysisResponse": { + "properties": { + "results": { + "items": { + "$ref": "#/components/schemas/CompanyAnalysisResponse" + }, + "type": "array", + "title": "Results" + }, + "total_companies": { + "type": "integer", + "title": "Total Companies" + }, + "successful": { + "type": "integer", + "title": "Successful" + }, + "failed": { + "type": "integer", + "title": "Failed" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp" + } + }, + "type": "object", + "required": [ + "results", + "total_companies", + "successful", + "failed", + "timestamp" + ], + "title": "BatchAnalysisResponse", + "description": "Response model for batch company analysis." + }, + "CompanyAnalysisResponse": { + "properties": { + "company_name": { + "type": "string", + "title": "Company Name" + }, + "analysis": { + "type": "string", + "title": "Analysis" + }, + "patent_count": { + "type": "integer", + "title": "Patent Count" + }, + "success": { + "type": "boolean", + "title": "Success" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp" + } + }, + "type": "object", + "required": [ + "company_name", + "analysis", + "patent_count", + "success", + "timestamp" + ], + "title": "CompanyAnalysisResponse", + "description": "Response model for single company analysis." + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "HealthResponse": { + "properties": { + "status": { + "type": "string", + "title": "Status" + }, + "version": { + "type": "string", + "title": "Version" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp" + } + }, + "type": "object", + "required": [ + "status", + "version", + "timestamp" + ], + "title": "HealthResponse", + "description": "Health check response." + }, + "JobStatus": { + "properties": { + "job_id": { + "type": "string", + "title": "Job Id" + }, + "status": { + "type": "string", + "title": "Status" + }, + "progress": { + "type": "integer", + "title": "Progress" + }, + "total_companies": { + "type": "integer", + "title": "Total Companies" + }, + "completed_companies": { + "type": "integer", + "title": "Completed Companies" + }, + "result": { + "anyOf": [ + { + "$ref": "#/components/schemas/BatchAnalysisResponse" + }, + { + "type": "null" + } + ] + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + } + }, + "type": "object", + "required": [ + "job_id", + "status", + "progress", + "total_companies", + "completed_companies" + ], + "title": "JobStatus", + "description": "Status of a background analysis job." + }, + "LoginRequest": { + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "Email" + }, + "password": { + "type": "string", + "title": "Password" + } + }, + "type": "object", + "required": [ + "email", + "password" + ], + "title": "LoginRequest", + "description": "User login request." + }, + "RefreshRequest": { + "properties": { + "refresh_token": { + "type": "string", + "title": "Refresh Token" + } + }, + "type": "object", + "required": [ + "refresh_token" + ], + "title": "RefreshRequest", + "description": "Token refresh request." + }, + "RegisterRequest": { + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "Email" + }, + "password": { + "type": "string", + "minLength": 8, + "title": "Password", + "description": "Password (min 8 characters)" + } + }, + "type": "object", + "required": [ + "email", + "password" + ], + "title": "RegisterRequest", + "description": "User registration request." + }, + "TokenResponse": { + "properties": { + "access_token": { + "type": "string", + "title": "Access Token" + }, + "refresh_token": { + "type": "string", + "title": "Refresh Token" + }, + "token_type": { + "type": "string", + "title": "Token Type", + "default": "bearer" + } + }, + "type": "object", + "required": [ + "access_token", + "refresh_token" + ], + "title": "TokenResponse", + "description": "Token response model." + }, + "UpdateRoleRequest": { + "properties": { + "role": { + "type": "string", + "pattern": "^(admin|user)$", + "title": "Role" + } + }, + "type": "object", + "required": [ + "role" + ], + "title": "UpdateRoleRequest", + "description": "Update user role request." + }, + "UserResponse": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "email": { + "type": "string", + "title": "Email" + }, + "role": { + "type": "string", + "title": "Role" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + } + }, + "type": "object", + "required": [ + "id", + "email", + "role", + "created_at" + ], + "title": "UserResponse", + "description": "User response model." + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + }, + "input": { + "title": "Input" + }, + "ctx": { + "type": "object", + "title": "Context" + } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" + } + }, + "securitySchemes": { + "HTTPBearer": { + "type": "http", + "scheme": "bearer" + } + } + } +} \ No newline at end of file