Lo que cambió, de lo más reciente a lo más antiguo. En GitHub el repositorio aún se llama linkedin-scheduler.
v2.0.0
Un Worker de Cloudflare en tu propia cuenta
Instalación con el botón Deploy to Cloudflare, un agente de código, o a mano.
Cada push despliega tu Worker y sincroniza las publicaciones en D1 y los archivos en Workers KV. Solo se envía lo que cambió.
Cada minuto: una reserva atómica, reintentos cada minuto durante 10 minutos, las respuestas poco claras nunca se reintentan, el mismo texto nunca dos veces.
/status muestra la cola, el historial y cuánto le queda al token.
Los vídeos de más de 25 MB pueden ir a un bucket R2 opcional.
Corregido
Una copia nueva ya no se vincula por error a una base de datos existente: el nombre por defecto ahora es my-linkedin-scheduler, y la sincronización comprueba que la base es la de este proyecto antes de escribir nada.
Una guía para actualizar una copia a una nueva versión.
v1
Cinco intentos por hueco
Un intento fallido se repite dos minutos después, hasta las 9:08, y luego en el siguiente hueco.
v1.0.0
Primera versión, en tu propia máquina
Un publicador en Python ejecutado por cron: como máximo una publicación lista por ejecución, en tu perfil personal, a través de la API oficial de LinkedIn.
Ganchos en negrita Unicode, un primer comentario para los enlaces, imágenes y vídeos.
Tarjetas de imagen creadas a partir de una plantilla HTML.
You are installing **linkedin-scheduler** for the user: an open-source Cloudflare Worker that publishes
LinkedIn posts written as Markdown files, on the user's personal profile, through LinkedIn's official API.
Everything runs on the user's own Cloudflare account (Worker, D1, KV) and their own private GitHub
repository. Talk to the user in their language. Explain each step before running it, and stop to ask
whenever a choice belongs to them.
## Rules
- **The token is the user's.** Never ask them to paste the LinkedIn token or `ADMIN_TOKEN` into the chat,
never print or write them to a file, never commit them. They type them into `wrangler secret put` or
the Cloudflare dashboard themselves.
- **Never publish a real post** unless the user says so for that post. For tests, keep `DRY_RUN` at `1`
or use `visibility: CONNECTIONS` with their explicit agreement.
- **Never deploy over an existing Worker** without asking: run `pnpm exec wrangler deployments list
--name <name>` first and read the whole output. If the name is taken, choose another `name` in
`wrangler.jsonc` with the user.
- Keep the safety rules in `src/core/scheduler.ts` as they are (atomic claim, `unknown` never retried,
same text never twice, 10-minute window).
## 1. Learn and check the repo
Read `README.md`, `docs/install.md`, `docs/writing-posts.md` and `docs/scheduling.md`. Done when you can
say what a post file looks like, what makes a post go out, and what stops it from going out twice.
```bash
node --version # 22 or newer
pnpm install
pnpm test && pnpm typecheck
git remote -v # must be the user's own repository, and private
```
If the repository is public or is `cjdotdev/linkedin-scheduler` itself, stop: the user first creates a
private copy ("Use this template" → Private, or `gh repo create <name> --template
cjdotdev/linkedin-scheduler --private --clone` if `gh` is installed and signed in).
## 2. LinkedIn app and token (the user does the clicks)
Walk the user through `docs/linkedin-setup.md` steps 1 and 2, one step at a time, waiting for them:
create the app (it needs a LinkedIn Page), add **Share on LinkedIn** and **Sign In with LinkedIn using
OpenID Connect**, generate a token with `openid`, `profile`, `w_member_social`. They keep the token for
step 3; ask them to note the expiry date (today + 60 days).
## 3. Install on Cloudflare
```bash
pnpm run setup
```
It signs in to Cloudflare (a browser window opens), creates the D1 database and the KV namespace, writes
their ids into `wrangler.jsonc`, asks the timezone, deploys, then asks for the secrets: the user types
`LINKEDIN_ACCESS_TOKEN`, `LINKEDIN_TOKEN_EXPIRES` and `ADMIN_TOKEN` themselves. Suggest
`openssl rand -hex 24` for `ADMIN_TOKEN` and tell them to keep it.
Then set `DRY_RUN` to `1` for the first test:
`pnpm exec wrangler deploy --var DRY_RUN:1` (the next normal deploy puts it back to `0`).
## 4. Deploy on every push
Commit `wrangler.jsonc` and `scheduler.json` (ids are not secrets) and push. Then the user connects the
repository once: Cloudflare dashboard → Workers & Pages → the Worker → Settings → Build → Connect →
their repository, branch `main`, deploy command `pnpm run deploy`. Open that page for them if you can,
and wait until they confirm.
## 5. A first post
Copy `posts/texts/_example.md` to `posts/texts/<today>-test.md`, set a time 3 minutes ahead (get the real
time with `curl -sI https://www.cloudflare.com | grep -i '^date'`, never the machine's clock), `status:
ready`, `visibility: CONNECTIONS`. Commit and push, wait for the build, then:
```bash
curl -H "Authorization: Bearer <ADMIN_TOKEN, typed by the user>" https://<worker>.workers.dev/status
```
With `DRY_RUN=1` it shows `posted` with a `dry-run` link. Ask the user whether to post for real; if yes,
redeploy with `DRY_RUN` at `0` (a normal push does it) and schedule a new test post with a new text.
## Done when
- `pnpm test` passes, the Worker answers `{"ok":true}` on `/`, and `/status` lists the test post.
- Pushes deploy through Workers Builds (the user saw a build succeed).
- The user knows: how to write a post (`docs/writing-posts.md`), that the token expires on the date they
noted and how to renew it (`docs/linkedin-setup.md#renew-the-token`), and where to look when something
fails (`docs/troubleshooting.md`).