Files
ComfyAssets-ComfyUI_PromptM…/tools/vendor
Vito e29ff4d4b2 feat(inspect): the Inspect page for local files (#280)
* feat(inspect): local adapter seams in the shared inspector and viewer

The inspection loader calls adapter.read when an adapter reads by itself, so a
file chosen in this browser never reaches the API. The full inspector shows the
D66 local provenance (no Path row, no Show in folder, local association line),
and the viewer uses adapter.mediaUrl exactly, so a blob: URL is never given the
_pm_viewer cache-buster and Retry media reuses it. Rooted and recorded-history
adapters keep their api.get paths and cache-busted originals.

* feat(inspect): owned local selection session

createLocalSession owns one chosen File at a time: it classifies the bytes,
creates the blob: URL only for a classified image or video, and reads it
through a real inspection controller with the local adapter. Replacement,
dispose, parent abort and pagehide each release the URL, the handle and the
record once; a released handle (and every copy) is foreign to the adapter, and
every await is fenced by a generation counter so a replaced read never
publishes. Empty, multiple and directory drops keep the previous selection.
Baseline entry for local-session.mjs; branch floors raised for the touched
inspection-state.mjs and local-inspection.mjs.

* feat(inspect): native Inspect a file page

#/inspect is now the concept's "Inspect a file" page instead of the legacy
handoff. One chosen or dropped image or video previews inline, and the one
heading action, "Open file metadata", opens the shared viewer with the full
inspector on a record read entirely in this browser. Nothing is uploaded,
imported or stored; only an explicit Send crosses the host bridge.

- inspect.mjs mounts the concept DOM (surface, file-drop, #local-preview)
  under the shell heading, owns one local session and the shared viewer and
  prompt sender, and releases media before the session revokes its URL on
  replacement, route change, page leave and dispose (D60-D65).
- A file that cannot be read after choosing opens the inspector's
  unreadable state when the browser declares a supported type, instead of
  the "unsupported" copy; the local adapter maps a browser read failure to
  an unreadable record.
- The route is native; Overview keeps its card to the legacy metadata page,
  which is unchanged.
- workspace-inspect.spec.mjs covers the chooser and viewer rail against the
  Images rail for the same bytes, drop, cancel and reselect, unsupported and
  unreadable files, video, URL ownership, mid-read replacement, exact send
  and the no-request/no-storage rule.

* test(inspect): concept parity and managed-host send for local files

Compare the native Inspect a file page with the immutable concept's
#metadata at 1600x1100 and 390x844 in both themes (initial, selected,
viewer-open), mapping D60-D66 and pinning the concept's CSS values and
the chooser's displayed file name, with a mutation check. Send a local
PNG (explicitly empty negative) and core-tags.webm to a real Prompt
Manager (+/-) node across Classic and Nodes 2.0 switches and reloads;
a connected input rejects the send unchanged. Document D60-D66, the
legacy-floor dispositions and the commands in TESTING.md.

* fix(inspect): reset a released preview video in the next task

On WebKit (GStreamer) a video replaced while its pipeline was still
starting blocked the page: pause, src removal and load() in one task
never returned, so the next chooser selection hung (CI page workflows
webkit shard 2/2, "URLs and media end with their owning session").
The src is still dropped before the URL is revoked; only the load()
reset moves to the next task. A fresh-page regression replaces the
first video as soon as it shows, fifteen times.

* fix(inspect): never reset a preview video that is still starting

Deferring load() to the next task was not enough: CI on b7db4c3 hung
WebKit one step later in the fresh-page regression. Reset with load()
only a settled video (metadata read, or failed); a starting one is
paused, loses its src before the URL is revoked and is removed, then
left to be collected. The ownership workflow waits for the video to
settle before asserting the reset.

* fix(inspect): final review round for the local Inspect page

- Each inline preview owns its listeners, so a released node is never
  pinned; a video released while still starting is reset with load()
  once it reports metadata or an error (I1).
- The viewer's video teardown on a just-started local video is guarded
  by a 15-page WebKit test; it needed no change (I2).
- The chooser keeps naming the current file after a cancelled picker
  and names the dropped file after an accepted drop (I3).
- The unrelated activity-scan.mjs floor raise is reverted (I4).
- The page owns pagehide: the viewer closes and the inline media goes
  before the session revokes the URL, and the chooser is cleared (M1,
  M2); the session gains clear() and the viewer close().
- The "metadata is available" toast shows only for readable metadata
  (M3); a rejected drop is a second, transient alert that never
  replaces the selection's status (M4).
- TESTING.md: D62/D63 updates, the WebKit loadstart follow-up and the
  pair-node follow-up (M5).
2026-10-22 16:06:07 -07:00
..

Viewer.js maintenance

ComfyUI serves the committed files in web/lib/viewerjs/. Node and npm are only needed by maintainers and CI. Keep upstream files pristine; application behavior belongs in web/js/, and theme overrides belong in comfyui-theme.css.

Install and verify

Use Node 24 or newer. From the repository root:

npm ci --prefix tools/vendor --ignore-scripts
npm run --prefix tools/vendor check
npm run --prefix tools/vendor test
node --test tests/js/*.test.js
npx --prefix tools/vendor playwright install chromium
npm run --prefix tools/vendor test:browser

On Linux, use playwright install --with-deps chromium when browser system libraries are missing. The browser tests use synthetic images and mock the ComfyUI API boundary; they run production viewer methods and the committed Viewer.js JS/CSS, without a running ComfyUI instance.

check is read-only and fails if any JS, CSS, license, or provenance file differs from the installed package. The manifest, lockfile, installed package, and asset version banners must agree. The lockfile records npm's archive integrity; provenance.json records the upstream source, package integrity, and SHA-256 of each copied file. A normal npm ci --ignore-scripts verifies archive integrity.

Full-page workflows, frontend coverage gates, and required merge checks are documented in TESTING.md. The viewerjs CI check runs both the fixture tests above and the real-page workflows on every PR.

Update

npm run --prefix tools/vendor update
# Or select a specific stable version:
npm run --prefix tools/vendor update -- --version 1.15.2

The command installs an exact version with lifecycle scripts disabled and copies dist/viewer.min.js, dist/viewer.min.css, and LICENSE. It writes deterministic provenance with no timestamps. Repeat the checks above and commit the manifest, lockfile, and all vendor files together. To regenerate files from the current pin without changing versions, run npm run --prefix tools/vendor sync.

Automated update PRs

Update vendored Viewer.js checks npm's stable release daily at 07:30 UTC and supports Actions → Update vendored Viewer.js → Run workflow, with an optional version. It tests the generated update before opening deps/viewerjs-X.Y.Z. Existing open or closed PRs for that release are left alone. A failed test does not publish a branch or PR. Changes require review; the workflow never merges or approves PRs.

The organization and repository must enable Actions → General → Workflow permissions → Allow GitHub Actions to create and approve pull requests. Keep default workflow permissions read-only. Only the update job requests contents: write, pull-requests: write, and actions: write.

The workflow uses GITHUB_TOKEN; no personal token is needed. Because bot-token pushes do not normally trigger other workflows, it explicitly dispatches the read-only Viewer.js vendor and compatibility workflow on the update branch. Both workflow files must be merged into the default branch before scheduling or manual dispatch becomes available.

Compatibility checklist

Check gallery grid/list views, navigation across 100-image windows, metadata, slideshow/fullscreen, keyboard navigation, Escape and focus cleanup. Check the admin gallery/filmstrip and tag viewer. On touch devices, test long swipes, short drags, and pinch/rotate gestures. Confirm the ComfyUI theme remains usable.

The gallery keeps its bounded viewer and custom slideshow. Upstream navbar windowing is not a replacement for bounding the supplied image list: native slideshow playback can still preload every supplied original. Review new preloading defaults, gesture behavior, CSS changes, and any adapter use of Viewer.js internal methods before adopting another release.

Shared ComfyAssets test tooling

The exact toolkit commit archive in package.json / package-lock.json supplies host orchestration and coverage helpers. comfyui-host.mjs is PromptManager's configuration adapter; keep reusable lifecycle changes in the toolkit source. The existing npm scripts remain the public maintainer entry points. See TESTING.md for the managed real-host matrix and update policy.

Shared ComfyAssets browser controls

Prompt Manager (Classic) consumes the same pinned toolkit's browser controls. The node identifier remains PromptManager; existing workflows, sockets, and immediate result selection are preserved. PromptManager Text is unchanged.

Committed assets in web/js/shared/toolkit/ work without npm or KikoTools installed. Maintain common controls in ComfyAssets Toolkit, then update the exact archive pin and lockfile here. Regenerate using npm run --prefix tools/vendor sync:toolkit; npm run --prefix tools/vendor check verifies both Viewer.js and the toolkit without rewriting files. The toolkit distribution includes its license, source history, archive integrity and per-file hashes. Do not edit its copied files directly. Classic's controller and layout remain in web/js/classic-node.js and web/js/classic-node.css.

Run the frontend coverage/browser suites and managed Classic/Nodes 2.0 matrix after updates. Shared modules participate in the frontend coverage gate. Pixaroma's reusable framework inspired this architecture; no Pixaroma code, styles or assets are included.