11import { createInterface } from 'node:readline' ;
22import { readFileSync } from 'node:fs' ;
33
4- const pkg = JSON . parse ( readFileSync ( new URL ( '../package.json' , import . meta. url ) , 'utf8' ) ) ;
4+ const pkg = readPackage ( ) ;
5+ const apiText = `# @crup/react-timer-hook
6+
7+ A lightweight React hooks library for building timers, stopwatches, and real-time clocks with minimal boilerplate.
8+
9+ Docs: https://crup.github.io/react-timer-hook/
10+ Package: @crup/react-timer-hook
11+ Install: npm install @crup/react-timer-hook@latest
12+ Runtime: Node 18+ and React 18+
13+ Repository: https://github.com/crup/react-timer-hook
14+
15+ Public exports:
16+ - @crup/react-timer-hook: useTimer(options) for one timer lifecycle.
17+ - @crup/react-timer-hook/group: useTimerGroup(options) for many keyed independent lifecycles with one shared scheduler.
18+ - @crup/react-timer-hook/schedules: useScheduledTimer(options) for schedule-enabled timers with timing context.
19+ - @crup/react-timer-hook/duration: durationParts(milliseconds) for duration display helper values.
20+ - @crup/react-timer-hook/diagnostics: consoleTimerDiagnostics(options) for optional event logging.
21+
22+ Core rules:
23+ - Use timer.now for wall-clock deadlines and clocks.
24+ - Use timer.elapsedMilliseconds for active elapsed duration.
25+ - Use endWhen(snapshot) to end a lifecycle.
26+ - Use onError(error, snapshot, controls) when onEnd can throw or reject.
27+ - Use cancel(reason) for terminal early stops.
28+ - Keep formatting, timezone, retries, and business rules in userland.
29+
30+ Schedules:
31+ - Use useScheduledTimer() from @crup/react-timer-hook/schedules.
32+ - Schedules are opt-in and default to overlap: "skip".
33+ - Schedule callbacks receive context with scheduledAt, firedAt, nextRunAt, overdueCount, and effectiveEveryMs.
34+ - Schedule callbacks can define onError(error, snapshot, controls, context); otherwise timer or item onError is used.
35+
36+ Recipes:
37+ - Wall clock: new Date(timer.now).
38+ - Stopwatch: render timer.elapsedMilliseconds.
39+ - Absolute countdown: Math.max(0, expiresAt - timer.now).
40+ - Pausable countdown: durationMs - timer.elapsedMilliseconds.
41+ - OTP resend: disable the resend button until elapsedMilliseconds reaches the cooldown.
42+ - Polling: use schedules with overlap: "skip".
43+ - Many independent timers: use useTimerGroup().
44+ ` ;
545
646const resources = {
747 'react-timer-hook://package' : {
@@ -12,7 +52,7 @@ const resources = {
1252 name : pkg . name ,
1353 version : pkg . version ,
1454 docs : 'https://crup.github.io/react-timer-hook/' ,
15- install : `npm install ${ pkg . name } @alpha ` ,
55+ install : `npm install ${ pkg . name } @latest ` ,
1656 } ,
1757 null ,
1858 2 ,
@@ -21,7 +61,7 @@ const resources = {
2161 'react-timer-hook://api' : {
2262 name : 'API' ,
2363 mimeType : 'text/markdown' ,
24- text : readFileSync ( new URL ( '../docs-site/static/llms-full.txt' , import . meta . url ) , 'utf8' ) ,
64+ text : apiText ,
2565 } ,
2666 'react-timer-hook://recipes' : {
2767 name : 'Recipes' ,
@@ -101,3 +141,15 @@ function respond(id, result) {
101141function respondError ( id , code , message ) {
102142 process . stdout . write ( `${ JSON . stringify ( { jsonrpc : '2.0' , id, error : { code, message } } ) } \n` ) ;
103143}
144+
145+ function readPackage ( ) {
146+ for ( const path of [ '../../package.json' , '../package.json' ] ) {
147+ try {
148+ return JSON . parse ( readFileSync ( new URL ( path , import . meta. url ) , 'utf8' ) ) ;
149+ } catch {
150+ // Try the next path. The bundled file runs from dist/mcp, while the source file runs from mcp.
151+ }
152+ }
153+
154+ return { name : '@crup/react-timer-hook' , version : '0.0.0' } ;
155+ }
0 commit comments