{"openapi":"3.1.0","info":{"version":"1.0.0","title":"Hono Datastar API","description":"Counter API backed by Cloudflare D1 (SQLite) with a Datastar SSE frontend, MCP tools for AI agents, and Better Auth."},"tags":[{"name":"Counter","description":"Read, increment, decrement, and reset the shared counter."},{"name":"Tasks","description":"Authenticated task CRUD (also exposed as MCP tools)."},{"name":"Admin","description":"Admin user management (Better Auth admin plugin, auto-mounted under /api/auth/admin/)."}],"servers":[{"url":"https://test-hono.gedw99.workers.dev","description":"Production"},{"url":"http://localhost:8787","description":"Local dev"}],"components":{"schemas":{"Counter":{"type":"object","properties":{"count":{"type":"integer","example":1}},"required":["count"]},"SetCount":{"type":"object","properties":{"inputValue":{"type":"integer","example":42,"description":"Value to set the counter to"}},"required":["inputValue"]},"CounterFragment":{"type":"object","properties":{"count":{"type":"integer"},"html":{"type":"string"},"renderedAt":{"type":"string"}},"required":["count","html","renderedAt"]},"NotesList":{"type":"object","properties":{"notes":{"type":"array","items":{"$ref":"#/components/schemas/Note"}},"noteCount":{"type":"integer"}},"required":["notes","noteCount"]},"Note":{"type":"object","properties":{"id":{"type":"integer"},"userId":{"type":"string"},"text":{"type":"string"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}},"required":["id","userId","text","createdAt","updatedAt"]},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"AddNote":{"type":"object","properties":{"newNote":{"type":"string","minLength":1,"example":"Buy groceries","description":"Text of the note to add"}},"required":["newNote"]},"Success":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"NotesReset":{"type":"object","properties":{"noteCount":{"type":"integer"}},"required":["noteCount"]},"TaskList":{"type":"object","properties":{"tasks":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"taskCount":{"type":"integer"}},"required":["tasks","taskCount"]},"Task":{"type":"object","properties":{"id":{"type":"integer"},"userId":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["pending","in_progress","completed"]},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}},"required":["id","userId","title","description","status","createdAt","updatedAt"]},"CreateTask":{"type":"object","properties":{"taskTitle":{"type":"string","minLength":1,"example":"Build MCP server","description":"Title of the task"},"taskDesc":{"type":"string","example":"Integrate with Claude Desktop","description":"Optional task description"}},"required":["taskTitle"]},"UpdateTask":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"New title"},"description":{"type":"string","description":"New description"},"status":{"type":"string","enum":["pending","in_progress","completed"],"description":"Task status"}}},"TasksReset":{"type":"object","properties":{"taskCount":{"type":"integer"}},"required":["taskCount"]},"SessionList":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionInfo"}},"sessionCount":{"type":"integer"}},"required":["sessions","sessionCount"]},"SessionInfo":{"type":"object","properties":{"id":{"type":"string"},"token":{"type":"string"},"ipAddress":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"browser":{"type":"string"},"os":{"type":"string"},"lastActive":{"type":"integer"},"createdAt":{"type":"integer"},"isCurrent":{"type":"boolean"}},"required":["id","token","ipAddress","userAgent","browser","os","lastActive","createdAt","isCurrent"]},"RevokeSession":{"type":"object","properties":{"revokeSessionToken":{"type":"string","minLength":1,"description":"Token of the session to revoke"}},"required":["revokeSessionToken"]}},"parameters":{}},"paths":{"/api/counter":{"get":{"tags":["Counter"],"summary":"Get current count","description":"Returns the current counter value from D1.","responses":{"200":{"description":"Current counter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counter"}}}}}}},"/api/counter/increment":{"post":{"tags":["Counter"],"summary":"Increment counter","description":"Atomically increments the counter by 1 and returns the new value.","responses":{"200":{"description":"Incremented counter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counter"}}}}}}},"/api/counter/decrement":{"post":{"tags":["Counter"],"summary":"Decrement counter","description":"Atomically decrements the counter by 1 and returns the new value.","responses":{"200":{"description":"Decremented counter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counter"}}}}}}},"/api/counter/set":{"post":{"tags":["Counter"],"summary":"Set counter to specific value","description":"Sets the counter to the provided value. Datastar sends all signals as the request body; Zod strips extras.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetCount"}}}},"responses":{"200":{"description":"Counter set to new value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counter"}}}}}}},"/api/counter/fragment":{"get":{"tags":["Counter"],"summary":"Server-rendered HTML fragment","description":"Returns the counter as a server-rendered HTML fragment. Datastar receives an SSE patch-elements event; API clients receive JSON with the HTML string.","responses":{"200":{"description":"Server-rendered counter fragment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CounterFragment"}}}}}}},"/api/counter/reset":{"post":{"tags":["Counter"],"summary":"Reset counter","description":"Resets the counter to 0. Used for test isolation.","responses":{"200":{"description":"Counter reset to 0","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counter"}}}}}}},"/api/notes":{"get":{"tags":["Notes"],"summary":"List notes for authenticated user","description":"Returns all notes ordered by creation date (newest first). SSE response renders HTML list items.","responses":{"200":{"description":"List of notes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotesList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Notes"],"summary":"Add a note","description":"Creates a new note. SSE response re-renders the list via fragment inner mode.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddNote"}}}},"responses":{"200":{"description":"Created note","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/notes/{id}":{"delete":{"tags":["Notes"],"summary":"Delete a note","description":"Deletes a note by ID. SSE response re-renders the list via fragment inner mode.","parameters":[{"schema":{"type":["integer","null"]},"required":false,"name":"id","in":"path"}],"responses":{"200":{"description":"Note deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/notes/reset":{"post":{"tags":["Notes"],"summary":"Clear all notes for authenticated user","description":"Deletes all notes. Used for test isolation.","responses":{"200":{"description":"Notes cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotesReset"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks":{"get":{"tags":["Tasks"],"summary":"List tasks for authenticated user","parameters":[{"schema":{"type":"string","enum":["pending","in_progress","completed"],"description":"Filter by status"},"required":false,"description":"Filter by status","name":"status","in":"query"}],"responses":{"200":{"description":"Tasks list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Tasks"],"summary":"Create a task","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTask"}}}},"responses":{"200":{"description":"Created task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/{id}":{"get":{"tags":["Tasks"],"summary":"Get a task by ID","parameters":[{"schema":{"type":["integer","null"]},"required":false,"name":"id","in":"path"}],"responses":{"200":{"description":"Task details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Tasks"],"summary":"Update a task","parameters":[{"schema":{"type":["integer","null"]},"required":false,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTask"}}}},"responses":{"200":{"description":"Updated task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Tasks"],"summary":"Delete a task","parameters":[{"schema":{"type":["integer","null"]},"required":false,"name":"id","in":"path"}],"responses":{"200":{"description":"Task deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/reset":{"post":{"tags":["Tasks"],"summary":"Clear all tasks for authenticated user","description":"Deletes all tasks. Used for test isolation.","responses":{"200":{"description":"Tasks cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TasksReset"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/sessions":{"get":{"tags":["Sessions"],"summary":"List active sessions for authenticated user","responses":{"200":{"description":"Sessions list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/sessions/revoke":{"post":{"tags":["Sessions"],"summary":"Revoke (log out) another session","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeSession"}}}},"responses":{"200":{"description":"Session revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Cannot revoke current session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}