# Running this Q-App in Qortal Hub (and on QDN) The [Qortal](https://github.com/qortal) org hosts the core chain, [Qortal-Hub](https://github.com/Qortal/Qortal-Hub), [qapp-core](https://github.com/Qortal/qapp-core) helpers, and app examples. For protocol-level behaviour of websites vs apps, see [**Q-Apps.md** in the qortal core repo](https://github.com/Qortal/qortal/blob/master/Q-Apps.md) and the [**Q-Apps** section on qortal.dev](https://qortal.dev/docs/q-apps). ## 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](https://github.com/Qortal/qortal/blob/master/Q-Apps.md): - **`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 **`<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” 1. **You must use the Qortal Hub** `GET_USER_ACCOUNT` is not a public HTTP API. It is implemented by the Hub’s `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 name’s **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-App’s 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](https://qortal.dev/docs/q-apps); the builder uses it via `getQortalRequest()` in `src/lib/qortalEnv.ts`. - **Official REST / node API reference (debugging):** [Qortal API Documentation](https://api.qortal.org/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 - [Qortal on GitHub](https://github.com/qortal) — core, Hub, `qapp-core`, and example apps. - [Q-Apps.md (qortal core)](https://github.com/Qortal/qortal/blob/master/Q-Apps.md) — QDN resources, `qortalRequest`, routing. - [qortal.dev Q-Apps docs](https://qortal.dev/docs/q-apps) — API overview. - [Qortal API documentation](https://api.qortal.org/api-documentation/) — node/REST reference for debugging and cross-checking shapes. - [qapp-core README](https://github.com/Qortal/qapp-core) — optional npm helpers for new apps.