footer.tmpl now just loads /assets/ifcurl.js; all injection logic lives in
the new ifcurl.js file alongside the other viewer assets. Update deploy
instructions in both READMEs; fix incorrect /etc/forgejo path in top-level README.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ifcopenshell can parse IFC bytes in-memory via from_string(); no need to
write a temp file, read it back, and unlink it. Simpler and faster.
Update README library example to match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- render.py: replace bare cpu_count() with _WORKER_COUNT = min(cpu_count, 4),
configurable via IFCURL_RENDER_WORKERS env var; prevents N concurrent
requests from spawning N×cpu_count geometry worker processes
- auth.py: document that inject_token() embeds the token in git CLI arguments,
making it visible in the process list; note SSH as the workaround
- README: replace placeholder comment with actual tempfile.mkstemp pattern for
loading IFC bytes into ifcopenshell (which requires a file path, not bytes)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- footer.tmpl: refactor to inject per-commit "View in 3D" links on the file
history page, alongside the existing file view page button
- ifc_url.go: add ')' to urlTerminators so bare ifc:// URLs followed by a
closing parenthesis are correctly terminated
- ifc_url_test.go: add tests for @ in query value, ) terminator, trailing
period, and SERVICE_TOKEN presence/absence in preview URL
- viewer.html: selector input placeholder and title attribute now document
that the browser viewer only supports type-name union selectors
- README: document viewer selector limitation vs full server-side behaviour
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /preview now accepts a token= query parameter, matching POST /preview
- Forgejo Go: add SERVICE_TOKEN config field; renderer appends it to <img src>
preview URLs so a machine-user token can authenticate private repos
- Go tests: verify token appears in preview URL when set, absent when unset
- viewer.html: BCF import via drag-and-drop or Import .bcf button in BCF row;
parses first viewpoint camera/clips/GUIDs and reloads with the viewpoint
applied to the current model context
- viewer-url.js, viewer.html: unescape %24 → $ in URL building so GlobalIds
with $ characters are human-readable in ifc:// URLs
- README: document SERVICE_TOKEN and private-repo preview configuration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ⎘ button to copy the current ifc:// URL to clipboard
- Add Issue button to open a pre-filled new issue on the git host
- Add click-to-identify via OBC.Highlighter: clicking an element shows
its IFC type, name, and GlobalId in a panel with a copy button
- Replace arrayBuffer() with ReadableStream loop showing fetch progress
as percentage (when Content-Length known) or MB transferred
- README: document viewer features, collaboration workflow, and that
private Forgejo repos work via same-origin session cookie
- CLAUDE.md: document that [attr=val] bracket selector syntax is invalid;
correct form is comma-separated (IfcWall, Name="...") and bare GlobalId
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pyproject.toml: add bcf to [service] dependencies (ifcurl-9rk)
- README.md: replace bogus GET /viewer row with POST /bcf (ifcurl-ttb)
- viewer-url.js: fix GitLab host detection (includes → startsWith) (ifcurl-3n4)
- git.py: call _evict_if_needed() after fetch, not only after clone (ifcurl-t1k)
- bcf.py: add description param to build_bcf(); markup.bcf now includes
<Description> when provided (ifcurl-7wg)
- service.py: pass request URL as description to build_bcf() (ifcurl-7wg)
- viewer.html: BCF export reads visibility= from URL and sets
DefaultVisibility accordingly (ifcurl-sto)
- viewer.html: applyCameraParam now switches to orthographic projection
and applies scale when scale= is present in URL (ifcurl-4l7)
- tests: 3 new tests for description field; update JS tests pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- forgejo/server-config/ifcurl-preview.service: systemd unit for the preview
service with dedicated user, EnvironmentFile for cache config, and
--allowed-hosts in ExecStart
- forgejo/server-config/gitconfig-ifcmerge: registers two [merge] driver
variants (ifcmerge and ifcmerge_ours) for the asymmetric .ifc merge case
- forgejo/README.md: systemd deployment section (manual + service), ifcmerge
section covering Perl script install, driver registration, per-repo
gitattributes, and merge-direction constraint (merge-commit preserves main's IDs)
- README.md: remove stale "IFC file proxy" description; update quick-summary
to show systemd install path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The preview endpoint is co-hosted with a specific Forgejo instance, so it
should only be allowed to fetch from that host.
- Local file transport (ifc:///path) is always rejected with 403 — the service
must not read from the server's own filesystem
- New --allowed-hosts CLI option for `ifcurl serve` takes a comma-separated
list of permitted git hostnames (e.g. git.example.com or localhost:3000);
any unlisted host is rejected with 403
- Defense-in-depth: literal private/loopback/link-local IP addresses are
blocked even without an allowlist (169.254.x.x, 127.x, RFC1918, etc.)
- README and forgejo/README.md updated to include --allowed-hosts in the
standard deployment invocation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /proxy endpoint was removed in a previous session (ifcurl-cuh).
Remove it from the endpoints table in README.md.
New beads issues:
- ifcurl-2v9 P2: SSRF audit for /preview endpoint
- ifcurl-69l P3: licence headers for viewer.html, viewer-url.js, footer.tmpl
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrite to lead with the vision and architecture, then cover each of the
four components (Python library+CLI, preview service, Forgejo integration,
browser viewer) with enough detail to understand what each does and how
to use it. Add a roadmap table showing phases 1-6. Keep the ifc:// URL
reference but trim it to the essentials — SPECIFICATION.md has the full
detail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ifcurl/auth.py: token config (~/.config/ifcurl/tokens.json),
get_token_for_host(), inject_token() for HTTPS URL credential injection
- ifcurl/git.py: thread token= through fetch_ifc/fetch_ifc_bytes/_open_remote;
authenticated fetch uses 'git fetch <auth_url> +refs/*:refs/*' so the
token is never written to on-disk git config
- ifcurl/service.py: optional token field in PreviewRequest; request token
takes precedence over config-file token; get_token_for_host imported at
module level for clean monkeypatching in tests
- tests
Generated with the assistance of an AI coding tool.
- ifcurl/service.py: FastAPI POST /preview → image/png with three
caching tiers (bytes LRU, GUID-set LRU, PNG filesystem)
- ifcurl/git.py: add fetch_ifc() returning (hexsha, bytes); refactor
around _get_repo() and _read_commit_blob() helpers
- ifcurl/__main__.py: add 'ifcurl serve' subcommand; no-args prints
full help; all subcommands have descriptions and examples; URL format
and parameter reference in every help page
Generated with the assistance of an AI coding tool.