{"id":37322761,"url":"https://github.com/paladini/node-intervals-icu","last_synced_at":"2026-01-16T03:24:03.230Z","repository":{"id":328395955,"uuid":"1114217060","full_name":"paladini/node-intervals-icu","owner":"paladini","description":"A lightweight TypeScript / Javascript client library for the Intervals.icu API.","archived":false,"fork":false,"pushed_at":"2026-01-12T19:12:22.000Z","size":214,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T00:41:47.828Z","etag":null,"topics":["intervals","intervals-icu"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/intervals-icu","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paladini.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-11T04:13:45.000Z","updated_at":"2026-01-12T19:12:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/paladini/node-intervals-icu","commit_stats":null,"previous_names":["paladini/node-intervals-icu"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/paladini/node-intervals-icu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paladini%2Fnode-intervals-icu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paladini%2Fnode-intervals-icu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paladini%2Fnode-intervals-icu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paladini%2Fnode-intervals-icu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paladini","download_url":"https://codeload.github.com/paladini/node-intervals-icu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paladini%2Fnode-intervals-icu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T03:13:13.607Z","status":"ssl_error","status_checked_at":"2026-01-16T03:11:47.863Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["intervals","intervals-icu"],"created_at":"2026-01-16T03:24:02.697Z","updated_at":"2026-01-16T03:24:03.207Z","avatar_url":"https://github.com/paladini.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# intervals-icu\n\nA lightweight TypeScript client library for the [Intervals.icu](https://intervals.icu) API. Supports all major endpoints including athletes, events, wellness, workouts, and activities.\n\n## Features\n\n- 🚀 **Lightweight** - Zero dependencies beyond axios\n- 📘 **Fully Typed** - Written in TypeScript with comprehensive type definitions\n- 🌳 **Tree-shakeable** - ESM exports for optimal bundle size\n- 🔐 **Authentication** - Built-in support for API key authentication\n- ⚡ **Rate Limiting Awareness** - Tracks and exposes rate limit information\n- 🛡️ **Error Handling** - Robust error handling with custom error types\n- 📖 **Well Documented** - JSDoc comments on all public methods\n\n## Installation\n\n```bash\nnpm install intervals-icu\n```\n\n## Quick Start\n\n```typescript\nimport { IntervalsClient } from 'intervals-icu';\n\n// Initialize the client\nconst client = new IntervalsClient({\n  apiKey: 'your-api-key-here',\n  athleteId: 'i12345' // optional, defaults to 'me'\n});\n\n// Get athlete information\nconst athlete = await client.getAthlete();\nconsole.log(`Athlete: ${athlete.name}, FTP: ${athlete.ftp}`);\n\n// Get events\nconst events = await client.getEvents({\n  oldest: '2024-01-01',\n  newest: '2024-12-31'\n});\n\n// Create a wellness entry\nawait client.createWellness({\n  date: '2024-01-15',\n  weight: 70,\n  restingHR: 50,\n  sleepSecs: 28800\n});\n```\n\n## API Reference\n\n### Client Configuration\n\n```typescript\ninterface IntervalsConfig {\n  apiKey: string;        // Required: Your Intervals.icu API key\n  athleteId?: string;    // Optional: Athlete ID (defaults to 'me')\n  baseURL?: string;      // Optional: API base URL\n  timeout?: number;      // Optional: Request timeout in ms (default: 10000)\n}\n```\n\n### Athlete Methods\n\n#### `getAthlete(athleteId?: string): Promise\u003cAthlete\u003e`\n\nGet athlete information.\n\n```typescript\nconst athlete = await client.getAthlete();\nconsole.log(athlete.name, athlete.ftp, athlete.weight);\n```\n\n#### `updateAthlete(data: Partial\u003cAthlete\u003e, athleteId?: string): Promise\u003cAthlete\u003e`\n\nUpdate athlete information.\n\n```typescript\nconst updated = await client.updateAthlete({\n  ftp: 250,\n  weight: 70\n});\n```\n\n### Event Methods\n\n#### `getEvents(options?: PaginationOptions, athleteId?: string): Promise\u003cEvent[]\u003e`\n\nGet calendar events.\n\n```typescript\nconst events = await client.getEvents({\n  oldest: '2024-01-01',\n  newest: '2024-12-31'\n});\n```\n\n#### `getEvent(eventId: number, athleteId?: string): Promise\u003cEvent\u003e`\n\nGet a specific event by ID.\n\n```typescript\nconst event = await client.getEvent(12345);\n```\n\n#### `createEvent(data: EventInput, athleteId?: string): Promise\u003cEvent\u003e`\n\nCreate a new calendar event.\n\n```typescript\nconst event = await client.createEvent({\n  start_date_local: '2024-01-15',\n  name: 'Race Day',\n  category: 'RACE',\n  description: 'Important race'\n});\n```\n\n#### `updateEvent(eventId: number, data: Partial\u003cEventInput\u003e, athleteId?: string): Promise\u003cEvent\u003e`\n\nUpdate an existing event.\n\n```typescript\nawait client.updateEvent(12345, {\n  name: 'Updated Race Day'\n});\n```\n\n#### `deleteEvent(eventId: number, athleteId?: string): Promise\u003cvoid\u003e`\n\nDelete an event.\n\n```typescript\nawait client.deleteEvent(12345);\n```\n\n#### Filtering Events by Type\n\nEvents now include a `type` field that allows you to reliably differentiate between different event types (Run, Ride, Swim, Strength, etc.) without relying on name patterns:\n\n```typescript\n// Get all events\nconst allEvents = await client.getEvents({\n  oldest: '2024-01-01',\n  newest: '2024-12-31'\n});\n\n// Filter only running events\nconst runEvents = allEvents.filter(event =\u003e event.type === 'Run');\n\n// Filter only cycling events\nconst rideEvents = allEvents.filter(event =\u003e event.type === 'Ride');\n\n// Filter only swimming events\nconst swimEvents = allEvents.filter(event =\u003e event.type === 'Swim');\n\n// Filter only strength training events\nconst strengthEvents = allEvents.filter(event =\u003e event.type === 'Strength');\n\n// Find a specific running workout\nconst runWorkout = allEvents.find(e =\u003e \n  e.category === 'WORKOUT' \u0026\u0026 e.type === 'Run'\n);\n```\n\nThis approach is:\n- ✅ Reliable and type-safe\n- ✅ Language-agnostic (works with any language/locale)\n- ✅ More maintainable than name-based pattern matching\n\n### Wellness Methods\n\n#### `getWellness(options?: PaginationOptions, athleteId?: string): Promise\u003cWellness[]\u003e`\n\nGet wellness data.\n\n```typescript\nconst wellness = await client.getWellness({\n  oldest: '2024-01-01',\n  newest: '2024-01-31'\n});\n```\n\n#### `createWellness(data: WellnessInput, athleteId?: string): Promise\u003cWellness\u003e`\n\nCreate a new wellness entry.\n\n```typescript\nconst wellness = await client.createWellness({\n  date: '2024-01-15',\n  weight: 70,\n  restingHR: 50,\n  hrv: 65,\n  sleepSecs: 28800,\n  sleepQuality: 8\n});\n```\n\n#### `updateWellness(date: string, data: Partial\u003cWellnessInput\u003e, athleteId?: string): Promise\u003cWellness\u003e`\n\nUpdate a wellness entry for a specific date.\n\n```typescript\nawait client.updateWellness('2024-01-15', {\n  weight: 69.5,\n  mood: 8\n});\n```\n\n#### `deleteWellness(date: string, athleteId?: string): Promise\u003cvoid\u003e`\n\nDelete a wellness entry.\n\n```typescript\nawait client.deleteWellness('2024-01-15');\n```\n\n### Workout Methods\n\n#### `getWorkouts(options?: PaginationOptions, athleteId?: string): Promise\u003cWorkout[]\u003e`\n\nGet planned workouts.\n\n```typescript\nconst workouts = await client.getWorkouts({\n  oldest: '2024-01-01',\n  newest: '2024-01-31'\n});\n```\n\n#### `getWorkout(workoutId: number, athleteId?: string): Promise\u003cWorkout\u003e`\n\nGet a specific workout by ID.\n\n```typescript\nconst workout = await client.getWorkout(12345);\n```\n\n#### `createWorkout(data: WorkoutInput, athleteId?: string): Promise\u003cWorkout\u003e`\n\nCreate a new workout.\n\n```typescript\nconst workout = await client.createWorkout({\n  start_date_local: '2024-01-15',\n  name: 'Tempo Run',\n  description: '45 min tempo at threshold',\n  duration_secs: 2700,\n  tss: 65\n});\n```\n\n#### `updateWorkout(workoutId: number, data: Partial\u003cWorkoutInput\u003e, athleteId?: string): Promise\u003cWorkout\u003e`\n\nUpdate an existing workout.\n\n```typescript\nawait client.updateWorkout(12345, {\n  name: 'Updated Tempo Run',\n  tss: 70\n});\n```\n\n#### `deleteWorkout(workoutId: number, athleteId?: string): Promise\u003cvoid\u003e`\n\nDelete a workout.\n\n```typescript\nawait client.deleteWorkout(12345);\n```\n\n### Activity Methods\n\n#### `getActivities(options?: PaginationOptions, athleteId?: string): Promise\u003cActivity[]\u003e`\n\nGet recorded activities.\n\n```typescript\nconst activities = await client.getActivities({\n  oldest: '2024-01-01',\n  newest: '2024-01-31'\n});\n```\n\n#### `getActivity(activityId: number, athleteId?: string): Promise\u003cActivity\u003e`\n\nGet a specific activity by ID.\n\n```typescript\nconst activity = await client.getActivity(12345);\n```\n\n#### `updateActivity(activityId: number, data: ActivityInput, athleteId?: string): Promise\u003cActivity\u003e`\n\nUpdate an existing activity.\n\n```typescript\nawait client.updateActivity(12345, {\n  name: 'Morning Run',\n  description: 'Easy recovery run',\n  feel: 8\n});\n```\n\n#### `deleteActivity(activityId: number, athleteId?: string): Promise\u003cvoid\u003e`\n\nDelete an activity.\n\n```typescript\nawait client.deleteActivity(12345);\n```\n\n## Rate Limiting\n\nThe client automatically tracks rate limit information from the API responses:\n\n```typescript\n// Make some API calls\nawait client.getAthlete();\n\n// Check rate limit status\nconst remaining = client.getRateLimitRemaining();\nconst resetTime = client.getRateLimitReset();\n\nconsole.log(`Remaining: ${remaining}, Resets at: ${resetTime}`);\n```\n\n## Error Handling\n\nThe client throws `IntervalsAPIError` for all API-related errors:\n\n```typescript\nimport { IntervalsClient, IntervalsAPIError } from 'intervals-icu';\n\ntry {\n  const athlete = await client.getAthlete();\n} catch (error) {\n  if (error instanceof IntervalsAPIError) {\n    console.error(`API Error: ${error.message}`);\n    console.error(`Status: ${error.status}`);\n    console.error(`Code: ${error.code}`);\n    \n    // Handle specific error types\n    if (error.code === 'RATE_LIMIT_EXCEEDED') {\n      console.error('Rate limit exceeded, try again later');\n    } else if (error.code === 'AUTH_FAILED') {\n      console.error('Invalid API key');\n    }\n  }\n}\n```\n\n## TypeScript Support\n\nAll methods and responses are fully typed. Import types as needed:\n\n```typescript\nimport type {\n  Athlete,\n  Event,\n  Wellness,\n  Workout,\n  Activity,\n  PaginationOptions,\n  IntervalsConfig\n} from 'node-intervals-icu';\n```\n\n## Authentication\n\nTo get your API key:\n\n1. Log in to [Intervals.icu](https://intervals.icu)\n2. Go to Settings → API Key\n3. Copy your API key\n\nYour athlete ID can be found in the URL when viewing your profile (e.g., `i12345`), or you can use `'me'` to refer to the authenticated athlete.\n\n## License\n\nMIT License - Copyright (c) 2025 Fernando Paladini\n\nSee the [LICENSE](./LICENSE) file for details.\n\n## Acknowledgments\n\nSpecial thanks to Filipe for the inspiration and the initial idea that led to the creation of this library. Your project was the spark that made this happen! 🙏\n\n## Contributing\n\nContributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) to learn how you can help make this project better.\n\n## Publishing\n\nFor maintainers: See the [Publishing Guide](./docs/PUBLISHING.md) for detailed instructions on publishing this library to NPM.\n\n## Links\n\n- [Intervals.icu API Documentation](https://intervals.icu/api/v1/docs)\n- [Intervals.icu Website](https://intervals.icu)\n- [GitHub Repository](https://github.com/paladini/intervals-icu)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaladini%2Fnode-intervals-icu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaladini%2Fnode-intervals-icu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaladini%2Fnode-intervals-icu/lists"}