mirror of
https://github.com/tiennm99/claude-code-routine-trigger.git
synced 2026-10-13 00:14:22 +00:00
6.3 KiB
6.3 KiB
phase, title, status, priority, effort, dependencies
| phase | title | status | priority | effort | dependencies | |
|---|---|---|---|---|---|---|
| 2 | Worker handler + fire client | completed | P1 | 2-3h |
|
Phase 2: Worker handler + fire client
Overview
Implement the scheduled handler in plain JS with JSDoc type annotations: render text template, POST to /fire, log structured JSON. Single worker.js file. No fetch handler (per locked decision: scheduled-only).
Requirements
- Functional:
- On cron tick, POSTs to
ROUTINE_FIRE_URLwith bearer token, beta header, JSON body. - Logs
claude_code_session_urlon 2xx; logs status + body on non-2xx; never throws (would crash CF retry). - Renders
TEXT_TEMPLATEwith{LocalTime},{Cron},{ISO}placeholders. - No retry (each
/fire= new session).
- On cron tick, POSTs to
- Non-functional:
- Token never logged.
- Use
console.log(JSON.stringify({...}))for structured logs (CF picks these up). - JSDoc
@typedef Envfor environment bindings +@param/@returnson all exports. - Total file ≤ 200 lines (split if exceeds).
Architecture
ScheduledEvent (cron, scheduledTime)
│
▼
fireRoutine(env, controller)
├── renderText(template, vars) # simple {Tok} substitution
├── fetch(URL, POST, headers, body)
└── log(json) # success or error
Mapping from Go daemon
| Go (claude-code-routine-cron) | JavaScript (this worker) |
|---|---|
Config.FireURL env |
env.ROUTINE_FIRE_URL secret |
Config.Token env |
env.ROUTINE_FIRE_TOKEN secret |
Config.Schedules env |
wrangler.toml [triggers].crons (literal) |
Config.Location (TZ) |
env.TZ plain var, default UTC |
Config.Template (Go text/template) |
env.TEXT_TEMPLATE plain string + {Tok} substitution |
FireClient.Fire() |
fireRoutine() function |
cron.New() scheduler |
CF Workers scheduled handler (built-in) |
slog JSON logs |
console.log(JSON.stringify(...)) |
JSDoc typedefs
/**
* @typedef {object} Env
* @property {string} ROUTINE_FIRE_URL - secret: Anthropic /fire endpoint
* @property {string} ROUTINE_FIRE_TOKEN - secret: per-routine bearer token
* @property {string} [TEXT_TEMPLATE] - plain var: prompt template, supports {LocalTime} {Cron} {ISO}
* @property {string} [TZ] - plain var: IANA tz, default 'UTC'
*/
/**
* @typedef {object} FireResponse
* @property {string} type
* @property {string} claude_code_session_id
* @property {string} claude_code_session_url
*/
Headers (verbatim from siblings)
Authorization: Bearer ${token}
anthropic-version: 2023-06-01
anthropic-beta: experimental-cc-routine-2026-04-01
Content-Type: application/json
Body
{ "text": "<rendered template>" }
Template substitution (KISS — not Go text/template)
| Token | Value |
|---|---|
{ISO} |
new Date(scheduledTime).toISOString() |
{LocalTime} |
formatted via Intl.DateTimeFormat(env.TZ ?? 'UTC') |
{Cron} |
controller.cron |
Default template: Scheduled trigger at {LocalTime} — same default as Go daemon.
Related Code Files
- Create:
worker.js(export default{ scheduled }, JSDoc-annotated) - (Optional split if >200 lines)
fire-client.js,template-renderer.js
Implementation Steps
- Top of
worker.js: write JSDoc@typedef Env+@typedef FireResponseblocks. - Implement
renderText(template, vars)with JSDoc:Replaces/** * @param {string} template * @param {Record<string, string>} vars * @returns {string} */{Key}tokens, leaves unknown tokens intact. - Implement
formatLocalTime(date, tz)usingIntl.DateTimeFormat. JSDoc:@param {Date} date,@param {string} tz,@returns {string}. - Implement
fireRoutine(env, controller)with JSDoc@param {Env} env,@param {ScheduledController} controller,@returns {Promise<void>}:- Build
textviarenderText. fetch(env.ROUTINE_FIRE_URL, { method: 'POST', headers, body: JSON.stringify({text}) }).- On
!response.ok:console.log(JSON.stringify({level:'error', cron, status, body})). - On
ok: parse JSON, log{level:'info', cron, session_url, session_id}. - Wrap in try/catch — log network errors, don't rethrow.
- Build
- Export default with JSDoc
@type {ExportedHandler<Env>}:/** @type {ExportedHandler<Env>} */ export default { async scheduled(controller, env, ctx) { ctx.waitUntil(fireRoutine(env, controller)); }, }; npx tsc --noEmit --allowJs --checkJs worker.js --target es2022 --module esnext --moduleResolution bundler --types @cloudflare/workers-types(one-shot smoke check; not added to scripts to avoid TS dependency creep). Optional — skip if undesired.- Local smoke:
wrangler dev --test-scheduled, thencurl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"— confirm log line.
Success Criteria
worker.js≤ 200 lines (split if needed)- All exported functions have JSDoc with
@param+@returns wrangler deploy --dry-runvalidates module- Token never appears in logged output (manual grep on
wrangler devoutput) - Local
__scheduledtest produces structured JSON log
Risk Assessment
Intl.DateTimeFormatTZ support on Workers runtime: supported since 2023; verify with smoke test.ctx.waitUntilvs awaiting inscheduled:waitUntilensures fire completes even if handler returns; preferred per CF docs.- No compile-time type errors: JSDoc + editor LSP catches most; runtime tests (phase 4) catch the rest.
- Template injection:
textis sent only to Anthropic API; no XSS / SQL surface — safe.
Security Considerations
- Token comes only from
env.ROUTINE_FIRE_TOKEN(CF Secret), never bundled. console.logbody must not includeAuthorizationheader value.- TLS to
api.anthropic.comis automatic (Workersfetchvalidates certs).