Appearance
Static app packages
Most Matrix webapps are static-asset packages: a built dist/browser/ directory containing HTML, JS, CSS, images. The gateway serves them through MatrixHttpAssetEndpointActor.
Package shape
A static app package's matrix.json:
json
{
"name": "@open-matrix/chat",
"webapp": {
"appName": "chat",
"displayName": "Chat",
"icon": "💬",
"navOrder": 10,
"shells": ["platform"],
"description": "...",
"routePrefix": "/apps/chat/"
},
"components": [
{
"type": "ChatActor",
"mount": "chat",
"autoStart": true,
"...": "..."
}
]
}The package's runtime, when started, reads webapp.distDir (or the build-derived equivalent) and configures a MatrixHttpAssetEndpointActor mounted at chat.http pointing at that directory.
Asset endpoint config
typescript
interface IMatrixHttpAssetEndpointConfig {
packageName: string; // for diagnostics
appName: string; // 'chat'
distDir: string; // absolute path resolved at mount time
entryFile: string; // typically 'index.html'
}The runtime resolves distDir from:
package-install-path + matrix.json.webapp.distDir (if set)For a package installed via npm install @open-matrix/chat, that's typically <host-home>/packages/global/node_modules/@open-matrix/chat/dist/browser.
Asset endpoint mount path
typescript
function buildMatrixHttpAssetMount(appName: string, runtimeId?: string): string {
if (runtimeId) {
return `system.runtimes.${runtimeId}.http`;
}
return `${appName}.http`;
}If a runtimeId is provided, the mount is namespaced under system.runtimes.<id>.http to avoid collisions when multiple runtimes serve the same appName. Otherwise it's the simple <appName>.http.
Webapp record advertisement
Alongside the asset mount, the runtime advertises a webapp record in its runtime metadata. This is what _loadRoutes reads:
typescript
{
appName: 'chat',
runtimeId: 'RUNTIME-host-chat',
packageName: '@open-matrix/chat',
webapp: {
assetMount: 'chat.http',
appName: 'chat',
displayName: 'Chat',
routePrefix: '/apps/chat/',
shells: ['platform'],
icon: '💬',
navOrder: 10
}
}The record reaches the gateway through:
- The host-runtime record file (
<host-home>/runtimes/<id>/runtime.json), written by host-service when the runtime starts. - The runtime registry actor (
system.runtimes.runtimes.registered).
Request flow
Browser GET /apps/chat/assets/index.js
→ Gateway HTTP listener
→ onWebapp handler
→ SystemGatewayHttpActor.onGatewayHttpRequest('chat', pathname)
→ _loadRoutes (joins records + registry)
→ _resolveRoute → { assetMount: 'chat.http', runtimeId: 'RUNTIME-host-chat' }
→ RequestReply.execute('chat.http', 'http.asset.request', { pathname, method: 'GET' })
→ MatrixHttpAssetEndpointActor.onHttpAssetRequest
→ resolveStaticAssetPath('assets/index.js', distDir) → filePath
→ fs.readFile(filePath) → bytes
→ return { ok: true, statusCode: 200, headers: { 'content-type': 'text/javascript' }, bodyEncoding: 'base64', bodyBase64: ... }
→ Gateway writes HTTP response to browserEnd-to-end: one HTTP request, one Matrix RR, one filesystem read.
SPA fallback
For client-side-routed SPAs, a path like /apps/chat/conversations/abc is not a real file. The asset endpoint detects this:
typescript
const resolved = resolveStaticAssetPath(pathname, config);
if (!resolved) {
return { ok: false, statusCode: 404, ... };
}If the SPA package has its dist set up so index.html is the fallback (the common case), the resolver returns index.html's path. The browser then loads index.html and the SPA's client-side router handles the path.
What can go wrong
| Failure | Cause | Fix |
|---|---|---|
| 404 for valid asset | distDir not resolved correctly at mount; runtime points at wrong directory | Check runtime.json.metadata.webapp.assetMount and the resolved distDir |
| 502 with "exceeded relay limit" | File >10 MB | Reduce asset size; chunked delivery is target state |
| Slow first request | RR call to runtime registry; cold-start cost | Acceptable; subsequent requests reuse parsed routes |
Missing MIME type / application/octet-stream | File extension not in MIME_TYPES table | Use one of the supported extensions or override in package config |
See also
- Static assets — the gateway-side view
- Runtime-backed apps — apps that combine static + service
- Cache and invalidation
Source:
projects/matrix-3/packages/system-gateway-http/src/index.ts:80-219.