diff --git a/.gitignore b/.gitignore index d40ee4f..5ed9b44 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ Cargo.lock # Personal study files, not part of the real schema build. /examples/ + +# Emitted by `tsc -b` into each package's dist/ - never commit build output. +*.js.map +*.d.ts.map diff --git a/packages/ts-types/package.json b/packages/ts-types/package.json index 89f42e6..1599298 100644 --- a/packages/ts-types/package.json +++ b/packages/ts-types/package.json @@ -10,6 +10,6 @@ ".": "./src/index.ts" }, "dependencies": { - "@sinclair/typebox": "^0.33.12" + "@sinclair/typebox": "0.34.52" } } diff --git a/packages/ts-types/src/index.d.ts b/packages/ts-types/src/index.d.ts deleted file mode 100644 index 292f605..0000000 --- a/packages/ts-types/src/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./schemas"; diff --git a/packages/ts-types/src/index.js b/packages/ts-types/src/index.js deleted file mode 100644 index 292f605..0000000 --- a/packages/ts-types/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from "./schemas"; diff --git a/packages/ts-types/src/schemas/edge.d.ts b/packages/ts-types/src/schemas/edge.d.ts deleted file mode 100644 index 46b945e..0000000 --- a/packages/ts-types/src/schemas/edge.d.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { type Static } from "@sinclair/typebox"; -/** - * The /ws/edge/v1 uplink protocol, mirroring - * `schemas/continuum/v1/edge/*.schema.json` by hand - the same convention - * every other schema in this package follows. The JSON Schema files are - * canonical; change them first, then this, then the Rust mirror (which for - * this one protocol lives in `continuum-proxy/src/uplink/protocol.rs` rather - * than in `packages/rust-types`, since the gateway is its only Rust - * consumer). - * - * Field names are snake_case, unlike the backend's HTTP routes. That is not - * an oversight: the other end of this wire is serde-derived Rust, and - * snake_case is what those structs produce without per-field rename - * attributes. It is also what the rest of this repository uses. - */ -export declare const PrinterTelemetrySchema: import("@sinclair/typebox").TObject<{ - /** - * The *gateway's* own id from its printers.toml - not a vendor serial and - * not `printers.id`. The backend resolves it through - * `printers.gateway_printer_id`, scoped to the authenticated farm. - */ - printer_id: import("@sinclair/typebox").TString; - name: import("@sinclair/typebox").TString; - /** - * The printer's own state string rather than an enum, so an unrecognised - * state survives the trip instead of being dropped at the edge. Bambu - * emits IDLE, RUNNING, PAUSE, FINISH, FAILED. - */ - state: import("@sinclair/typebox").TOptional>; - percent: import("@sinclair/typebox").TOptional>; - layer: import("@sinclair/typebox").TOptional>; - total_layers: import("@sinclair/typebox").TOptional>; - remaining_minutes: import("@sinclair/typebox").TOptional>; - job_name: import("@sinclair/typebox").TOptional>; - nozzle_temp: import("@sinclair/typebox").TOptional>; - nozzle_target: import("@sinclair/typebox").TOptional>; - bed_temp: import("@sinclair/typebox").TOptional>; - bed_target: import("@sinclair/typebox").TOptional>; - /** Vendor error code; non-zero means the printer is reporting a fault. */ - print_error: import("@sinclair/typebox").TOptional>; - /** Count of active Health-Management-System entries, not decoded messages. */ - active_alerts: import("@sinclair/typebox").TOptional>; -}>; -export type PrinterTelemetry = Static; -/** - * Deliberately small, and deliberately missing "start a print" - see the - * JSON Schema for why that variant is absent until the gateway's - * start-an-uploaded-file path has been run against real hardware by hand. - */ -export declare const PrinterCommandSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ - action: import("@sinclair/typebox").TLiteral<"set_fan_speed">; - /** - * A percentage on this wire whatever the vendor wants. A Bambu turns it - * into an M106 PWM value and reports it back as one of 16 gears, so what - * is set here does not read back identically. - */ - percent: import("@sinclair/typebox").TInteger; -}>, import("@sinclair/typebox").TObject<{ - action: import("@sinclair/typebox").TLiteral<"send_gcode_line">; - /** The most powerful variant by far; be careful about exposing it to a UI. */ - line: import("@sinclair/typebox").TString; -}>]>; -export type PrinterCommand = Static; -export declare const EdgeClientMessageSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"hello">; - gateway_id: import("@sinclair/typebox").TString; - farm_id: import("@sinclair/typebox").TString; - token: import("@sinclair/typebox").TString; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"heartbeat">; - /** Monotonic per connection, restarting at 1 on reconnect. */ - seq: import("@sinclair/typebox").TInteger; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"telemetry">; - /** - * A batch, not a message per printer: a farm has one uplink and many - * printers, and a coherent picture of the farm at an instant is worth - * more here than the lowest possible per-machine latency. - */ - printers: import("@sinclair/typebox").TArray>; - percent: import("@sinclair/typebox").TOptional>; - layer: import("@sinclair/typebox").TOptional>; - total_layers: import("@sinclair/typebox").TOptional>; - remaining_minutes: import("@sinclair/typebox").TOptional>; - job_name: import("@sinclair/typebox").TOptional>; - nozzle_temp: import("@sinclair/typebox").TOptional>; - nozzle_target: import("@sinclair/typebox").TOptional>; - bed_temp: import("@sinclair/typebox").TOptional>; - bed_target: import("@sinclair/typebox").TOptional>; - /** Vendor error code; non-zero means the printer is reporting a fault. */ - print_error: import("@sinclair/typebox").TOptional>; - /** Count of active Health-Management-System entries, not decoded messages. */ - active_alerts: import("@sinclair/typebox").TOptional>; - }>>; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"command_result">; - command_id: import("@sinclair/typebox").TString; - ok: import("@sinclair/typebox").TBoolean; - /** Only when `ok` is false. A message for an operator, not a code. */ - error: import("@sinclair/typebox").TOptional>; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"frame_batch">; - printer_id: import("@sinclair/typebox").TString; - print_job_id: import("@sinclair/typebox").TOptional>; - frames: import("@sinclair/typebox").TArray>; -}>]>; -export type EdgeClientMessage = Static; -export declare const EdgeServerMessageSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"hello_ack">; - session_id: import("@sinclair/typebox").TString; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"hello_error">; - message: import("@sinclair/typebox").TString; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"heartbeat_ack">; - seq: import("@sinclair/typebox").TInteger; -}>, import("@sinclair/typebox").TObject<{ - type: import("@sinclair/typebox").TLiteral<"command">; - command_id: import("@sinclair/typebox").TString; - /** The gateway's own printer id - the backend translates on the way out. */ - printer_id: import("@sinclair/typebox").TString; - command: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ - action: import("@sinclair/typebox").TLiteral<"set_fan_speed">; - /** - * A percentage on this wire whatever the vendor wants. A Bambu turns it - * into an M106 PWM value and reports it back as one of 16 gears, so what - * is set here does not read back identically. - */ - percent: import("@sinclair/typebox").TInteger; - }>, import("@sinclair/typebox").TObject<{ - action: import("@sinclair/typebox").TLiteral<"send_gcode_line">; - /** The most powerful variant by far; be careful about exposing it to a UI. */ - line: import("@sinclair/typebox").TString; - }>]>; -}>]>; -export type EdgeServerMessage = Static; diff --git a/packages/ts-types/src/schemas/edge.js b/packages/ts-types/src/schemas/edge.js deleted file mode 100644 index 35cef3c..0000000 --- a/packages/ts-types/src/schemas/edge.js +++ /dev/null @@ -1,125 +0,0 @@ -import { Type } from "@sinclair/typebox"; -/** - * Optional *and* nullable: the key may be missing, or present as `null`. - * - * Strict in what we send, liberal in what we accept. A gateway omits fields - * it has no value for, which is what the JSON Schema describes - but a - * serde-derived Rust struct emits `null` by default unless every field is - * annotated, and one such field reaching here would otherwise fail - * validation and make Elysia drop an entire telemetry batch over a printer - * that merely had no job name. Not worth risking a farm's telemetry on. - */ -const Maybe = (schema) => Type.Optional(Type.Union([schema, Type.Null()])); -/** - * The /ws/edge/v1 uplink protocol, mirroring - * `schemas/continuum/v1/edge/*.schema.json` by hand - the same convention - * every other schema in this package follows. The JSON Schema files are - * canonical; change them first, then this, then the Rust mirror (which for - * this one protocol lives in `continuum-proxy/src/uplink/protocol.rs` rather - * than in `packages/rust-types`, since the gateway is its only Rust - * consumer). - * - * Field names are snake_case, unlike the backend's HTTP routes. That is not - * an oversight: the other end of this wire is serde-derived Rust, and - * snake_case is what those structs produce without per-field rename - * attributes. It is also what the rest of this repository uses. - */ -export const PrinterTelemetrySchema = Type.Object({ - /** - * The *gateway's* own id from its printers.toml - not a vendor serial and - * not `printers.id`. The backend resolves it through - * `printers.gateway_printer_id`, scoped to the authenticated farm. - */ - printer_id: Type.String(), - name: Type.String(), - /** - * The printer's own state string rather than an enum, so an unrecognised - * state survives the trip instead of being dropped at the edge. Bambu - * emits IDLE, RUNNING, PAUSE, FINISH, FAILED. - */ - state: Maybe(Type.String()), - percent: Maybe(Type.Integer({ minimum: 0, maximum: 100 })), - layer: Maybe(Type.Integer({ minimum: 0 })), - total_layers: Maybe(Type.Integer({ minimum: 0 })), - remaining_minutes: Maybe(Type.Integer({ minimum: 0 })), - job_name: Maybe(Type.String()), - nozzle_temp: Maybe(Type.Number()), - nozzle_target: Maybe(Type.Number()), - bed_temp: Maybe(Type.Number()), - bed_target: Maybe(Type.Number()), - /** Vendor error code; non-zero means the printer is reporting a fault. */ - print_error: Maybe(Type.Integer()), - /** Count of active Health-Management-System entries, not decoded messages. */ - active_alerts: Maybe(Type.Integer({ minimum: 0 })), -}); -/** - * Deliberately small, and deliberately missing "start a print" - see the - * JSON Schema for why that variant is absent until the gateway's - * start-an-uploaded-file path has been run against real hardware by hand. - */ -export const PrinterCommandSchema = Type.Union([ - Type.Object({ - action: Type.Literal("set_fan_speed"), - /** - * A percentage on this wire whatever the vendor wants. A Bambu turns it - * into an M106 PWM value and reports it back as one of 16 gears, so what - * is set here does not read back identically. - */ - percent: Type.Integer({ minimum: 0, maximum: 100 }), - }), - Type.Object({ - action: Type.Literal("send_gcode_line"), - /** The most powerful variant by far; be careful about exposing it to a UI. */ - line: Type.String(), - }), -]); -export const EdgeClientMessageSchema = Type.Union([ - Type.Object({ - type: Type.Literal("hello"), - gateway_id: Type.String(), - farm_id: Type.String(), - token: Type.String(), - }), - Type.Object({ - type: Type.Literal("heartbeat"), - /** Monotonic per connection, restarting at 1 on reconnect. */ - seq: Type.Integer({ minimum: 0 }), - }), - Type.Object({ - type: Type.Literal("telemetry"), - /** - * A batch, not a message per printer: a farm has one uplink and many - * printers, and a coherent picture of the farm at an instant is worth - * more here than the lowest possible per-machine latency. - */ - printers: Type.Array(PrinterTelemetrySchema), - }), - Type.Object({ - type: Type.Literal("command_result"), - command_id: Type.String(), - ok: Type.Boolean(), - /** Only when `ok` is false. A message for an operator, not a code. */ - error: Maybe(Type.String()), - }), - Type.Object({ - type: Type.Literal("frame_batch"), - printer_id: Type.String(), - print_job_id: Maybe(Type.String({ format: "uuid" })), - frames: Type.Array(Type.Object({ - object_key: Type.String(), - captured_at: Type.String({ format: "date-time" }), - })), - }), -]); -export const EdgeServerMessageSchema = Type.Union([ - Type.Object({ type: Type.Literal("hello_ack"), session_id: Type.String() }), - Type.Object({ type: Type.Literal("hello_error"), message: Type.String() }), - Type.Object({ type: Type.Literal("heartbeat_ack"), seq: Type.Integer({ minimum: 0 }) }), - Type.Object({ - type: Type.Literal("command"), - command_id: Type.String(), - /** The gateway's own printer id - the backend translates on the way out. */ - printer_id: Type.String(), - command: PrinterCommandSchema, - }), -]); diff --git a/packages/ts-types/src/schemas/index.d.ts b/packages/ts-types/src/schemas/index.d.ts deleted file mode 100644 index c801356..0000000 --- a/packages/ts-types/src/schemas/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./edge"; diff --git a/packages/ts-types/src/schemas/index.js b/packages/ts-types/src/schemas/index.js deleted file mode 100644 index 9225554..0000000 --- a/packages/ts-types/src/schemas/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// The old Material/PrintParameters/PrintJob/Template mirrors were removed -// (2026-09) when schemas/continuum/v1/ was restructured into -// material/printer/vendor - see that directory and its README. Add a -// hand-written TypeBox schema here per file under schemas/continuum/v1/ -// once something actually consumes it (continuum-backend's validators, -// most likely), same convention as before. -// The /ws/edge/v1 gateway uplink protocol - the first thing to actually need -// a TypeBox mirror here, consumed by continuum-backend's edge WebSocket -// route. Mirrors schemas/continuum/v1/edge/. -export * from "./edge"; diff --git a/packages/ts-types/tsconfig.json b/packages/ts-types/tsconfig.json index 49e05ce..792172f 100644 --- a/packages/ts-types/tsconfig.json +++ b/packages/ts-types/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "./dist", "rootDir": "./src" diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..07f894f --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2022"], + "strict": true, + "declaration": true, + "composite": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + } +} diff --git a/tsconfig.json b/tsconfig.json index 00d2583..7ce7fe6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,10 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "Bundler", - "lib": ["ES2022"], - "strict": true, - "declaration": true, - "composite": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true - }, - "exclude": ["examples", "node_modules"] + // A solution file: it builds nothing itself and only points at the real + // projects. It used to carry the compilerOptions directly with no `include`, + // which made `tsc -b` compile every .ts file in the repository as one project + // and emit .js/.d.ts next to the sources - overriding each package's own + // `outDir`, and leaving generated files in src/ that then got committed. + // Shared options now live in tsconfig.base.json, which each package extends. + "files": [], + "references": [{ "path": "./packages/ts-types" }] }