{"openapi":"3.1.0","info":{"title":"nxv API","description":"API for querying Nix package version history. Find specific versions of packages across nixpkgs history.","contact":{"name":"nxv","url":"https://github.com/jamesbrink/nxv"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"/","description":"Local server"}],"paths":{"/api/v1/health":{"get":{"tags":["health"],"summary":"Health check endpoint.","description":"Note: The health check uses relaxed concurrency controls to ensure it can\nrespond even when the server is under heavy load. It has a shorter timeout\nand doesn't wait for a semaphore permit.","operationId":"health_check","responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/metrics":{"get":{"tags":["monitoring"],"summary":"Get server metrics for monitoring.","description":"Returns metrics about the server including database connection pool utilization\nand rate limiting configuration. Useful for monitoring dashboards and alerting.\n\n# Returns\n\nJSON response with server, database, and rate limit metrics.","operationId":"get_metrics","responses":{"200":{"description":"Server metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsResponse"}}}}}}},"/api/v1/packages/{attr}":{"get":{"tags":["packages"],"summary":"Retrieve all package versions that match the given attribute path.","description":"Returns a list of package version records for the exact attribute path. If no matching\npackage versions are found, the handler returns a 404 Not Found error.\n\n# Examples\n\n```rust,ignore\n// Example: the handler returns an ApiResponse wrapping the matching package versions.\n// In handler tests you would call `get_package` with a test AppState and assert the result.\nuse axum::Json;\nuse dpkg_indexer_common::ApiResponse;\n\nlet resp = ApiResponse::new(Vec::<()>::new());\nassert!(matches!(resp.data.len(), 0));\n```","operationId":"get_package","parameters":[{"name":"attr","in":"path","description":"Package attribute path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Package info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_Vec_PackageVersionSchema"}}}},"404":{"description":"Package not found"},"503":{"description":"Index not available"}}}},"/api/v1/packages/{attr}/history":{"get":{"tags":["packages"],"summary":"Get version history for a package.","operationId":"get_version_history","parameters":[{"name":"attr","in":"path","description":"Package attribute path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_Vec_VersionHistorySchema"}}}},"404":{"description":"Package not found"},"503":{"description":"Index not available"}}}},"/api/v1/packages/{attr}/versions/{version}":{"get":{"tags":["packages"],"summary":"Retrieve information for a specific package version.","description":"If the package version exists, the response payload contains the package record.\nIf the version is not found, the handler returns an `ApiError::not_found`.\n\n# Examples\n\n```no_run\nuse axum::extract::{State, Path};\nuse std::sync::Arc;\n// Assume `state` is an Arc<AppState> and `attr`, `version` are Strings.\n// let resp = get_version_info(State(state), Path((attr, version))).await;\n```","operationId":"get_version_info","parameters":[{"name":"attr","in":"path","description":"Package attribute path","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Package version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PackageVersionSchema"}}}},"404":{"description":"Version not found"},"503":{"description":"Index not available"}}}},"/api/v1/packages/{attr}/versions/{version}/first":{"get":{"tags":["packages"],"summary":"Returns the first recorded occurrence of a specific package version.","description":"Looks up the earliest stored PackageVersion for the given package attribute path (`attr`)\nand version string (`version`). If found, the package version is returned wrapped in an\n`ApiResponse`; if not found, a 404 ApiError is returned.\n\n# Parameters\n\n- `attr`: Package attribute path to look up.\n- `version`: Specific package version to find.\n\n# Returns\n\n`ApiResponse<PackageVersion>` containing the first recorded occurrence of the requested version.\n\n# Examples\n\n```no_run\n// HTTP GET /api/v1/packages/my.package/versions/1.2.3/first\n```","operationId":"get_first_occurrence","parameters":[{"name":"attr","in":"path","description":"Package attribute path","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Package version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"First occurrence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PackageVersionSchema"}}}},"404":{"description":"Version not found"},"503":{"description":"Index not available"}}}},"/api/v1/packages/{attr}/versions/{version}/last":{"get":{"tags":["packages"],"summary":"Get last occurrence of a specific version.","operationId":"get_last_occurrence","parameters":[{"name":"attr","in":"path","description":"Package attribute path","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Package version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Last occurrence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PackageVersionSchema"}}}},"404":{"description":"Version not found"},"503":{"description":"Index not available"}}}},"/api/v1/search":{"get":{"tags":["packages"],"summary":"Search packages by name or attribute path and return paginated package versions.","description":"Builds search options from query parameters, executes the index search, and wraps\nthe matching `PackageVersion` records along with pagination metadata in an `ApiResponse`.\n\n# Examples\n\n```\nuse std::sync::Arc;\nuse axum::extract::Query;\nuse crate::server::{AppState, SearchParams};\n// Construct query params (as if received from a request)\nlet params = SearchParams {\n    q: \"serde\".to_string(),\n    version: None,\n    exact: None,\n    license: None,\n    sort: None,\n    reverse: None,\n    limit: Some(10),\n    offset: Some(0),\n};\n// In an application handler you'd call `search_packages(State(state), Query(params)).await`.\n// This example demonstrates the intended parameters; actual invocation requires an Axum runtime and AppState.\n```","operationId":"search_packages","parameters":[{"name":"q","in":"query","description":"Package name or attribute path to search","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Filter by version prefix","required":false,"schema":{"type":"string"}},{"name":"exact","in":"query","description":"Exact match only","required":false,"schema":{"type":"boolean"}},{"name":"license","in":"query","description":"Filter by license","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","description":"Sort order: date, version, or name","required":false,"schema":{"type":"string"}},{"name":"reverse","in":"query","description":"Reverse sort order","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum results (default: 50)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"offset","in":"query","description":"Results to skip","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_Vec_PackageVersionSchema"}}}},"400":{"description":"Invalid parameters"},"503":{"description":"Index not available"}}}},"/api/v1/search/description":{"get":{"tags":["packages"],"summary":"Search packages by their description using full-text search.","description":"Performs a description-based search and returns a paginated list of matching package versions.\n\n# Examples\n\n```\n// Build a query URL for the description search endpoint.\nlet query = \"serde features\";\nlet limit = 10;\nlet offset = 0;\nlet url = format!(\"/api/v1/search/description?q={}&limit={}&offset={}\", query, limit, offset);\nassert!(url.starts_with(\"/api/v1/search/description\"));\n```","operationId":"search_description","parameters":[{"name":"q","in":"query","description":"Search query for descriptions","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum results (default: 50)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"offset","in":"query","description":"Results to skip","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_Vec_PackageVersionSchema"}}}},"400":{"description":"Invalid parameters"},"503":{"description":"Index not available"}}}},"/api/v1/stats":{"get":{"tags":["stats"],"summary":"Return index statistics for the server's package index.","description":"On success, returns `Ok(Json(ApiResponse<IndexStatsSchema>))` containing the index statistics; on failure, returns `Err(ApiError)`.\n\n# Examples\n\n```\n# async fn doc_example() {\n# use std::sync::Arc;\n# use axum::extract::State;\n# use crate::server::AppState;\n# use crate::server::handlers::get_stats;\n// `state` would normally be provided by the application runtime.\n// let state: Arc<AppState> = ...;\n// let result = get_stats(State(state)).await;\n// match result {\n//     Ok(json_resp) => println!(\"stats: {:?}\", json_resp),\n//     Err(err) => eprintln!(\"error: {:?}\", err),\n// }\n# }\n```","operationId":"get_stats","responses":{"200":{"description":"Index statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_IndexStatsSchema"}}}},"503":{"description":"Index not available"}}}}},"components":{"schemas":{"ApiResponse_IndexStatsSchema":{"type":"object","description":"Wrapper for paginated API responses.","required":["data"],"properties":{"data":{"type":"object","description":"Index statistics schema.","required":["total_ranges","unique_names","unique_versions"],"properties":{"last_indexed_commit":{"type":["string","null"],"description":"The commit hash that was last indexed."},"last_indexed_date":{"type":["string","null"],"description":"When the index was last updated (RFC3339 format)."},"newest_commit_date":{"type":["string","null"],"format":"date-time"},"oldest_commit_date":{"type":["string","null"],"format":"date-time"},"total_ranges":{"type":"integer","format":"int64"},"unique_names":{"type":"integer","format":"int64"},"unique_versions":{"type":"integer","format":"int64"}}},"meta":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta","description":"Pagination metadata (present for list responses)."}]}}},"ApiResponse_PackageVersionSchema":{"type":"object","description":"Wrapper for paginated API responses.","required":["data"],"properties":{"data":{"type":"object","description":"Package version info (re-export with ToSchema).\nThis wrapper is needed because PackageVersion is defined elsewhere.","required":["id","name","version","first_commit_hash","first_commit_date","last_commit_hash","last_commit_date","attribute_path"],"properties":{"attribute_path":{"type":"string"},"description":{"type":["string","null"]},"first_commit_date":{"type":"string","format":"date-time"},"first_commit_hash":{"type":"string"},"homepage":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"known_vulnerabilities":{"type":["string","null"],"description":"Known security vulnerabilities (JSON array, may be null for secure packages)."},"last_commit_date":{"type":"string","format":"date-time"},"last_commit_hash":{"type":"string"},"license":{"type":["string","null"]},"maintainers":{"type":["string","null"]},"name":{"type":"string"},"platforms":{"type":["string","null"]},"source_path":{"type":["string","null"],"description":"Source file path relative to nixpkgs root (may be null for older packages)."},"version":{"type":"string"}}},"meta":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta","description":"Pagination metadata (present for list responses)."}]}}},"ApiResponse_Vec_PackageVersionSchema":{"type":"object","description":"Wrapper for paginated API responses.","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","description":"Package version info (re-export with ToSchema).\nThis wrapper is needed because PackageVersion is defined elsewhere.","required":["id","name","version","first_commit_hash","first_commit_date","last_commit_hash","last_commit_date","attribute_path"],"properties":{"attribute_path":{"type":"string"},"description":{"type":["string","null"]},"first_commit_date":{"type":"string","format":"date-time"},"first_commit_hash":{"type":"string"},"homepage":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"known_vulnerabilities":{"type":["string","null"],"description":"Known security vulnerabilities (JSON array, may be null for secure packages)."},"last_commit_date":{"type":"string","format":"date-time"},"last_commit_hash":{"type":"string"},"license":{"type":["string","null"]},"maintainers":{"type":["string","null"]},"name":{"type":"string"},"platforms":{"type":["string","null"]},"source_path":{"type":["string","null"],"description":"Source file path relative to nixpkgs root (may be null for older packages)."},"version":{"type":"string"}}}},"meta":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta","description":"Pagination metadata (present for list responses)."}]}}},"ApiResponse_Vec_VersionHistorySchema":{"type":"object","description":"Wrapper for paginated API responses.","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","description":"Version history entry for API responses.","required":["version","first_seen","last_seen","is_insecure"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"First time this version was seen."},"is_insecure":{"type":"boolean","description":"Whether this version has known vulnerabilities."},"last_seen":{"type":"string","format":"date-time","description":"Last time this version was seen."},"version":{"type":"string","description":"Package version string."}}}},"meta":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta","description":"Pagination metadata (present for list responses)."}]}}},"DatabaseMetrics":{"type":"object","description":"Database connection pool metrics.","required":["max_connections","available_permits","in_use","timeout_seconds"],"properties":{"available_permits":{"type":"integer","description":"Currently available connection permits.","minimum":0},"in_use":{"type":"integer","description":"Permits currently in use.","minimum":0},"max_connections":{"type":"integer","description":"Maximum concurrent database connections allowed.","minimum":0},"timeout_seconds":{"type":"integer","format":"int64","description":"Database operation timeout in seconds.","minimum":0}}},"HealthResponse":{"type":"object","description":"Health check response.","required":["status","version"],"properties":{"index_commit":{"type":["string","null"],"description":"Last indexed commit hash (if available)."},"status":{"type":"string","description":"Service status."},"version":{"type":"string","description":"nxv version."}}},"IndexStatsSchema":{"type":"object","description":"Index statistics schema.","required":["total_ranges","unique_names","unique_versions"],"properties":{"last_indexed_commit":{"type":["string","null"],"description":"The commit hash that was last indexed."},"last_indexed_date":{"type":["string","null"],"description":"When the index was last updated (RFC3339 format)."},"newest_commit_date":{"type":["string","null"],"format":"date-time"},"oldest_commit_date":{"type":["string","null"],"format":"date-time"},"total_ranges":{"type":"integer","format":"int64"},"unique_names":{"type":"integer","format":"int64"},"unique_versions":{"type":"integer","format":"int64"}}},"MetricsResponse":{"type":"object","description":"Server metrics response for monitoring.","required":["server","database"],"properties":{"database":{"$ref":"#/components/schemas/DatabaseMetrics","description":"Database connection pool metrics."},"rate_limit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitMetrics","description":"Rate limiting metrics (if enabled)."}]},"server":{"$ref":"#/components/schemas/ServerMetrics","description":"Server uptime information."}}},"PackageVersionSchema":{"type":"object","description":"Package version info (re-export with ToSchema).\nThis wrapper is needed because PackageVersion is defined elsewhere.","required":["id","name","version","first_commit_hash","first_commit_date","last_commit_hash","last_commit_date","attribute_path"],"properties":{"attribute_path":{"type":"string"},"description":{"type":["string","null"]},"first_commit_date":{"type":"string","format":"date-time"},"first_commit_hash":{"type":"string"},"homepage":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"known_vulnerabilities":{"type":["string","null"],"description":"Known security vulnerabilities (JSON array, may be null for secure packages)."},"last_commit_date":{"type":"string","format":"date-time"},"last_commit_hash":{"type":"string"},"license":{"type":["string","null"]},"maintainers":{"type":["string","null"]},"name":{"type":"string"},"platforms":{"type":["string","null"]},"source_path":{"type":["string","null"],"description":"Source file path relative to nixpkgs root (may be null for older packages)."},"version":{"type":"string"}}},"PaginationMeta":{"type":"object","description":"Pagination metadata for list responses.","required":["total","limit","offset","has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether more results are available."},"limit":{"type":"integer","description":"Maximum results per page.","minimum":0},"offset":{"type":"integer","description":"Number of results skipped.","minimum":0},"total":{"type":"integer","description":"Total number of results before pagination.","minimum":0}}},"RateLimitMetrics":{"type":"object","description":"Rate limiting metrics.","required":["requests_per_second","burst_size","enabled"],"properties":{"burst_size":{"type":"integer","format":"int32","description":"Configured burst size.","minimum":0},"enabled":{"type":"boolean","description":"Whether rate limiting is enabled."},"requests_per_second":{"type":"integer","format":"int64","description":"Configured requests per second per IP.","minimum":0}}},"ServerMetrics":{"type":"object","description":"Server-level metrics.","required":["version","status"],"properties":{"status":{"type":"string","description":"Server status."},"version":{"type":"string","description":"nxv version."}}},"VersionHistorySchema":{"type":"object","description":"Version history entry for API responses.","required":["version","first_seen","last_seen","is_insecure"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"First time this version was seen."},"is_insecure":{"type":"boolean","description":"Whether this version has known vulnerabilities."},"last_seen":{"type":"string","format":"date-time","description":"Last time this version was seen."},"version":{"type":"string","description":"Package version string."}}}}},"tags":[{"name":"packages","description":"Package search and information"},{"name":"stats","description":"Index statistics"},{"name":"health","description":"Health checks"},{"name":"monitoring","description":"Server metrics and monitoring"}]}