Files
Simon James b54a3139c7 Initial commit: Qortal Web Builder monorepo.
Includes QWB, Qortal Web, and Q-Shops Q-Apps with shared packages and build scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 12:17:29 +00:00

6.9 KiB
Raw Permalink Blame History

Running this Q-App in Qortal Hub (and on QDN)

The Qortal org hosts the core chain, Qortal-Hub, qapp-core helpers, and app examples. For protocol-level behaviour of websites vs apps, see Q-Apps.md in the qortal core repo and the Q-Apps section on qortal.dev.

What to ship

  1. npm run build — produces dist/ with index.html, assets/, manifest.json, zip-store.js, favicon.svg, etc.

  2. Create a flat zip of everything inside dist/ (not the parent “Portfolio” zip that also wraps app.js / extracted/ — that is for a different release layout). The Hub and QDN expect the Q-App root to match the zip root: index.html next to assets/… and zip-store.js.

    Use either:

    • bash scripts/make-zip.sh — zips the dist/ tree into Qortal-Hub-Dev-Test-YYYYMMDD.zip and mirrors to extracted/, or
    • Manually: ( cd dist && zip -r ../my-qapp.zip . )
  3. In Qortal Hub, load that zip and use Preview (see Q-Apps.md: Select "Preview" in the UI after choosing the zip) so you can test before publishing to QDN.

WEBSITE vs APP (important for a Vite SPA)

From Q-Apps / QDN routing:

  • WEBSITE: a missing filepath returns 404; there is no automatic “send everything to index.html” for unknown paths.
  • APP: unhandled requests are routed to index.html, which is what most single-page apps (React + client router) expect when the host resolves subpaths.

For the builder UI loaded as a registered Q-App, prefer publishing/loading it as an APP-style package when the Hub allows it, so subpaths and asset loading behave like a normal SPA. Your published end-user site (users website.zip) is still a WEBSITE resource where appropriate.

APP preview: “Could not load … /render/APP/…/assets/…”

If the Hub opens the app at a URL like /render/APP/YourName without a trailing slash, the browser resolves relative URLs such as ./assets/index-….js against /render/APP/ (dropping your name from the path), so JS/CSS 404. WEBSITE URLs often include index.html or a trailing slash, so the same zip can appear to work only as WEBSITE.

This project injects a &lt;base href&gt; (see the first script in dev.html / site.html) so the app root always ends with /. Rebuild and re-zip dist/ after pulling this fix.

Published site: embedded Q-Apps and wallet

Visitors are not auto-connected to the Hub wallet: they must click Authenticate in the site chrome. Only then does the store hold a wallet address, sessionTag updates, embed URL cache clears, and _snConn is appended to embedded /render/APP/… iframe URLs so the Hub can align the child frame with the parent session. The embed resolver reads sessionTag only after await (no stale _snConn).

If auth inside an embedded Q-App still fails after you authenticated the page, that is often a Hub limitation (qortalRequest only in the top window). Use Open in Qortal on the Q-App tile (new tab). For core fixes, the Hub team needs version, OS, and whether the inner app uses qortalRequest.

Why Authenticate or Connect “does nothing”

  1. You must use the Qortal Hub
    GET_USER_ACCOUNT is not a public HTTP API. It is implemented by the Hubs qortalRequest (injected in the page, or forwarded from our inline stub to window.parent). Opening the built site.html or index.html in Chrome/Firefox alone (file:// or a random https:// host) cannot complete wallet auth.

  2. Inline bridge + top-level window
    If the Hub has not injected qortalRequest and our fallback stub is active (__QWB_QORTAL_BRIDGE_STUB__ on window), wallet calls are sent to window.parent. If you are not inside a Hub iframe (parent === top), that path fails by design. Open the resource from the Hub (Browse → your names WEBSITE, or qortal://WEBSITE/…).

  3. Hub version
    Older Hub builds may handle postMessage / MessageChannel for GET_USER_ACCOUNT differently. Update the Hub if auth always times out.

  4. Embedded Q-Apps after you authenticated the page
    The site can append _snConn to embed URLs only after you use Authenticate.
    The published WEBSITE page includes a small message relay (site.html / dev.html): when an embedded Q-Apps stub sends qortalRequest to its parent (this site, not the Hub), the parent calls its own qortalRequest and returns the result on the MessageChannel so the embed can use the same wallet. If a Q-App still cannot connect, use Open in Qortal on the tile, or check Hub version.

What to send when reporting issues: Qortal Hub version, OS, exact URL (e.g. qortal://WEBSITE/Name vs external site), browser console errors, and whether window.qortalRequest exists and is native or the stub (__QWB_QORTAL_BRIDGE_STUB__).

Runtime API

  • qortalRequest() is injected by the core; the builder uses it via getQortalRequest() in src/lib/qortalEnv.ts.
  • Official REST / node API reference (debugging): Qortal API Documentation — useful to compare request/response field names and node behaviour with what the Hub bridge returns; interactive flows in this app use qortalRequest actions (see src/lib/qortalClient.ts), not raw HTTP, but the same domain concepts apply.
  • Q-Apps are static files; ship fonts and JS in the zip — avoid relying on public CDNs for required assets (see project .cursor/rules/qortal-qdn-sandbox.mdc).

If the UI stays on “Loading…” or a gray screen

  1. Network tab: assets/index-*.js and index-*.css must be 200 (same folder as index.html). Root-absolute paths like /assets/... or /zip-store.js often 404 when the app is not at the site root — this project uses relative ./ URLs and strips crossorigin in vite.config.ts to avoid CORS-related fetch failures in some Hub builds.
  2. Zip layout: the paths inside the zip must match what the browser requests (flat dist contents).
  3. Re-run npm run build after any HTML/Vite config change, then re-zip only dist/.

References