V0.6.2 docs openapi (#37)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-go-pg (push) Successful in 2m46s
CI/CD / test-sqlite (push) Successful in 2m49s
CI/CD / build-and-deploy (push) Successful in 28s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #37.
This commit is contained in:
2026-03-31 12:01:51 +00:00
committed by xcaliber
parent 1a7f41493d
commit a887b4c78b
32 changed files with 3862 additions and 548 deletions

View File

@@ -332,6 +332,107 @@ func hasPermission(granted []string, perm string) bool {
return false
}
// ── api_schema support (v0.6.2) ─────────────────────────────────────
// APISchemaEntry represents one route's OpenAPI-level documentation
// declared via the optional manifest "api_schema" array.
type APISchemaEntry struct {
Path string `json:"path"`
Method string `json:"method"`
Summary string `json:"summary,omitempty"`
Description string `json:"description,omitempty"`
Params map[string]any `json:"params,omitempty"`
Body map[string]any `json:"body,omitempty"`
Response map[string]any `json:"response,omitempty"`
}
// ParseAPISchema extracts the optional api_schema array from a package manifest.
// Malformed entries are logged and skipped — never blocks extension loading.
func ParseAPISchema(manifest map[string]any) []APISchemaEntry {
raw, ok := manifest["api_schema"]
if !ok {
return nil
}
arr, ok := raw.([]any)
if !ok {
log.Printf("[ext_api] api_schema is not an array, skipping")
return nil
}
var entries []APISchemaEntry
for i, item := range arr {
m, ok := item.(map[string]any)
if !ok {
log.Printf("[ext_api] api_schema[%d]: not an object, skipping", i)
continue
}
path, _ := m["path"].(string)
method, _ := m["method"].(string)
if path == "" || method == "" {
log.Printf("[ext_api] api_schema[%d]: missing path or method, skipping", i)
continue
}
entry := APISchemaEntry{
Path: path,
Method: strings.ToUpper(method),
}
if s, ok := m["summary"].(string); ok {
entry.Summary = s
}
if s, ok := m["description"].(string); ok {
entry.Description = s
}
if p, ok := m["params"].(map[string]any); ok {
entry.Params = p
}
if b, ok := m["body"].(map[string]any); ok {
entry.Body = b
}
if r, ok := m["response"].(map[string]any); ok {
entry.Response = r
}
entries = append(entries, entry)
}
return entries
}
// ExtractAPIRoutes returns all declared path+method pairs from the manifest.
// Used by the OpenAPI builder to enumerate routes for stub generation.
func ExtractAPIRoutes(manifest map[string]any) []struct{ Method, Path string } {
raw, ok := manifest["api_routes"]
if !ok {
return nil
}
// Boolean shorthand — no specific routes to enumerate
if _, ok := raw.(bool); ok {
return nil
}
routes, ok := raw.([]any)
if !ok {
return nil
}
var result []struct{ Method, Path string }
for _, entry := range routes {
route, ok := entry.(map[string]any)
if !ok {
continue
}
method, _ := route["method"].(string)
path, _ := route["path"].(string)
if method == "" || path == "" {
continue
}
result = append(result, struct{ Method, Path string }{
Method: strings.ToUpper(method),
Path: path,
})
}
return result
}
// HasAPIRoutes checks whether a package manifest declares API routes.
// Used by startup discovery and admin UI to identify API-capable packages.
func HasAPIRoutes(manifest map[string]any) bool {