A variable declared inside a try block but read after it shipped and broke
collection checks for a day; tests can't reach that path and node --check
only parses. ESLint flags it as no-undef. Wired into npm run lint / check
and into CI before the image build, so a failure stops the build.
Three findings fixed on the way: an unread argument, and two values
assigned then immediately replaced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Settings → Printer takes the printer's address, serial number and access code
(the code stored as a secret, like the other tokens). "Save & test connection"
connects to the printer's own MQTT broker on port 8883, subscribes to its
reports, asks once for a full report, and listens for a few seconds — then
says what it heard: its state, and the filament in each AMS slot or on the
external spool holder, with how much is left where the printer knows.
Nothing sent to the printer changes what it is doing; the only thing published
is the request for a full report. If the printer is in cloud mode and treats
even that as a write, the test says it received nothing rather than failing
silently. The access code never leaves the server.
Adds mqtt as a runtime dependency — server.js now loads it at startup, so the
lockfile has to travel with this change.
Not verified against a real printer yet: the printer's ports answer on the
network, but no connection has been made with its credentials.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- AI tagging through any OpenAI-compatible API: DeepSeek by default, or
OpenRouter, OpenAI, or a local server (Ollama, LM Studio). Settings → AI
with presets, prices and "Save & test connection"; the key never leaves
the server except to the provider.
- Runs over untagged models, all models, or one model from its page: live
progress, tokens and cost, stop/resume (retrying failures), an optional
spending limit, and paused rather than resumed after a restart. Adapts to
models without JSON mode or image input; stops on a rejected key or no
credit. Tags are only added; descriptions filled only where empty unless
asked.
- Search by meaning: local bge-small-en-v1.5 embeddings (transformers.js),
indexed in the background whenever a model's text changes; Words/Meaning
switch on the search box. Stored as REAL[] in Postgres, no pgvector needed.
- Automatic tags: strict whole-word rules (part types, mechanisms, materials,
techniques) over names, file names and archive contents, plus your own
word -> tag rules; on/off (optionally removing its tags) and re-apply.
- Tags remember where they came from (user / rule / ai); edits keep that,
rule and AI passes never touch your own tags, and the model page marks them.
- Docker: ships the embedding model and only Linux onnxruntime binaries.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Archives
- ZIP, 7Z, RAR and TAR/.tar.gz uploads are indexed in the background into
archive_entries (7-Zip compiled to WASM in a worker thread; node-tar for
tar). macOS/Windows clutter and paths that could escape the extraction
folder are skipped.
- Models inside archives are extracted once per archive to hash and
geometry-fingerprint them, so duplicates are found inside packs too.
Pictures, PDFs and readmes are listed but never matched.
- New routes list an archive's entries and serve/convert a single entry,
extracted on first use and cached under extracted/.
Viewer
- Model detail lists what's inside each archive with view/download links;
opening an entry adds a viewer tab.
- New 3D formats: FBX (with sibling textures), OBJ with its MTL and
textures, STEP/STP via occt-import-js, and Rhino 3DM via rhino3dm — the
WASM readers are served from node_modules, loaded on first use.
- Pictures, PDFs and text files (jpg/png/gif/webp/bmp/svg, pdf, txt/md)
can be uploaded and preview in the viewer; a model without an embedded
3MF preview uses its first picture as the card thumbnail.
- Inline file responses send nosniff, and SVGs are sandboxed.
- GLB conversions write to a temp file and rename, so a half-written
preview is never served; a later tab can't be overdrawn by a slow load.
- Better 3MF card image: the project thumbnail or plate 1 render, not a
slicer pick map.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Fingerprint every file in the background: SHA-256 for all formats plus a
trimesh geometry fingerprint for STL/OBJ/3MF, so renamed, re-exported or
converted copies are still matched. Backfills existing files on startup.
- Duplicates view groups models that share files (exact copies vs same
shape), recommends which to keep, merges tags/collections/notes into the
kept model and trashes the rest; groups can be dismissed.
- Deleting now moves models to a restorable trash; files are only removed
from disk on permanent delete or when the trash is emptied.
- Per-model notes with autosave.
- Search across names, notes, tags, files and designers; filter by format,
source and license; include/exclude tags with any/all matching; sort and
group by source or format. Preferences persist per browser.
- Add node:test unit tests for duplicate grouping and fingerprints.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- users + password_resets tables; bcrypt hashing; JWT session in an
httpOnly cookie (auth_secret auto-generated in settings)
- /api gated behind auth (except /api/config and /api/auth/*)
- First-run creates the account (no open registration after that);
login, logout, forgot/reset-password flows
- SMTP settings (host/port/secure/user/pass/from) in Settings menu;
nodemailer sends reset links
- Auth screen (sign in / create account / forgot / reset) gates the SPA;
Sign out button; COOKIE_SECURE=true in compose for HTTPS
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>