
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
@kaiord/core
Advanced tools
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.
npm install @kaiord/core
or with pnpm:
pnpm add @kaiord/core
or with yarn:
yarn add @kaiord/core
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 });
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 });
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);
}
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 dataReturns: Promise<KRD> - Validated KRD object
Throws:
FitParsingError - When FIT file is corrupted or invalidKrdValidationError - When converted data fails schema validationconvertKrdToFit({ krd })Converts a KRD object to FIT workout file format.
const fitBuffer = await providers.convertKrdToFit({ krd });
Parameters:
krd: KRD - Valid KRD objectReturns: Promise<Uint8Array> - Binary FIT file data
Throws:
KrdValidationError - When KRD data is invalidFitParsingError - When FIT encoding failsvalidateRoundTrip({ 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 tolerancesAll 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;
All TypeScript types are inferred from Zod schemas:
import type {
KRD,
Workout,
WorkoutStep,
Duration,
Target,
Sport,
SubSport,
Intensity,
} from "@kaiord/core";
import {
FitParsingError,
KrdValidationError,
ToleranceExceededError,
} from "@kaiord/core";
For detailed API examples, see docs/api-examples.md (coming soon).
@kaiord/core is written in TypeScript and provides complete type definitions.
Import types separately from values for optimal tree-shaking:
import { createDefaultProviders, krdSchema } from "@kaiord/core";
import type { KRD, Workout, Duration } from "@kaiord/core";
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"
}
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
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");
}
@kaiord/core uses custom error classes for different failure scenarios.
FitParsingErrorThrown 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 descriptioncause?: unknown - Original error from FIT SDKKrdValidationErrorThrown 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 descriptionerrors: Array<{ field: string; message: string }> - Validation errorsToleranceExceededErrorThrown 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 descriptionviolations: Array<{ field: string; expected: number; actual: number; deviation: number; tolerance: number }> - Tolerance violationsimport {
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;
}
}
We welcome contributions! Please see:
Before contributing:
pnpm testpnpm lintpnpm 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
@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):
See docs/tree-shaking.md for detailed guide and best practices.
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.
FAQs
Core library for the Kaiord health & fitness data framework
The npm package @kaiord/core receives a total of 240 weekly downloads. As such, @kaiord/core popularity was classified as not popular.
We found that @kaiord/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.