# Inicio rápido: script

> Crea una tarea de script programada que lee una página con Playwright, guarda una captura y propone enviar un formulario para su aprobación.

Esta guía crea una tarea `script` que abre una página cada día, registra lo que ve y, cuando hay algo que enviar, propone el envío de un formulario que apruebas desde el panel.

## Antes de empezar

- **Acceso** a OpenWAF Tasks. Mira [pedir acceso](https://developers.openwaf.dev/es/tasks/#get-access).
- **Una clave de navegador** de [OpenWAF Browsers](https://developers.openwaf.dev/es/browsers/quickstart/#create-a-key). Las ejecuciones de la tarea la usan y cuentan en su cuota.
- **Un `admin` de toda la organización** para crear tareas y aprobar acciones. Leer ejecuciones solo necesita `readonly`.

## 1. Escribe el script

Un script es un módulo ES que exporta una función asíncrona. Recibe una `page` de Playwright (y `context` y `browser`) conectada al navegador de la tarea, y `task`:

| `task.…` | Qué es |
|---|---|
| `input` | El JSON `input` de la tarea, que fijas tú |
| `state` | JSON que el script guardó en la ejecución anterior (`{}` la primera vez) |
| `setState(valor)` | Guarda JSON para la siguiente ejecución (hasta 64 KiB) |
| `log(mensaje)` | Una línea en los registros de la ejecución |
| `screenshot(nombre)` | Guarda una captura de la página como artefacto de la ejecución |
| `output(valor)` | El JSON de salida de la ejecución (hasta 64 KiB) |
| `approve({summary, target, steps})` | Propone una acción para que la apruebe una persona; mira [aprobaciones](https://developers.openwaf.dev/es/tasks/approvals/) |

```js
export default async function ({ page, task }) {
  const { url, message } = task.input;
  await page.goto(url);
  await page.getByRole("heading", { name: "Guestbook" }).waitFor();
  await task.screenshot("before");

  const already = await page.getByText(message).count();
  task.log(`message on the page: ${already > 0}`);
  if (already > 0) {
    task.output({ posted: false, reason: "already there" });
    return;
  }

  // The browser is read-only here: clicking "Sign" would be blocked. Propose it instead.
  await task.approve({
    summary: `Sign the guestbook with "${message}"`,
    target: url,
    steps: [
      { op: "goto", url },
      { op: "fill", selector: "#name", text: "Example Inc." },
      { op: "fill", selector: "#message", text: message },
      { op: "click", selector: "#sign" },
      { op: "wait_for", text: message },
    ],
  });
  task.setState({ proposed_at: new Date().toISOString() });
  task.output({ posted: "pending approval" });
}
```

`task.approve` devuelve el id de la aprobación (una cadena) en cuanto la propuesta queda registrada; la acción se ejecuta más tarde, tras la aprobación, en un navegador nuevo. El script nunca sabe si se aprobó: guarda el id con `task.setState` para que la siguiente ejecución no proponga otra vez la misma acción, y consulta la aprobación o la página en la siguiente ejecución.

## 2. Crea la tarea

**Panel**

1. Abre **Tareas** en el menú de la organización y elige **Nueva tarea**, tipo **Script**.
2. Llámala `guestbook`, elige la clave de navegador, pega el script y fija la entrada.
3. Dominios permitidos: `example.com`. Calendario: `0 9 * * *`, zona horaria `Europe/Madrid`.
4. Guarda.

**API**

```sh
curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/tasks" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" -H "Content-Type: application/json" \
  -H "X-Change-Reason: Daily guestbook entry" \
  --data-binary @- <<EOF
{"name": "guestbook", "kind": "script",
 "schedule": {"cron": "0 9 * * *", "timezone": "Europe/Madrid"},
 "browser": {"key_id": "$KEY_ID", "profile": "", "recording": false},
 "allow": ["example.com"],
 "script": $(jq -Rs . < guestbook.mjs),
 "input": {"url": "https://example.com/guestbook", "message": "Hello from Example Inc."}}
EOF
```

La respuesta `201` trae la tarea con su `id` y `next_run_at`. Añade `?dry_run=true` para solo validarla.
**CLI**

Pon el mismo cuerpo JSON en `task.json` y después:

```sh
openwaf-cloud ctl tasks create task.json --org acme --reason "Daily guestbook entry"
```


## 3. Ejecútala ahora

Elige **Ejecutar ahora** en la tarea, o llama a `POST /v1/orgs/{org}/tasks/{task}/run`, o `openwaf-cloud ctl tasks run guestbook --org acme --reason "First run"`. La respuesta es la ejecución (`202`). Sigue sus registros con `GET /v1/orgs/{org}/task-runs/{run}/logs?after=<seq>`. Mientras corre, `live_url` te deja ver el navegador.

Cuando el script propone la acción, la ejecución pasa a `awaiting_approval` y la propuesta aparece en **Tareas → Aprobaciones**.

## 4. Apruébala

Abre la aprobación. Revisa el resumen, el destino, cada paso y la captura, y elige **Aprobar**. Desde la API devuelves el hash que has visto:

```sh
curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/task-approvals/$APPROVAL/approve" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" -H "Content-Type: application/json" \
  -d '{"payload_sha256": "9c1e…", "reason": "Text checked"}'
```

El runner repite los pasos en un navegador nuevo, hace una captura final y guarda el resultado en la aprobación. La ejecución termina `succeeded` o `failed`.

## Siguientes pasos

- [Aprobaciones](https://developers.openwaf.dev/es/tasks/approvals/): todos los tipos de paso, el hash y el webhook.
- [Límites](https://developers.openwaf.dev/es/tasks/limits/): los límites por dominio que pueden retrasar una acción aprobada.
