Liking cljdoc? Tell your friends :D

Bambu TypeScript native seams (read-only reference study)

References: G/ = clones-ref/bambu-mcp-griches/ at ca6db60 (MIT stated in G/README.md:209-211); P/ = clones-ref/bambu-printer-mcp/ at cc93603 (GPL-2.0, P/package.json:1-3,22-42). P/ supplies facts only, not code or prose for the MIT addon. The existing Python/TS network comparison is docs/native-seams-net.md; no printer, Blender instance or slicer was run. Source reading is not hardware verification (G/src/mqtt-client.ts:53-65; P/src/safety/print-file.ts:144-148).

In-process npm entry points and ownership

SurfaceHost-callable shape and lifecycleAdds relative to docs/native-seams-net.md
G fleet (MIT)ESM Node >=18, package main/bin dist/index.js, dependencies mqtt, basic-ftp, MCP SDK, zod (G/package.json:1-26). Do not import the main: its top level constructs server/fleet and calls main() to connect stdio, then loads configured printers (G/src/index.ts:1-37,39-81). Deep import dist/fleet-manager.js: new FleetManager(), await connectPrinter(PrinterConfig), resolvePrinters(id|'all'|undefined), executeOnPrinters(target, async conn => string), disconnectPrinter/disconnectAll; it owns id→config+MQTT instances, replaces connections, fans out via Promise.allSettled, returns MCP text rather than structured status (G/src/fleet-manager.ts:4-46,52-132).Fleet id routing, single-printer ambiguity refusal and partial-result fanout beyond Python's one BambuPrinter(spec) (G/src/fleet-manager.ts:56-132; docs/native-seams-net.md, Entry table).
G MQTT + files (MIT)Deep import dist/mqtt-client.js: new BambuMQTTClient({host,port,username,password,deviceId,model}), await connect(), requestStatus(), getCachedStatus(), print/AMS/LED methods, disconnect(); callback-based MQTT client, mutable sequence/status, Node timers and promises, no GPU/window (G/src/mqtt-client.ts:4-34,35-137,185-298,351-428). Deep import dist/ftp-client.js: withFtpClient(host,code,fn), listFiles, uploadFile, downloadFile, deleteFile; opens implicit FTPS 990, user bblp, secureOptions.rejectUnauthorized:false, closes client in finally (G/src/ftp-client.ts:1-74).Native JS implicit FTPS without the prior TS/Python curl fallback; basic-ftp success against target firmware remains unmeasured (G/src/ftp-client.ts:7-25,44-73; docs/native-seams-net.md, Protocol, FTPS). G's report merges print || mc_print, but its pushing.pushall waits 2s and returns cached state, not a fresh safety attestation (G/src/mqtt-client.ts:91-101,236-249).
P standalone utilities (GPL facts only)ESM Node package main/bin dist/index.js, postinstall patch installer, bambu-js, bambu-node, basic-ftp, mqtt, three, jszip, xml2js; build:native script exists (P/package.json:1-63). Main import is not passive: dotenv.config(), temp directory, server construction and server.run() at module bottom (P/src/index.ts:45-68,4349-4357). Named deep-import surfaces: STLManipulator, normalizeSlicerType (P/src/stl/stl-manipulator.ts:57-110,196-207), flattenForCli (P/src/slicer/profile-flatten.ts:25-98,656-656), parse3MF (P/src/3mf_parser.ts:200-224), inspectPrintFile (P/src/safety/print-file.ts:144-166), BlenderMcpBridge (P/src/blender-mcp-bridge.ts:229-230,283-344). Do not import GPL package into MIT addon pending Pedro's licence decision.STL geometry/editing, profile inheritance flattening, sliced-3MF inspection, fresh hardware gating, Blender handoff: Python surface covers printer/report/manifest, not these (P/src/stl/stl-manipulator.ts:1-11,196-207,1585-1596; P/src/slicer/profile-flatten.ts:1-21; P/src/safety/print-file.ts:144-166; docs/native-seams-net.md, Entry table).

G dispatch is nine register*Tools(server,fleet) registrations, with zod MCP schemas and async callbacks; G MQTT's closest (id,params)->result is private sendCommand('section.command', params, waitForResponse); status is a merged open report. No 500+ engine command registry or reusable exported JSON dispatcher in either network implementation (G/src/index.ts:5-36; G/src/mqtt-client.ts:187-249; P/src/index.ts:3099-3135,4222-4275). P CallToolRequestSchema dispatches a long named switch, returns text or optional structuredContent, catches errors into {status:'error',isError:true}, not a standalone library execute function (P/src/index.ts:3099-3110,4222-4275). INFERRED: our cljs adapter would keep its own small typed command map instead of importing either MCP main (G/src/index.ts:23-36,72-81; P/src/index.ts:4349-4357).

Protocol, trust and safety contrasts

  • G sends JSON to device/{deviceId}/request and subscribes device/{deviceId}/report over MQTT TLS 8883; bblp and access code set by fleet. Certificate verification is disabled, reconnection starts after initial handshake, and sendCommand matches section+sequence with a 10s timeout; a publish-only command returns {sent:true} without device ACK (G/src/fleet-manager.ts:17-30; G/src/mqtt-client.ts:48-92,187-234). G does not attach a signing header in this path: signing is a separate sign_message MCP tool calling getAppCert(); getAppCert supports env overrides or returns embedded credentials. Never propagate those keys (G/src/mqtt-client.ts:205-216; G/src/tools/signing.ts:6-38; G/src/types.ts:76-101). Python lacked outgoing signatures; prior TS reference had optional outgoing signature (docs/native-seams-net.md, Protocol TLS).
  • G send_gcode uppercases/trim then prefix-blocks M112/M502/M500/M501/M997/M999, before calling sendGcode; because prefix matching is not token parsing, it can overblock and does not establish safety for every G-code/program shape. set_temperature accepts 0..300°C nozzle or 0..120°C bed and emits M104/M140; set_speed enforces profile silent|standard|sport|ludicrous or percentage 50..166 (G/src/tools/gcode.ts:5-46; G/src/tools/hardware.ts:5-12,17-66,96-132). change_filament checks tray 0..3 but does not check integer-ness or optional target_temp; printFile routes 3MF vs G-code and H2 model-specific URL/nozzle fields without an inspected-file safety gate (G/src/tools/ams.ts:11-38; G/src/mqtt-client.ts:303-393). G file tool claims 3MF/G-code uploads yet allows .stl, rejects paths by substring .. only; do not assume its upload is a print-safe artifact gate (G/src/tools/files.ts:76-127).
  • P uses independent model/material ceilings: unknown positive heat model/material refused; zero is permitted; nozzle limit per material and machine, bed/chamber per machine, special X1E 290°C PLA startup allowance only in inspector (P/src/safety/limits.ts:23-39,46-93). inspectPrintFile(filePath,{model,nozzleDiameters?,plateIndex?,bedType?}) returns file digest, declared nozzle/material/filament positions, selected plate, peak temperatures and AMS usage; it requires sliced .3mf plate G-code or textual .gcode, consistent printer/nozzle/material metadata, bound declarations and an FFF rather than laser/cutter job (P/src/safety/print-file.ts:5-19,96-136,144-205,227-250,361-389). It scans thermal-affecting G/M/T and AMS commands, rejects dynamic syntax, laser/cutter and unsupported temperature command forms; bounded X1E flush exception checks a precise follow-up sequence (P/src/safety/print-file.ts:55-95,262-331,348-389). Limit: it explicitly checks declared object bounds, not arbitrary motion or physical spool/nozzle authenticity (P/src/safety/print-file.ts:144-148).
  • P archive gate caps input 256 MiB, individual entry 256 MiB and total decoded 512 MiB; rejects ambiguous/duplicate paths, ZIP64, encrypted/unsupported forms, inconsistent local/central entries, CRC mismatch before loading verified bytes into JSZip. By contrast its general-purpose parse3MF uses JSZip.loadAsync(data) and xml2js directly; it is not the same verified-print archive boundary (P/src/safety/archive.ts:6-9,27-47,82-131,156-181; P/src/3mf_parser.ts:1-4,143-151,200-224).
  • P's readFreshPrinterStatus subscribes raw MQTT messages and requests pushall+get_version, collects observed identity/state/error/HMS after request rather than trusting cached printer.data; validatePrinterState requires a recent observation (15s), reported matching model, safe state, no print/HMS error, nozzle and used-filament/AMS mapping match (P/src/safety/printer-state.ts:40-104,130-137,212-330). normalizeBridgeAmsTrayValue accepts absolute -1..15 or HT/external 128..254, and mapping objects sort numeric keys; not G's single 0..3 tray UI (P/src/ams-mapping.ts:1-47; G/src/tools/ams.ts:17-38). Operation queue is per serial, stop/heater-off bumps generation, withPrintSnapshot copies source to read-only temporary file to mitigate changes after inspection (P/src/safety/artifact.ts:7-46).
  • P native networking is not a direct npm FFI seam: bambu-native.ts spawns native/bambu-native-print on macOS, with beforeDispatch authorization handshake and timeout/cancellation; bambu-network-bridge.ts owns a framed JSON/binary child process; STLManipulator.sliceSTL invokes the slicer CLI via execFile. Only the slicer CLI is an accepted subprocess in the wave-2 policy (P/src/bambu-native.ts:1-2,58-84,115-148,191-215; P/src/bambu-network-bridge.ts:1-40,116-135; P/src/stl/stl-manipulator.ts:1585-1596,1740-1769). P uses bambu-js/bambu-node and custom TolerantBambuClient for LAN where H2 get_version ACK is missing, optional client cert from files and MQTT transport; X2D direct legacy MQTT/FTPS printing is refused (P/src/printers/bambu.ts:12-27,34-51,95-102,177-215).

Blender contract and data crossing

P's BlenderMcpBridge is an MCP client, not an in-process Blender import: BLENDER_MCP_COMMAND plus JSON-array BLENDER_MCP_ARGS configure StdioClientTransport; each session connects, paginates tools/list, checks advertised JSON schema with Ajv, calls named tool, closes. A legacy BLENDER_MCP_BRIDGE_COMMAND mode uses execFile with MCP_BLENDER_PAYLOAD in environment (P/src/blender-mcp-bridge.ts:43-75,229-294,313-326). status({connect?,timeout_ms?}), call({tool_name,arguments,timeout_ms}), edit({stl_path,operations,output_path,user_prompt?,execute?,timeout_ms?}) are the public calls; timeouts 100..300000ms, default 120000 (P/src/blender-mcp-bridge.ts:38-43,297-344). The edit path accepts 1..64 operations (decimate:ratio, remesh:positive-voxel-size, boolean_union:STL-path), validates input and output as new .stl, max 256 MiB with finite triangles, constructs a bpy execute_blender_code request, checks request-id/path receipt and staged output STL before hard-link publishing (P/src/blender-mcp-bridge.ts:105-161,163-228,313-343). This code-execution tool is a trust boundary; errors can arrive as MCP isError, text or structured status; timeout after dispatch reports unknown execution, not retryable proof of failure (P/src/blender-mcp-bridge.ts:87-103,258-294,333-343). INFERRED: direct cljs-to-Blender-module import is not evidenced; standalone blender-mcp has its own seam, while this GPL bridge documents a file-based STL/MCP contract only (P/src/blender-mcp-bridge.ts:1-13,229-294).

G's PrinterConfig, PrinterStatus (open [key:string]:any), FileInfo are TS interfaces, not runtime serializers; report JSON crosses as plain objects, STL bytes/geometry remain Node Buffer/Three.js BufferGeometry, operations return path strings or JSON-friendly inspection (G/src/types.ts:1-10,12-73; G/src/mqtt-client.ts:91-101; P/src/stl/stl-manipulator.ts:1-10,39-53; P/src/safety/archive.ts:27-47; P/src/safety/print-file.ts:5-19). INFERRED: retain opaque handles for live MQTT client, FTP client, mesh and running operation; map snapshots/inspection records to values, transfer STL/3MF by bounded file/byte channel (G/src/fleet-manager.ts:4-12; P/src/safety/artifact.ts:32-46; P/src/blender-mcp-bridge.ts:105-125).

Vocabulary, closed vs open

  • Value nouns: printer identity/config and report/AMS trays (G/src/types.ts:1-67), fleet connection (G/src/fleet-manager.ts:4-12), print job/selected plate/nozzle/material/filament position (P/src/safety/print-file.ts:5-19,144-166), physical printer observation (P/src/safety/printer-state.ts:106-137), 3MF objects/build items/slicer config/AMS mapping (P/src/types.ts:12-60), STL transform/axis/bounds and slicer profiles (P/src/stl/stl-manipulator.ts:24-53; P/src/slicer/profile-flatten.ts:25-70).
  • Closed local vocabularies: G speed profiles and LED modes, target heater and blocked-Gcode policy (G/src/tools/hardware.ts:5-12,23-28,76-90,103-108; G/src/tools/gcode.ts:5-12); P slicer type list, profile kind, operation union and selected model/bed/nozzle types (P/src/stl/stl-manipulator.ts:57-66; P/src/slicer/profile-flatten.ts:25-25; P/src/blender-mcp-bridge.ts:15-17; P/src/index.ts:113-123). INFERRED: these are candidate closed malli enums for local policy, not firmware exhaustive enums (G/src/types.ts:12-73).
  • Open registries/data: G fleet IDs/config, MQTT report keys, per-tool registrations, filament names (G/src/fleet-manager.ts:9-12,52-99; G/src/types.ts:12-73; G/src/index.ts:28-36); P arbitrary BambuSlicerConfig keys and profile names/inheritance, MCP tool names advertised by Blender, observed firmware gcode_state strings (P/src/types.ts:28-49; P/src/slicer/profile-flatten.ts:109-120; P/src/blender-mcp-bridge.ts:264-294; P/src/safety/printer-state.ts:212-215). INFERRED: model capability selection must fail closed when unrecognized; profile/tool names remain registry-extensible (P/src/safety/limits.ts:37-47,74-86; P/src/blender-mcp-bridge.ts:283-294).

Ranked attachment candidates (policy-constrained)

  1. G MIT FleetManager + BambuMQTTClient + ftp-client deep imports via cljs/Node: true in-process npm calls, fleet and FTPS beyond Python; requires async owner per printer, cautious credential handling, wrapping MCP-text fanout into values, independent print safety rather than trusting its prefix guard/cached status (G/src/fleet-manager.ts:9-46,100-132; G/src/ftp-client.ts:5-25; G/src/tools/gcode.ts:5-46; G/src/mqtt-client.ts:236-249).
  2. Direct MIT npm mqtt + basic-ftp behind our cljs port, using G as protocol evidence: avoids G MCP-text coupling, permits single session owner and fresh-report checking; forces implementation of publish/subscribe, timeouts, FTPS validation, signing/certificate decision and all safety policy. INFERRED design cut, not a shipped facade (G/package.json:15-22; G/src/mqtt-client.ts:48-101,187-249; G/src/ftp-client.ts:5-25; P/src/safety/printer-state.ts:40-104).
  3. P GPL utility package deep imports (inspection/STL/profile/Blender) only after legal decision: richer safety and geometry, but GPL-2.0 licensing question, native sidecars and legacy executable Blender path conflict with in-process-only policy; separate pure npm three/jszip and slicer CLI are potential replacements, NOT equivalent safety implementations. INFERRED design cut, not permission to copy or link (P/package.json:22-63; P/src/safety/print-file.ts:144-166; P/src/blender-mcp-bridge.ts:229-344; P/src/bambu-native.ts:115-148).

Open questions

  1. Pedro/legal: is requiring GPL-2.0 bambu-printer-mcp from an MIT cljs addon legally acceptable, or should only its observed facts inform an independently authored adapter? Do not decide here (P/package.json:22-42; P/src/index.ts:4349-4357).
  2. Can G's basic-ftp implicit TLS path connect/upload on target firmware, and does signing via separate G tool ever authenticate G's unsigned MQTT publish? Neither path was exercised here (G/src/ftp-client.ts:5-25,44-73; G/src/tools/signing.ts:6-38; G/src/mqtt-client.ts:205-216).
  3. Can the target node build deep-import the distributed ESM paths for both packages under shadow-cljs, and can a fresh report identify model/AMS before printing? Source exports imply possible imports but no runtime import or printer gate was run (G/package.json:1-26; G/src/fleet-manager.ts:9-46; P/src/safety/printer-state.ts:40-104).

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close