npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kaiord/core

v4.5.2

Published

Core library for the Kaiord health & fitness data framework

Downloads

1,102

Readme

@kaiord/core

npm version License: MIT Build Status

Core library for the Kaiord health & fitness data framework. Contains domain types, schemas, ports, use cases, and the plugin architecture for format adapters.

Note: As of v2.0, format adapters (FIT, TCX, ZWO) are in separate packages. Install only the adapters you need for optimal bundle size.

Features

  • KRD canonical format with Zod schema validation
  • Hexagonal architecture with ports and adapters pattern
  • Plugin architecture for format adapters
  • Full TypeScript support with type inference
  • Custom logger injection
  • Tree-shakeable ESM bundle

Installation

npm install @kaiord/core

or with pnpm:

pnpm add @kaiord/core

or with yarn:

yarn add @kaiord/core

Quick Start

Single Format

import { createDefaultProviders } from "@kaiord/core";
import { createFitProviders } from "@kaiord/fit";
import type { KRD } from "@kaiord/core";
import { readFile } from "fs/promises";

// Wire FIT adapter into core
const providers = createDefaultProviders({
  fit: createFitProviders(),
});

// Convert FIT to KRD
const fitBuffer = await readFile("workout.fit");
const krd: KRD = await providers.convertFitToKrd!({ fitBuffer });

// Convert KRD to FIT
const output = await providers.convertKrdToFit!({ krd });

Multiple Formats

import { createDefaultProviders } from "@kaiord/core";
import { createFitProviders } from "@kaiord/fit";
import { createTcxProviders } from "@kaiord/tcx";
import { createZwoProviders } from "@kaiord/zwo";

// Wire all adapters you need
const providers = createDefaultProviders({
  fit: createFitProviders(),
  tcx: createTcxProviders(),
  zwo: createZwoProviders(),
});

// Convert between formats
const krd = await providers.convertFitToKrd!({ fitBuffer });
const tcx = await providers.convertKrdToTcx!({ krd });
const zwo = await providers.convertKrdToZwift!({ krd });

Schema Validation

import { krdSchema } from "@kaiord/core";

// Validate KRD data
const result = krdSchema.safeParse(data);

if (result.success) {
  console.log("Valid KRD:", result.data);
} else {
  console.error("Validation errors:", result.error.errors);
}

API Overview

Main Functions

createDefaultProviders(adapters?, logger?)

Creates a provider container with optional format adapters wired in.

import { createDefaultProviders } from "@kaiord/core";
import { createFitProviders } from "@kaiord/fit";
import { createTcxProviders } from "@kaiord/tcx";

const providers = createDefaultProviders({
  fit: createFitProviders(),
  tcx: createTcxProviders(),
});
// Returns: { schemaValidator, toleranceChecker, logger, convertFitToKrd, ... }

convertFitToKrd({ fitBuffer })

Converts a FIT workout file to KRD format.

const krd = await providers.convertFitToKrd({ fitBuffer });

Parameters:

  • fitBuffer: Uint8Array - Binary FIT file data

Returns: Promise<KRD> - Validated KRD object

Throws:

  • FitParsingError - When FIT file is corrupted or invalid
  • KrdValidationError - When converted data fails schema validation

convertKrdToFit({ krd })

Converts a KRD object to FIT workout file format.

const fitBuffer = await providers.convertKrdToFit({ krd });

Parameters:

  • krd: KRD - Valid KRD object

Returns: Promise<Uint8Array> - Binary FIT file data

Throws:

  • KrdValidationError - When KRD data is invalid
  • FitParsingError - When FIT encoding fails

validateRoundTrip({ fitBuffer })

Validates that FIT → KRD → FIT conversion preserves data within tolerances.

import { validateRoundTrip, createToleranceChecker } from "@kaiord/core";

const checker = createToleranceChecker();
await validateRoundTrip(
  fitReader,
  fitWriter,
  validator,
  checker,
  logger
)({
  fitBuffer,
});

Throws:

  • ToleranceExceededError - When round-trip conversion exceeds tolerances

Schema Exports

All domain schemas are exported for validation and type inference:

import {
  krdSchema,
  workoutSchema,
  durationSchema,
  targetSchema,
  sportSchema,
  subSportSchema,
  intensitySchema,
} from "@kaiord/core";

// Validate data
const result = krdSchema.safeParse(data);

// Access enum values
const sport = sportSchema.enum.cycling;
const intensity = intensitySchema.enum.warmup;

Type Exports

All TypeScript types are inferred from Zod schemas:

import type {
  KRD,
  Workout,
  WorkoutStep,
  Duration,
  Target,
  Sport,
  SubSport,
  Intensity,
} from "@kaiord/core";

Error Types

import {
  FitParsingError,
  KrdValidationError,
  ToleranceExceededError,
} from "@kaiord/core";

For detailed API examples, see docs/api-examples.md (coming soon).

TypeScript Support

@kaiord/core is written in TypeScript and provides complete type definitions.

Type Imports

Import types separately from values for optimal tree-shaking:

import { createDefaultProviders, krdSchema } from "@kaiord/core";
import type { KRD, Workout, Duration } from "@kaiord/core";

Discriminated Unions

Duration and Target types use discriminated unions for type safety:

import type { Duration } from "@kaiord/core";

const duration: Duration =
  | { type: "time"; seconds: number }
  | { type: "distance"; meters: number }
  | { type: "open" };

// TypeScript narrows the type based on discriminator
if (duration.type === "time") {
  console.log(duration.seconds); // ✓ TypeScript knows this exists
}
import type { Target } from "@kaiord/core";

const target: Target =
  | { type: "power"; value: { unit: "watts"; value: number } }
  | { type: "heart_rate"; value: { unit: "bpm"; value: number } }
  | { type: "open" };

// Type narrowing works automatically
if (target.type === "power") {
  console.log(target.value.unit); // ✓ "watts" | "percent_ftp" | "zone" | "range"
}

Schema Validation with Type Inference

Zod schemas provide both runtime validation and TypeScript types:

import { krdSchema, workoutSchema } from "@kaiord/core";
import type { KRD, Workout } from "@kaiord/core";

// Parse with automatic type inference
const krd = krdSchema.parse(data); // Type: KRD

// Safe parse with error handling
const result = krdSchema.safeParse(data);
if (result.success) {
  const krd: KRD = result.data; // Type: KRD
} else {
  console.error(result.error.errors);
}

// Validate nested objects
const workout = workoutSchema.parse(data); // Type: Workout

Enum Values

Access enum values via schema .enum property:

import { sportSchema, intensitySchema } from "@kaiord/core";

// Access enum values
const sport = sportSchema.enum.cycling; // "cycling"
const intensity = intensitySchema.enum.warmup; // "warmup"

// Use in comparisons
if (workout.sport === sportSchema.enum.running) {
  console.log("Running workout");
}

Error Handling

@kaiord/core uses custom error classes for different failure scenarios.

Error Types

FitParsingError

Thrown when FIT file parsing fails due to corrupted or invalid data.

import { FitParsingError } from "@kaiord/core";

try {
  const krd = await providers.convertFitToKrd({ fitBuffer });
} catch (error) {
  if (error instanceof FitParsingError) {
    console.error("Failed to parse FIT file:", error.message);
    console.error("Original error:", error.cause);
  }
}

Properties:

  • message: string - Error description
  • cause?: unknown - Original error from FIT SDK

KrdValidationError

Thrown when KRD data fails schema validation.

import { KrdValidationError } from "@kaiord/core";

try {
  const krd = await providers.convertFitToKrd({ fitBuffer });
} catch (error) {
  if (error instanceof KrdValidationError) {
    console.error("KRD validation failed:");
    for (const err of error.errors) {
      console.error(`  - ${err.field}: ${err.message}`);
    }
  }
}

Properties:

  • message: string - Error description
  • errors: Array<{ field: string; message: string }> - Validation errors

ToleranceExceededError

Thrown when round-trip conversion exceeds defined tolerances.

import { ToleranceExceededError } from "@kaiord/core";

try {
  await validateRoundTrip(
    fitReader,
    fitWriter,
    validator,
    checker,
    logger
  )({
    fitBuffer,
  });
} catch (error) {
  if (error instanceof ToleranceExceededError) {
    console.error("Round-trip validation failed:");
    for (const violation of error.violations) {
      console.error(
        `  - ${violation.field}: expected ${violation.expected}, got ${violation.actual}`
      );
      console.error(
        `    Deviation: ${violation.deviation}, tolerance: ${violation.tolerance}`
      );
    }
  }
}

Properties:

  • message: string - Error description
  • violations: Array<{ field: string; expected: number; actual: number; deviation: number; tolerance: number }> - Tolerance violations

Complete Error Handling Example

import {
  createDefaultProviders,
  FitParsingError,
  KrdValidationError,
  ToleranceExceededError,
} from "@kaiord/core";

async function convertWorkout(fitBuffer: Uint8Array) {
  try {
    const providers = createDefaultProviders();
    const krd = await providers.convertFitToKrd({ fitBuffer });
    return krd;
  } catch (error) {
    if (error instanceof FitParsingError) {
      console.error("❌ FIT parsing failed:", error.message);
      if (error.cause) {
        console.error("   Cause:", error.cause);
      }
      throw new Error("Invalid FIT file");
    }

    if (error instanceof KrdValidationError) {
      console.error("❌ KRD validation failed:");
      for (const err of error.errors) {
        console.error(`   - ${err.field}: ${err.message}`);
      }
      throw new Error("Conversion produced invalid KRD");
    }

    // Unknown error - re-throw
    throw error;
  }
}

Documentation

Main Documentation

Package-Specific Documentation

Contributing

We welcome contributions! Please see:

Before contributing:

  1. Read the Architecture documentation
  2. Follow the Testing guidelines
  3. Ensure all tests pass: pnpm test
  4. Run linter: pnpm lint

Scripts

pnpm build                  # Build the library
pnpm test                   # Run tests once
pnpm test:watch             # Run tests in watch mode
pnpm test:coverage          # Run tests with coverage report
pnpm generate:schema        # Generate JSON Schema from Zod schemas
pnpm generate:krd-fixtures  # Generate KRD test fixtures from FIT files
pnpm clean                  # Clean build artifacts

Tree-Shaking

@kaiord/core is fully optimized for tree-shaking. Import only what you need:

// ✅ Good: Import specific items (smaller bundle)
import { krdSchema, sportSchema } from "@kaiord/core";
import type { KRD, Sport } from "@kaiord/core";

// Test utilities (separate export, not included in main bundle)
import { loadKrdFixture } from "@kaiord/core/test-utils";

// ❌ Avoid: Import everything (larger bundle)
import * as Kaiord from "@kaiord/core";

Bundle sizes (minified + gzipped):

  • Types only: 0 KB (compile-time)
  • Schema validation: ~15 KB
  • Full conversion: ~80 KB
  • Test utilities: Not included in production bundles

See docs/tree-shaking.md for detailed guide and best practices.

Test Utilities

The package exports test utilities for other packages to use:

import {
  loadFitFixture,
  loadKrdFixture,
  loadFixturePair,
  FIXTURE_NAMES,
} from "@kaiord/core/test-utils";

// Load fixtures for testing
const fitBuffer = loadFitFixture("WorkoutIndividualSteps.fit");
const krd = loadKrdFixture("WorkoutIndividualSteps.krd");

// Load both for round-trip tests
const { fit, krd } = loadFixturePair(FIXTURE_NAMES.INDIVIDUAL_STEPS);

See docs/krd-fixtures-generation.md for details on fixture generation.