Skip to content

fix(core): restore remote project import from a shareable link - #15

Merged
DavidBabinec merged 1 commit into
mainfrom
fix/remote-project-import
Aug 17, 2026
Merged

fix(core): restore remote project import from a shareable link#15
DavidBabinec merged 1 commit into
mainfrom
fix/remote-project-import

Conversation

@DavidBabinec

Copy link
Copy Markdown
Contributor

The bug

Remote import from a shareable link vanished in 2.0.0. Anyone holding a
coreframework.com/app/<id> link had nowhere to paste it, and third parties
like Brixies, whose setup docs tell people to paste one into project settings,
were sending users to a field that no longer existed.

It broke in two steps. 87855079 stripped the client-side API key out of the
importer's fetch, which is right for a public repo, but it left a request the
deployed function answered with a 400. 6d56e9f0 then deleted the UI that
could no longer work, and the endpoint was recorded in the open-source boundary
check as a "retired hosted preset importer". It was never retired. It was
serving traffic the whole time and still is.

The fix

fetchRemotePreset.ts sits on the platform seam already used across the
monorepo, so each shell supplies its own implementation:

  • parseRemotePresetId takes a bare ID or a full shareable link and validates
    it against the ULID alphabet, matching the server regex, so bad input fails
    without a round trip.
  • www fetches the public endpoint directly, which sends
    Access-Control-Allow-Origin: *.
  • WordPress goes through a new core-framework/v2/remote-import route behind
    the existing verify_nonce check (manage_options plus nonce).

The REST route accepts an ID and never a URL. The endpoint is a class constant
and the ID is regex validated before use, so there is no caller-controlled URL
to guard against. It also sets redirection => 0, a 15 second timeout, and an
8 MB body cap.

The boundary check now forbids x-api-key in shipped source instead of
forbidding the endpoint. That blocks the mistake that actually caused this,
which was shipping a credential, rather than blocking the feature.

Not done here: the onboarding file and UI kit start options. Those were
commented out in February 2024 and were never live in the 2.x line, so turning
them on is a product decision rather than part of this fix.

Screenshot

The restored field, and a project loaded from a link. Note Always Light in
the imported column, a group that does not exist in the local project, so that
is genuinely remote data.

Verification

bun run test:www                      # 23 suites, 147 pass, 0 fail
bun run lint                          # clean, 5 pre-existing warnings unchanged
bun run build:www                     # built in 3.50s
bun run build:wp                      # built in 3.64s
packages/wp   tsc --noEmit            # clean
packages/www  tsc --noEmit            # clean
php -l AllPoints.php                  # No syntax errors detected
check-open-source-boundaries.ts all   # passed

The seam resolves the way it should. The WordPress bundle contains the REST
route and no reference to the third-party host, so the admin browser never
calls it:

rg -c "remote-import" packages/wp/dist/main-*.js            # 1
rg -c "cloudfunctions.net/getPreset" packages/wp/dist/main-*.js   # no matches

Endpoint behaviour, checked against production before and after the function
was redeployed:

Request Before After
valid ULID, no key 400 404
malformed id 400 400
real public project 400 200 with project JSON

Notes

This needs the getPreset function deployed to work, which is done. It now
runs on Node 22, since Node 18 was decommissioned on 2025-10-31 and Node 20
decommissions on 2026-10-31. That change lives in the website repo and is up
as a separate PR.

WordPress is verified by build, typecheck, and bundle inspection, but the PHP
route has not been exercised against a running WordPress install.

Preparing 2.0.0 for open source stripped the importer's client-side API
key, so every request started failing with a 400, and the input that no
longer worked was deleted the next day. That took out a working feature
and broke every shareable link already in circulation.

WordPress now fetches the project through the plugin's own REST route
rather than from the browser, so the request leaves the server and the
admin screen never contacts a third-party host.
@DavidBabinec
DavidBabinec merged commit 5b6d878 into main Aug 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant