Add /import?src=<url>: a hand-off point for scanning apps - #720
Add /import?src=<url>: a hand-off point for scanning apps#720alxbouchard wants to merge 3 commits into
Conversation
A scanning app (or any external tool) can now open editor.pascal.app/import?src=<https-url> to hand a build JSON to the editor. The fetch happens client-side in the visitor's browser (same trust model as dropping a file on Load Build; the host must allow CORS), the file runs through the same validateBuildJson pre-flight, the visitor reviews the contents, and only an explicit click creates the scene through the regular POST /api/scenes route — so auth, origin checks and apiGraphSchema validation all apply unchanged. src accepts https only (http for localhost during development), no embedded credentials, 25 MB cap. Unit tests for the URL validation.
validateBuildJson dropped the top-level materials table: every scene:<id> slot ref in an imported file pointed at a material that no longer existed, so custom finishes silently reverted to defaults on both Load Build and /import. ParsedBuildJson now carries materials — each entry SceneMaterial-validated individually, invalid ones skipped with a warning so a bad material never takes the import down — and handleConfirmImport hands them to setScene, whose extra.materials support already existed. Unit tests for valid, partially-invalid and non-object materials.
|
Follow-up commit: while testing the import end to end I found that |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 81715bc. Configure here.
| */ | ||
|
|
||
| /** Hard cap on the fetched document; matches generous hand-made scenes. */ | ||
| export const MAX_IMPORT_BYTES = 25 * 1024 * 1024 |
There was a problem hiding this comment.
Import cap exceeds scene store
Medium Severity
MAX_IMPORT_BYTES is 25 MB while the SQLite scene store defaults to 10 MB (DEFAULT_MAX_SCENE_BYTES). A build that passes review can still fail on POST /api/scenes with 413, and the UI only shows a generic create failure instead of a size explanation.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 81715bc. Configure here.
Review feedback (Bugbot): a superseded or aborted fetch could overwrite a newer state — including surfacing the cleanup abort as a CORS error — and a src change left the previous review (and its Import button) live against the old file. The effect now resets to 'fetching' on every src change and every state update from a cancelled run is ignored.
|
Addressed the Bugbot review (it ran against the first commit, 53b688c):
|


What
A new
/import?src=<https-url>[&name=<scene name>]page: an external tool — in our case an iOS LiDAR scanning app — hosts a build JSON at a URL and opens this page; the visitor reviews what the file contains and imports it as a new scene with one click.Until now the only way to get a generated scene into the editor was dragging a file onto Load Build, which does not exist on mobile. With this page, any scan app can end its export flow with "Open in Pascal Editor".
How it works
validateBuildJsonpre-flight as Load Build, and the page shows the node counts, floor area, warnings and errors before anything happens.POST /api/scenesroute — so auth, origin checks andapiGraphSchemavalidation (including the AssetUrl allowlist) all apply unchanged.srcaccepts https only (http for localhost during development), rejects embedded credentials, and caps the document at 25 MB. URL validation lives inlib/import-src.tswith unit tests.Tested
bun test lib: 41 pass (6 new)bun run check-types,biome check: cleanWhy we built it
We build A3 Atlas Scanner, an iOS field tool that captures homes with RoomPlan and already exports your
{nodes, rootNodeIds, materials}graph (catalog items scaled to measured dimensions, measured colors as scene materials, IFC alongside). This page is the missing link that turns every scan into a one-tap Pascal scene. Happy to adjust anything to fit the project's conventions.🤖 Generated with Claude Code
Note
Medium Risk
Introduces a new user-facing import surface and changes how build JSON is normalized (materials), though URL fetch stays client-side and scene creation still goes through the existing authenticated API.
Overview
Adds
/import?src=<https-url>[&name=…]so external tools (e.g. scan apps) can hand off a CORS-hosted build JSON: the browser fetches it, runsvalidateBuildJsonlike Load Build, shows stats/warnings/errors, and only on confirm creates a scene viaPOST /api/scenes(auth and existing graph validation unchanged).parseImportSrcinlib/import-src.tsrestrictssrcto https (http on localhost only), blocks credentials and bad schemes, and enforces a 25 MB cap, with unit tests.validateBuildJsonnow parses a top-levelmaterialsmap intoParsedBuildJson, skipping invalid entries withinvalid_materialswarnings instead of failing the import. The settings panel Load Build path passes those materials intosetScenesoscene:<id>slot refs keep custom finishes instead of reverting to defaults.Reviewed by Cursor Bugbot for commit 1ced72b. Bugbot is set up for automated code reviews on this repo. Configure here.