feat(infra): auto-commit con 88 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
---
|
||||
name: hoppscotch_login
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def hoppscotch_login(email: str, *, backend_url: str = \"http://localhost:3170\", mailpit_url: str = \"http://localhost:8025\", timeout_s: float = 15.0) -> dict"
|
||||
description: "Login headless contra un Hoppscotch self-hosted via magic link, leyendo el correo de verificacion desde una instancia Mailpit de pruebas. Reproduce el flujo sin navegador: POST /v1/auth/signin (deviceIdentifier) -> lee el correo 'Sign in' del email en Mailpit -> extrae el token (?token=...) del cuerpo -> POST /v1/auth/verify (Set-Cookie access_token + refresh_token). Devuelve los JWT de sesion que las mutations GraphQL protegidas esperan en la cookie access_token."
|
||||
tags: [hoppscotch, flow-replay, http, infra, auth]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [re, requests]
|
||||
params:
|
||||
- name: email
|
||||
desc: "correo del usuario que inicia sesion. Debe poder recibir el correo de verificacion en la instancia Mailpit indicada (en el self-host de pruebas, admin@example.com)."
|
||||
- name: backend_url
|
||||
desc: "base del backend Hoppscotch sin barra final. Los endpoints REST de auth cuelgan de {backend_url}/v1/auth/signin y /v1/auth/verify. Default http://localhost:3170."
|
||||
- name: mailpit_url
|
||||
desc: "base de la API de Mailpit donde aterriza el correo de verificacion, sin barra final. Default http://localhost:8025."
|
||||
- name: timeout_s
|
||||
desc: "timeout por request HTTP en segundos. Default 15.0."
|
||||
output: "dict. En exito: {status: 'ok', access_token: str, refresh_token: str, email: str}. En error (signin != 201, no llega correo 'Sign in', token no encontrado en el correo, verify != 200, o fallo de transporte): {status: 'error', error: str}. Nunca lanza por errores de red esperables."
|
||||
tested: true
|
||||
tests:
|
||||
- "test_golden_login_devuelve_tokens"
|
||||
- "test_verify_recibe_token_extraido_y_device_identifier"
|
||||
- "test_error_signin_no_201"
|
||||
- "test_error_correo_no_encontrado"
|
||||
- "test_error_token_no_en_correo"
|
||||
test_file_path: "python/functions/infra/hoppscotch_login_test.py"
|
||||
file_path: "python/functions/infra/hoppscotch_login.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys
|
||||
sys.path.insert(0, "python/functions")
|
||||
from infra.hoppscotch_login import hoppscotch_login
|
||||
from infra.hoppscotch_create_request import hoppscotch_create_request
|
||||
|
||||
# 1) Obtener un JWT de sesion via magic link (headless, lee el correo de Mailpit).
|
||||
login = hoppscotch_login("admin@example.com")
|
||||
assert login["status"] == "ok", login["error"]
|
||||
token = login["access_token"]
|
||||
|
||||
# 2) Usar el token para crear una request en una team collection.
|
||||
# El self-host de referencia exige team_id dentro del input.
|
||||
created = hoppscotch_create_request(
|
||||
collection_id="cmq8lt8ta000t0xls4ddy6sdz",
|
||||
method="GET",
|
||||
url="https://api.example.com/ping",
|
||||
title="Ping",
|
||||
team_id="cmq8kn0v500030xls1nvminjy",
|
||||
access_token=token,
|
||||
)
|
||||
print(created) # {"status": "ok", "id": "...", "title": "Ping"}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites un JWT de sesion de un Hoppscotch self-hosted para operar su API
|
||||
GraphQL protegida (crear/editar/borrar requests, gestionar collections) sin abrir
|
||||
el navegador. Es el primer paso de cualquier flujo CRUD del grupo `hoppscotch`:
|
||||
llama esto, captura `access_token`, y paselo a `hoppscotch_create_request` /
|
||||
`hoppscotch_update_request` / `hoppscotch_delete_request` / `hoppscotch_list_requests`.
|
||||
Requiere que el backend mande el correo de verificacion a una instancia Mailpit
|
||||
accesible (entorno de pruebas).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **El access_token va como cookie, no como header Authorization.** Las mutations
|
||||
GraphQL leen el JWT de la cookie `access_token`. Cada funcion del grupo lo manda
|
||||
con `cookies={"access_token": ...}`.
|
||||
- **El token expira (~24h).** Cuando una llamada GraphQL devuelva un error de auth,
|
||||
re-loguea con `hoppscotch_login` para obtener un access_token fresco.
|
||||
- **Depende de Mailpit.** El flujo lee el correo de verificacion de una instancia
|
||||
Mailpit de pruebas. No funciona contra un backend que mande el correo a un buzon
|
||||
real al que esta funcion no pueda consultar por API.
|
||||
- **Secreto — nunca logear el token en crudo.** `access_token`/`refresh_token` son
|
||||
credenciales de sesion. No los imprimas ni los persistas en claro; trataelos como
|
||||
un secreto (vault/pass) si los guardas entre ejecuciones.
|
||||
- **Coincidencia del correo por subject + destinatario.** Se elige el mensaje mas
|
||||
reciente cuyo destinatario sea `email` y cuyo subject contenga "Sign in". Si hay
|
||||
varios magic links pendientes para el mismo email, se usa el ultimo de la lista.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
v1.0.0 — version inicial. Flujo magic link headless validado contra el self-host
|
||||
vivo (login + CRUD completo) el 10/06/2026.
|
||||
Reference in New Issue
Block a user