Includes QWB, Qortal Web, and Q-Shops Q-Apps with shared packages and build scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
6.9 KiB
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
-
npm run build— producesdist/withindex.html,assets/,manifest.json,zip-store.js,favicon.svg, etc. -
Create a flat zip of everything inside
dist/(not the parent “Portfolio” zip that also wrapsapp.js/extracted/— that is for a different release layout). The Hub and QDN expect the Q-App root to match the zip root:index.htmlnext toassets/…andzip-store.js.Use either:
bash scripts/make-zip.sh— zips thedist/tree intoQortal-Hub-Dev-Test-YYYYMMDD.zipand mirrors toextracted/, or- Manually:
( cd dist && zip -r ../my-qapp.zip . )
-
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 missingfilepathreturns 404; there is no automatic “send everything toindex.html” for unknown paths.APP: unhandled requests are routed toindex.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 <base href> (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”
-
You must use the Qortal Hub
GET_USER_ACCOUNTis not a public HTTP API. It is implemented by the Hub’sqortalRequest(injected in the page, or forwarded from our inline stub towindow.parent). Opening the builtsite.htmlorindex.htmlin Chrome/Firefox alone (file:// or a randomhttps://host) cannot complete wallet auth. -
Inline bridge + top-level window
If the Hub has not injectedqortalRequestand our fallback stub is active (__QWB_QORTAL_BRIDGE_STUB__onwindow), wallet calls are sent towindow.parent. If you are not inside a Hub iframe (parent === top), that path fails by design. Open the resource from the Hub (Browse → your name’s WEBSITE, orqortal://WEBSITE/…). -
Hub version
Older Hub builds may handlepostMessage/MessageChannelforGET_USER_ACCOUNTdifferently. Update the Hub if auth always times out. -
Embedded Q-Apps after you authenticated the page
The site can append_snConnto embed URLs only after you use Authenticate.
The published WEBSITE page includes a small message relay (site.html/dev.html): when an embedded Q-App’s stub sendsqortalRequestto its parent (this site, not the Hub), the parent calls its ownqortalRequestand returns the result on theMessageChannelso 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 viagetQortalRequest()insrc/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
qortalRequestactions (seesrc/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
- Network tab:
assets/index-*.jsandindex-*.cssmust be 200 (same folder asindex.html). Root-absolute paths like/assets/...or/zip-store.jsoften 404 when the app is not at the site root — this project uses relative./URLs and stripscrossorigininvite.config.tsto avoid CORS-related fetch failures in some Hub builds. - Zip layout: the paths inside the zip must match what the browser requests (flat
distcontents). - Re-run
npm run buildafter any HTML/Vite config change, then re-zip onlydist/.
References
- Qortal on GitHub — core, Hub,
qapp-core, and example apps. - Q-Apps.md (qortal core) — QDN resources,
qortalRequest, routing. - qortal.dev Q-Apps docs — API overview.
- Qortal API documentation — node/REST reference for debugging and cross-checking shapes.
- qapp-core README — optional npm helpers for new apps.