@crup/react-timer-hook 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -257,7 +257,7 @@ The default import stays small. Add the other pieces only when that screen needs
257
257
  | 📡 Schedules | `@crup/react-timer-hook/schedules` | Polling, cadence callbacks, overdue timing context | 8.62 kB | 3.02 kB | 2.78 kB |
258
258
  | 🧩 Duration | `@crup/react-timer-hook/duration` | `days`, `hours`, `minutes`, `seconds`, `milliseconds` | 318 B | 224 B | 192 B |
259
259
  | 🔎 Diagnostics | `@crup/react-timer-hook/diagnostics` | Optional lifecycle and schedule event logging | 105 B | 115 B | 90 B |
260
- | 🤖 MCP docs server | `react-timer-hook-mcp` | Optional local docs context for MCP clients and coding agents | 3.80 kB | 1.63 kB | 1.40 kB |
260
+ | 🤖 MCP docs server | `react-timer-hook-mcp` | Optional local docs context for MCP clients and coding agents | 6.69 kB | 2.60 kB | 2.25 kB |
261
261
 
262
262
  CI writes a size summary to the GitHub Actions UI and posts bundle-size reports on pull requests.
263
263
 
@@ -306,6 +306,14 @@ react-timer-hook://api
306
306
  react-timer-hook://recipes
307
307
  ```
308
308
 
309
+ It also exposes MCP tools that editors are more likely to call directly:
310
+
311
+ ```txt
312
+ get_api_docs
313
+ get_recipe
314
+ search_docs
315
+ ```
316
+
309
317
  ## Contributing
310
318
 
311
319
  Issues, recipes, docs improvements, and focused bug reports are welcome.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{createInterface as m}from"readline";import{readFileSync as p}from"fs";var n=f(),d=`# @crup/react-timer-hook
2
+ import{createInterface as w}from"readline";import{readFileSync as k}from"fs";var p=S(),l=`# @crup/react-timer-hook
3
3
 
4
4
  A lightweight React hooks library for building timers, stopwatches, and real-time clocks with minimal boilerplate.
5
5
 
@@ -38,7 +38,11 @@ Recipes:
38
38
  - OTP resend: disable the resend button until elapsedMilliseconds reaches the cooldown.
39
39
  - Polling: use schedules with overlap: "skip".
40
40
  - Many independent timers: use useTimerGroup().
41
- `,l={"react-timer-hook://package":{name:"Package",mimeType:"application/json",text:JSON.stringify({name:n.name,version:n.version,docs:"https://crup.github.io/react-timer-hook/",install:`npm install ${n.name}@latest`},null,2)},"react-timer-hook://api":{name:"API",mimeType:"text/markdown",text:d},"react-timer-hook://recipes":{name:"Recipes",mimeType:"text/markdown",text:["# Recipes","","- Countdown: derive remaining time with Math.max(0, expiresAt - timer.now).","- Stopwatch: render timer.elapsedMilliseconds.","- Clock: render new Date(timer.now) with user-owned formatting.","- Polling: import useScheduledTimer from @crup/react-timer-hook/schedules.","- Many timers: import useTimerGroup from @crup/react-timer-hook/group."].join(`
42
- `)}},h=m({input:process.stdin,output:process.stdout,terminal:!1});h.on("line",e=>{if(!e.trim())return;let t;try{t=JSON.parse(e)}catch{return}let{id:r,method:i,params:s}=t;if(i==="initialize"){c(r,{protocolVersion:"2024-11-05",serverInfo:{name:"react-timer-hook-docs",version:n.version},capabilities:{resources:{}}});return}if(i==="resources/list"){c(r,{resources:Object.entries(l).map(([o,a])=>({uri:o,name:a.name,mimeType:a.mimeType}))});return}if(i==="resources/read"){let o=l[s?.uri];if(!o){u(r,-32004,`Unknown resource: ${s?.uri??"missing uri"}`);return}c(r,{contents:[{uri:s.uri,mimeType:o.mimeType,text:o.text}]});return}u(r,-32601,`Method not found: ${i}`)});function c(e,t){process.stdout.write(`${JSON.stringify({jsonrpc:"2.0",id:e,result:t})}
43
- `)}function u(e,t,r){process.stdout.write(`${JSON.stringify({jsonrpc:"2.0",id:e,error:{code:t,message:r}})}
44
- `)}function f(){for(let e of["../../package.json","../package.json"])try{return JSON.parse(p(new URL(e,import.meta.url),"utf8"))}catch{}return{name:"@crup/react-timer-hook",version:"0.0.0"}}
41
+ `,f={"react-timer-hook://package":{name:"Package",mimeType:"application/json",text:JSON.stringify({name:p.name,version:p.version,docs:"https://crup.github.io/react-timer-hook/",install:`npm install ${p.name}@latest`},null,2)},"react-timer-hook://api":{name:"API",mimeType:"text/markdown",text:l},"react-timer-hook://recipes":{name:"Recipes",mimeType:"text/markdown",text:["# Recipes","","- Countdown: derive remaining time with Math.max(0, expiresAt - timer.now).","- Stopwatch: render timer.elapsedMilliseconds.","- Clock: render new Date(timer.now) with user-owned formatting.","- Polling: import useScheduledTimer from @crup/react-timer-hook/schedules.","- Many timers: import useTimerGroup from @crup/react-timer-hook/group."].join(`
42
+ `)}},m={"wall-clock":"Use useTimer({ autoStart: true }) and render new Date(timer.now). Keep locale and timezone formatting in userland.",stopwatch:"Use useTimer({ updateIntervalMs: 100 }). Render timer.elapsedMilliseconds and wire start, pause, resume, restart, and reset to buttons.","absolute-countdown":"Use timer.now for server deadlines: const remainingMs = Math.max(0, expiresAt - timer.now). Use endWhen: snapshot => snapshot.now >= expiresAt.","pausable-countdown":"Use timer.elapsedMilliseconds for active elapsed time: const remainingMs = durationMs - timer.elapsedMilliseconds. Paused time is excluded.","otp-resend":"Use a duration countdown. Disable the resend button while timer.isRunning and enable it after timer.isEnded or remainingMs <= 0.",polling:'Import useScheduledTimer from @crup/react-timer-hook/schedules. Add schedules: [{ id, everyMs, overlap: "skip", callback }].',"autosave-heartbeat":"Use useScheduledTimer with a schedule every 5000-15000ms. Keep retry/backoff and request state in app code.","timer-group":"Import useTimerGroup from @crup/react-timer-hook/group for many keyed timers that each need independent pause, resume, cancel, restart, or onEnd.","per-item-polling":"Use useTimerGroup with item schedules when each row needs independent polling cadence or cancel conditions.",diagnostics:"Import consoleTimerDiagnostics from @crup/react-timer-hook/diagnostics and pass diagnostics only while debugging."},y=[{name:"get_api_docs",description:"Return the compact API notes for @crup/react-timer-hook.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_recipe",description:"Return guidance for a named recipe or use case.",inputSchema:{type:"object",properties:{name:{type:"string",description:`Recipe name. Known values: ${Object.keys(m).join(", ")}.`}},required:["name"],additionalProperties:!1}},{name:"search_docs",description:"Search API and recipe notes for a query.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Search query such as countdown, polling, group, diagnostics, or OTP."}},required:["query"],additionalProperties:!1}}],b=w({input:process.stdin,output:process.stdout,terminal:!1});b.on("line",r=>{if(!r.trim())return;let t;try{t=JSON.parse(r)}catch{return}let{id:e,method:o,params:n}=t;if(o==="initialize"){u(e,{protocolVersion:"2024-11-05",serverInfo:{name:"react-timer-hook-docs",version:p.version},capabilities:{resources:{},tools:{}}});return}if(o==="resources/list"){u(e,{resources:Object.entries(f).map(([i,a])=>({uri:i,name:a.name,mimeType:a.mimeType}))});return}if(o==="resources/read"){let i=f[n?.uri];if(!i){c(e,-32004,`Unknown resource: ${n?.uri??"missing uri"}`);return}u(e,{contents:[{uri:n.uri,mimeType:i.mimeType,text:i.text}]});return}if(o==="tools/list"){u(e,{tools:y});return}if(o==="tools/call"){let i=n?.name,a=n?.arguments??{};if(i==="get_api_docs"){d(e,l);return}if(i==="get_recipe"){let s=m[T(a.name)];if(!s){c(e,-32602,`Unknown recipe: ${a.name??"missing name"}`);return}d(e,s);return}if(i==="search_docs"){let s=String(a.query??"").trim().toLowerCase();if(!s){c(e,-32602,"search_docs requires a non-empty query.");return}let h=[...g("api",{api:l},s),...g("recipe",m,s)];d(e,h.length>0?h.join(`
43
+
44
+ `):`No matches for "${s}".`);return}c(e,-32601,`Tool not found: ${i??"missing name"}`);return}c(e,-32601,`Method not found: ${o}`)});function u(r,t){process.stdout.write(`${JSON.stringify({jsonrpc:"2.0",id:r,result:t})}
45
+ `)}function d(r,t){u(r,{content:[{type:"text",text:t}]})}function c(r,t,e){process.stdout.write(`${JSON.stringify({jsonrpc:"2.0",id:r,error:{code:t,message:e}})}
46
+ `)}function T(r){return String(r??"").trim().toLowerCase().replace(/\s+/g,"-")}function g(r,t,e){return Object.entries(t).filter(([o,n])=>`${o}
47
+ ${n}`.toLowerCase().includes(e)).map(([o,n])=>`## ${r}: ${o}
48
+ ${n}`)}function S(){for(let r of["../../package.json","../package.json"])try{return JSON.parse(k(new URL(r,import.meta.url),"utf8"))}catch{}return{name:"@crup/react-timer-hook",version:"0.0.0"}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crup/react-timer-hook",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "A lightweight React hooks library for building timers, stopwatches, and real-time clocks with minimal boilerplate.",
5
5
  "homepage": "https://crup.github.io/react-timer-hook/",
6
6
  "repository": {