@canshift/core

中文文档
13.11.1发布于 2026/10/22UNLICENSEDTypeScriptES Module构建来源已验证近 30 天下载 2276

CANShift shared configuration domain types, schemas, and validation

原始使用文档
文档目录11 节
  1. Purpose
  2. Folder Structure
  3. Public API
  4. Schema Versioning & Migrations
  5. Shape changes (from the 1.24.0 floor)
  6. Validation
  7. Firmware Sync Requirement
  8. Installation In Consuming Projects
  9. Build & Test
  10. Conventions & Rules
  11. Connections To Other Projects

canshift-core

canshift-core — pure TypeScript contract layer for the CANShift ecosystem.

📖 Documentation — the config contract and the wire protocol versioning rule.


Purpose

canshift-core is the single source of truth for:

  • Configuration types — DashboardConfig, Widget discriminated union, PageConfig, TopBarConfig, ButtonAction, DeviceConfig, SignalConfig, InputBindingsConfig
  • Validation — runtime checks on dashboard, signal, and device configs
  • Schema migrations — versioned chain that brings older configs forward to CURRENT_SCHEMA_VERSION
  • Design tokens & widget metrics — DARK_TOKENS palette + tokensToCssVars consumed by the Tuner (canshift-tuner/, generated src/styles/tokens.generated.css), plus widget-metrics.ts (shared gauge/label/shift-light geometry mirrored by the firmware renderer) and theme-presets.ts (the 8 built-in dash themes)
  • Wire-format schemas — DeviceConfigWireSchema, InputBindingsConfigWireSchema, TrackTelemetrySchema, ScreenSettingsSchema, ECU profiles, hardware profiles

It is pure TypeScript with no Node.js, browser, or React Native APIs. Today it is consumed by canshift-tuner and canshift-mobile. Transport-shape types live in canshift-tuner/src/transport/ so core can stay browser/Node-neutral.

It does not contain:

  • Firmware C++ code (lives in canshift-firmware/)
  • UI components (live in canshift-tuner/src/)
  • Node or React Native specific APIs

Folder Structure

canshift-core/
└── src/
    ├── index.ts              # Package root — re-exports every entry plus the config contract
    ├── entries/              # One file per subpath export, re-exports only
    ├── schemas/              # Zod schemas — dashboard, widgets, signals, device, wire payloads
    ├── migrations/           # Shape-change steps from MIGRATION_FLOOR_VERSION to CURRENT_SCHEMA_VERSION
    ├── validation/           # validateDashboard
    ├── wire/                 # TELE, ALERT and CAN monitor binary frames, device commands, JSON envelope parsing
    ├── track/                # Lap crossing detection, start/finish line
    ├── widget-metrics/       # Dash geometry and colours the firmware renderer mirrors
    ├── design-tokens/        # Tuner CSS tokens
    ├── controls/             # Button control vocabulary
    ├── ecu-profiles/         # Built-in ECU signal catalogues, OBD-II PIDs and DTCs
    ├── can-xml/              # CAN XML import
    ├── board-profile/        # Board profile blob format
    ├── constants/            # FIRMWARE_CAPS, STRING_CAPS, dash signals
    ├── display-tiers.ts      # Read by the firmware parity script — do not move
    ├── layout-grid.ts        # Read by the firmware parity script — do not move
    ├── schema-version.ts     # Read by the firmware build — do not move
    └── __tests__/

constants/firmware-caps.ts, display-tiers.ts, layout-grid.ts and schema-version.ts are parsed by canshift-firmware's scripts from a sibling checkout, so those paths and their literal layout are part of the contract.


Public API

The root export carries everything a consumer imports. Subpaths carry a slice of it, so a bundler that does not tree-shake (Metro) loads only the modules behind the slice:

ImportWhat it holds
@canshift/coreEverything below, plus the dashboard config contract, validation, migrations
@canshift/core/wireTELE, ALERT and CAN monitor frames, device commands, STATUS / USB / timer payload parsers
@canshift/core/trackLap crossing detector, start/finish line, track telemetry schema
@canshift/core/widget-metricsDash geometry, severity, sensor ranges and danger bands, shift-light segments
@canshift/core/tokensTuner design tokens and their CSS variables
@canshift/core/ecu-profilesECU catalogues, MaxxECU units, OBD-II mode 01 PIDs and DTC decoding
@canshift/core/schema-versionCURRENT_SCHEMA_VERSION

An export no consumer imports is removed, not kept for later. Widget is a union discriminated on type: narrowing widget.type narrows widget.config, and WidgetOfType<'gauge'> names one member.


Schema Versioning & Migrations

Every config file carries a "version" field at the root:

{ "version": "1.41.0", ... }

CURRENT_SCHEMA_VERSION (src/schema-version.ts) is the version this code reads and writes. It follows semver:

  • MAJOR — breaking schema change, migration required
  • MINOR — additive change, backwards compatible
  • PATCH — documentation or comment change only

When loading a config, consumers must:

  1. Read version
  2. If version === CURRENT_SCHEMA_VERSION → load normally
  3. If version < CURRENT_SCHEMA_VERSION → run migrateConfig(config, CURRENT_SCHEMA_VERSION); a version older than MIGRATION_FLOOR_VERSION (1.24.0) throws a below_floor MigrationError
  4. If version > CURRENT_SCHEMA_VERSION → ask the user to update the app

The registry holds shape changes only. A release that only adds optional fields bumps CURRENT_SCHEMA_VERSION and needs no entry: migrateConfig runs every step between the file's version and the target in order, then sets the target version. Configs older than 1.24.0 no longer load (#151).

Shape changes (from the 1.24.0 floor)

StepChange
1.24.0 → 1.25.0Pixel layouts converted to 12-column grid spans, derived from the target screen profile
1.26.0 → 1.27.0Top-level widget type realigned with config.type
1.28.0 → 1.29.0Legacy flag top bar migrated to the track bar
1.29.0 → 1.30.0Gauge arcFillStyle dropped — spec-strict fills
1.30.0 → 1.31.0Button icon fields stripped — no icons on the dash
1.36.0 → 1.37.0Theme faces paired into theme.day / theme.night
1.39.0 → 1.40.0Gauge alertThreshold dropped — it armed nothing
1.42.0 → 1.43.0criticalAlert becomes the one-entry list criticalAlerts
1.43.0 → 1.44.0Strings cut to the firmware buffers (top bar text/format 15, ids 31), zOrder clamped

migrateConfig deep-clones the input before any migration runs (#282) so individual migrations can mutate freely without aliasing the caller's object.


Validation

Validation is Zod-backed (Zod is canshift-core's only runtime dependency). Each validator returns:

{ valid: boolean; errors: string[]; warnings: string[]; config?: T }

config is only present on the success branch and is the validated DashboardConfig (or equivalent) ready to consume.

validateDashboard covers:

  • Layout bounds against CANVAS and TOPBAR_HEIGHT
  • Hex colours against HexColorSchema
  • Signal-catalog references (every bound signal exists)
  • Duplicate widget IDs
  • Firmware caps from FIRMWARE_CAPS (max widgets per page, max pages, etc.)
  • Discriminated WidgetConfig.type exhaustiveness

The Vitest suite pins behaviour against the bundled dashboard.json fixture (#287) so regressions surface immediately when shape changes are introduced without a paired migration.


Firmware Sync Requirement

config_types.h in canshift-firmware/src/config/ mirrors these TypeScript types in C++. When changing DashboardConfig, PageConfig, WidgetConfig, or SignalDef:

  1. Update the TypeScript type here
  2. Bump CURRENT_SCHEMA_VERSION if the change is not purely additive
  3. Add a migration in migrations/migration-runner.ts and a corresponding test
  4. Update config_types.h in firmware to match
  5. Update config_loader.cpp in firmware to read the new field

Schema mismatches between firmware and core are detected at runtime so a stale firmware paired with a newer config logs a clear error rather than silently misreading bytes (#259). The firmware does not run the migration chain — only the Tuner migrates configs forward. Issue #1019 (A-COMPAT-1) tracks the firmware-side preflight that will reject mismatched pushes instead of degrading silently.


Installation In Consuming Projects

Install from npm:

npm install @canshift/core

Local development against an unpublished change: npm link from this repo, or a temporary file: override — never committed.


Build & Test

npm run build         # tsc → dist/
npm run lint          # eslint src
npm run format:check  # prettier --check src/**/*.ts
npm test              # Vitest

The Vitest suite under src/__tests__/ covers migrations, dashboard validation (full and end-to-end), signal validation, device validation, and the bundled fixture.


Conventions & Rules

  • Pure TypeScript — no Node, browser, or React Native APIs
  • Strict typing — no any; narrow unknown with type guards before use
  • Published entries only — consumers import from @canshift/core or one of its subpath exports; dist/ paths are not exported
  • Bump CURRENT_SCHEMA_VERSION whenever the DashboardConfig shape changes, and ship a paired migration in the same PR
  • Discriminated unions — WidgetConfig uses type as the discriminant; new widget kinds extend the union and the validator's exhaustive switch
  • Mirror C++ — every change here must be reflected in firmware config_types.h

Connections To Other Projects

  • canshift-tuner — the configurator; imports types, validators, migrations, widget metrics, theme presets, design tokens
  • canshift-firmware — config_types.h mirrors these types in C++; loaders read the same JSON shapes, and the renderer mirrors widget-metrics.ts / theme-presets.ts constants
  • canshift-mobile — consumes the same package directly when it needs config or telemetry types (BLE STATUS schema, screen-settings bounds, design tokens)

版本与发布记录

@canshift/core 共发布 63 个版本,首次发布于 2026/08/03;过去 12 个月发布了 63 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
13.11.1latest2026/10/2218 天前
13.11.02026/10/2119 天前
13.10.02026/10/2119 天前
13.9.02026/10/2119 天前
13.8.02026/10/2119 天前
13.7.02026/10/2119 天前

关于 @canshift/core 的常见问题

@canshift/core 是什么?

CANShift shared configuration domain types, schemas, and validation

如何安装 @canshift/core?

在项目目录运行 npm install @canshift/core,或使用 pnpm add / yarn add / bun add。

@canshift/core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@canshift/core 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@canshift/core 可以商用吗?

@canshift/core 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@canshift/core 的下载量有多少?

根据 npm 官方下载统计,@canshift/core 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,276 次,日均约 76 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@canshift/core 还在维护吗?

最新版本 13.11.1 发布于 2026/10/22(18 天前);至今共发布 63 个版本,其中过去 12 个月发布了 63 个;首次发布于 2026/08/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。