- ARCHITECTURE.md: main architecture document - api-spec.yaml: full OpenAPI 3.0 spec - folder-structure.md: detailed folder layout - data-format.md: JSON schemas for .meta.json, .library.json, .tag-index.json - env-template.md: environment variables documentation - cli-protocol.md: CLI-to-API communication protocol
6.5 KiB
6.5 KiB
SimpleNote CLI - Protocolo de Comunicación
1. Overview
El CLI (simplenote-cli) se comunica con el servidor (simplenote-web) exclusivamente
vía HTTP REST usando el API documentado en api-spec.yaml.
No hay comunicación peer-to-peer ni protocolos binarios. Todo es JSON sobre HTTP.
┌──────────────────┐ HTTP/REST ┌─────────────────┐
│ simplenote-cli │ ◄──────────────────► │ simplenote-web │
│ (Commander.js) │ Bearer token auth │ (Express.js) │
└──────────────────┘ └─────────────────┘
│ │
└──── ~/.config/simplenote/config.json ──┘
2. Cliente HTTP
2.1 Clase SimpleNoteClient
// src/api/client.js
const axios = require('axios');
class SimpleNoteClient {
constructor({ baseUrl, token }) {
this.baseUrl = baseUrl.replace(/\/$/, ''); // strip trailing slash
this.token = token;
this._axios = axios.create({
baseURL: this.baseUrl,
timeout: 10000,
headers: { 'Content-Type': 'application/json' }
});
}
_authHeaders() {
return this.token ? { Authorization: `Bearer ${this.token}` } : {};
}
async _request(method, path, data) {
try {
const res = await this._axios.request({
method,
url: path,
data,
headers: this._authHeaders()
});
return res.data;
} catch (err) {
if (err.response) {
const msg = err.response.data?.error || err.message;
throw new Error(`API Error ${err.response.status}: ${msg}`);
}
throw err;
}
}
// Auth
async verifyToken() { return this._request('GET', '/auth/verify'); }
// Documents
async listDocuments(params) {
const qs = new URLSearchParams(params).toString();
return this._request('GET', `/documents${qs ? '?' + qs : ''}`);
}
async getDocument(id) { return this._request('GET', `/documents/${id}`); }
async createDocument(data) { return this._request('POST', '/documents', data); }
async updateDocument(id, data) { return this._request('PUT', `/documents/${id}`, data); }
async deleteDocument(id) { return this._request('DELETE', `/documents/${id}`); }
async exportDocument(id) { return this._request('GET', `/documents/${id}/export`); }
// Documents > Tags
async addTagsToDocument(id, tags) {
return this._request('POST', `/documents/${id}/tags`, { tags });
}
// Libraries
async listLibraries() { return this._request('GET', '/libraries'); }
async getLibrary(id) { return this._request('GET', `/libraries/${id}`); }
async createLibrary(data) { return this._request('POST', '/libraries', data); }
async getLibraryTree(id) { return this._request('GET', `/libraries/${id}/tree`); }
async listLibraryDocuments(id) {
return this._request('GET', `/libraries/${id}/documents`);
}
// Tags
async listTags() { return this._request('GET', '/tags'); }
async getTagDocuments(tag) { return this._request('GET', `/tags/${tag}`); }
}
3. Flujo de Auth
3.1 Login Inicial
simplenote auth login snk_a1b2c3d4e5f6...
Flujo:
- CLI guarda token en
~/.config/simplenote/config.json - CLI llama
GET /api/v1/auth/verifypara validar - Si 200 → login exitoso. Si 401 → token inválido.
3.2 Requests Subsecuentes
Todas las requests incluyen:
Authorization: Bearer <token>
3.3 Verificación de Status
simplenote auth status
→ GET /auth/verify → muestra si token es válido.
4. Comandos CLI Detallados
4.1 Documents
# Listar con filtros
simplenote doc list --tag backend --library 550e8400... --type requirement
simplenote doc list --tag api --limit 10
# Ver documento
simplenote doc get 770e8400-e29b-41d4-a716-446655440002
# Crear
simplenote doc create \
--title "API Authentication" \
--content "# API Authentication\n\n..." \
--tags "backend,api,auth" \
--type requirement \
--priority high \
--library 550e8400-e29b-41d4-a716-446655440000
# Actualizar
simplenote doc update 770e8400... --title "Nuevo título" --content "..."
simplenote doc update 770e8400... --status approved
# Eliminar
simplenote doc delete 770e8400...
# Exportar como markdown
simplenote doc export 770e8400...
# Agregar tags
simplenote doc add-tags 770e8400... --tags "new-tag,another"
4.2 Libraries
# Listar librerías raíz
simplenote lib list
# Listar con padre
simplenote lib list --parent 550e8400...
# Ver contenido
simplenote lib get 550e8400...
# Crear
simplenote lib create --name "API Specs"
simplenote lib create --name "Sub Librería" --parent 550e8400...
# Ver árbol completo
simplenote lib tree 550e8400...
4.3 Tags
# Listar todos los tags
simplenote tag list
# Ver docs con tag
simplenote tag docs backend
4.4 Auth
# Login con token
simplenote auth login snk_xxxxx
# Verificar status
simplenote auth status
5. Manejo de Errores
// Errores de API se transforman en mensajes claros
try {
await client.getDocument('non-existent-id');
} catch (err) {
console.error(err.message);
// "API Error 404: Document not found"
}
Códigos de error CLI:
1— Error general (network, parse, etc)2— Token inválido / auth fallida3— Recurso no encontrado (404)4— Validación de input
6. Configuración de Conexión
// ~/.config/simplenote/config.json
{
"apiUrl": "http://localhost:3000/api/v1",
"token": "snk_xxxxx",
"activeLibrary": "550e8400-e29b-41d4-a716-446655440000"
}
Override por línea de comandos:
simplenote --api-url http://custom:3000/api/v1 doc list
7. Dependencias CLI
// package.json
{
"dependencies": {
"commander": "^11.1.0",
"axios": "^1.6.0",
"chalk": "^5.3.0",
"inquirer": "^9.2.0"
}
}
8. Ejemplo de Sesión Completa
$ simplenote auth login snk_a1b2c3d4e5f6
✓ Token verified. Logged in.
$ simplenote lib list
[
{ "id": "550e8400...", "name": "Backend Requirements", "documentCount": 5 }
]
$ simplenote doc create \
--title "Token Auth" \
--tags "backend,auth" \
--type requirement \
--library 550e8400...
{
"id": "770e8400...",
"title": "Token Auth",
"tags": ["backend", "auth"],
...
}
$ simplenote tag docs backend
[
{ "id": "770e8400...", "title": "Token Auth", ... }
]
$ simplenote doc get 770e8400...
# Muestra documento formateado con content + metadata