Drop Protobuf; move continuum/v1 domain model to JSON Schema

Nothing imported the proto-generated code (zero references to
continuum-rust-types or @continuum/ts-types's proto export in any
consumer repo), and protobuf's real value - one schema compiled to a
compact binary wire format for both languages - never applied: BE<->proxy
and FE<->BE are both JSON. Also fixes 8 broken $ref paths in the bambulab
schemas and a root tsconfig.json that was sweeping the gitignored
examples/ directory into typecheck.

- proto/continuum/v1/*.proto -> schemas/continuum/v1/*.schema.json
- packages/rust-types: hand-written serde structs instead of
  prost-build codegen
- packages/ts-types: drop the generated/ proto barrel export, keep the
  hand-written TypeBox schemas as the TS source of truth
- root package.json: drop build:ts, protoc, ts-proto
This commit is contained in:
2026-09-05 14:56:24 +00:00
parent 8bdade66c2
commit 952b5e1eca
20 changed files with 233 additions and 199 deletions
+76 -42
View File
@@ -1,46 +1,80 @@
pub mod continuum {
pub mod v1 {
include!(concat!(env!("OUT_DIR"), "/continuum.v1.rs"));
}
// Hand-written structs mirroring the JSON Schemas in `schemas/continuum/v1/`
// and the TypeBox schemas in `ts-types/src/schemas/` - this used to be
// prost-generated from `.proto` sources, but nothing here needed protobuf's
// actual value (cross-language binary codegen): both consumers (this crate
// and ts-types) only ever exchange JSON, so a hand-synced struct is less
// machinery than a `protoc`/`prost-build` pipeline for the same three
// flat DTOs. Keep field names and the `PrintJobStatus` string values in
// sync with `ts-types/src/schemas/` by hand when either side changes.
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MaterialProfile {
pub id: String,
pub name: String,
pub filament_type: String,
pub nozzle_temp_c: f64,
pub bed_temp_c: f64,
pub density_g_cm3: f64,
pub color_hex: String,
}
pub use continuum::v1::{
MaterialProfile, PrintJob, PrintJobStatus, PrintParameters, Template,
};
// PrintJob.status is generated as a plain i32 (see build.rs's comment) -
// (de)serialize it via PrintJobStatus's full proto name strings
// (e.g. "PRINT_JOB_STATUS_QUEUED") so Rust's JSON matches ts-types'
// TypeBox schema and protobuf's own canonical JSON enum mapping.
mod print_job_status_serde {
use super::PrintJobStatus;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S: Serializer>(value: &i32, serializer: S) -> Result<S::Ok, S::Error> {
let status = PrintJobStatus::try_from(*value).unwrap_or(PrintJobStatus::Unspecified);
status.as_str_name().serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<i32, D::Error> {
let name = String::deserialize(deserializer)?;
PrintJobStatus::from_str_name(&name)
.map(|status| status as i32)
.ok_or_else(|| serde::de::Error::custom(format!("unknown PrintJobStatus: {name}")))
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PrintParameters {
pub layer_height_mm: f64,
pub infill_percent: i32,
pub infill_pattern: String,
pub print_speed_mm_s: f64,
pub supports_enabled: bool,
pub wall_count: i32,
}
// Bambu's raw MQTT command/report structs are NOT modeled here - they're
// plain hand-written Rust + serde in continuum-proxy's
// src/printer/bambu_commands/, not proto. That data is JSON-over-MQTT
// (not binary protobuf), and only continuum-proxy ever needs to parse it
// - none of protobuf's actual value (cross-language codegen, binary wire
// efficiency) applies, and forcing it through prost-build's codegen model
// anyway produced real, avoidable friction (see this crate's git history
// for the specifics: a field/variant attribute-matching collision on
// `oneof`, needing package-scoped `type_attribute` calls, explicit
// `field_attribute(..., "#[serde(default)]")` for fields that aren't
// always present - every one of these disappears with a hand-written
// struct, where `Option<T>` and `#[serde(flatten)]` just work with zero
// configuration). Proto stays for continuum.v1 above, which - unlike
// this - is a schema we designed ourselves and that both TS and Rust
// genuinely need.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Template {
pub id: String,
pub name: String,
pub description: String,
pub owner_id: String,
pub model_file_key: String,
pub material: MaterialProfile,
pub print_parameters: PrintParameters,
pub created_at_unix: i64,
pub updated_at_unix: i64,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PrintJobStatus {
#[serde(rename = "PRINT_JOB_STATUS_UNSPECIFIED")]
Unspecified,
#[serde(rename = "PRINT_JOB_STATUS_QUEUED")]
Queued,
#[serde(rename = "PRINT_JOB_STATUS_PRINTING")]
Printing,
#[serde(rename = "PRINT_JOB_STATUS_PAUSED")]
Paused,
#[serde(rename = "PRINT_JOB_STATUS_COMPLETED")]
Completed,
#[serde(rename = "PRINT_JOB_STATUS_FAILED")]
Failed,
#[serde(rename = "PRINT_JOB_STATUS_CANCELLED")]
Cancelled,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PrintJob {
pub id: String,
pub farm_id: String,
pub printer_id: String,
pub template_id: String,
pub status: PrintJobStatus,
pub progress_percent: f64,
pub started_at_unix: i64,
pub completed_at_unix: i64,
pub gcode_file_key: String,
}