@volter/world-console 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +17 -0
- package/client/brand/fonts/Geist-Variable.woff2 +0 -0
- package/client/brand/fonts/GeistMono-Variable.woff2 +0 -0
- package/client/brand/fonts/InstrumentSerif-Italic.woff2 +0 -0
- package/client/brand/fonts/InstrumentSerif-Regular.woff2 +0 -0
- package/client/brand/fonts/LICENSES.txt +191 -0
- package/client/brand/tokens.css +212 -0
- package/client/console.css +113 -0
- package/client/console.tsx +815 -0
- package/dist/client/brand/fonts/Geist-Variable.woff2 +0 -0
- package/dist/client/brand/fonts/GeistMono-Variable.woff2 +0 -0
- package/dist/client/brand/fonts/InstrumentSerif-Italic.woff2 +0 -0
- package/dist/client/brand/fonts/InstrumentSerif-Regular.woff2 +0 -0
- package/dist/client/brand/fonts/LICENSES.txt +191 -0
- package/dist/client/brand/tokens.css +212 -0
- package/dist/client/console.bundle.js +235 -0
- package/dist/client/console.css +113 -0
- package/dist/client/console.tsx +815 -0
- package/dist/src/console.d.ts +22 -0
- package/dist/src/console.js +57 -0
- package/package.json +53 -0
- package/src/console.ts +61 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ConsoleMount = {
|
|
2
|
+
/** `worlds`: the origin the Worlds are served at, when the console has an origin of its own; `names`: the
|
|
3
|
+
* Worlds (`<org>/<world>`) a World token may open there, for a host that does not list its Worlds (a hosted one). */
|
|
4
|
+
handle: (request: Request, base: string, opts?: {
|
|
5
|
+
worlds?: string;
|
|
6
|
+
names?: string[];
|
|
7
|
+
}) => Promise<Response | null>;
|
|
8
|
+
/** Serve the shell with a session already in it — the platform's portal (managed mode). */
|
|
9
|
+
/** `scripts`: HTML the mount puts before the app script — the platform's identity keep-alive rides here. */
|
|
10
|
+
shell: (base: string, opts: {
|
|
11
|
+
token: string;
|
|
12
|
+
managed: boolean;
|
|
13
|
+
scripts?: string;
|
|
14
|
+
}) => Response;
|
|
15
|
+
};
|
|
16
|
+
/** The client, built once per process and kept (bundleClient: Bun.build under Bun, the prebuilt
|
|
17
|
+
* dist/client/console.bundle.js under Node, written by this package's build). */
|
|
18
|
+
export declare function buildConsoleClient(): Promise<string>;
|
|
19
|
+
/** The console as a host mounts it: `handle(request, '/-/console')` answers the shell at `base/`,
|
|
20
|
+
* the bundle at `base/app.js`, the styles at `base/styles.css` over the brand's at `base/brand/`, and the shell again for any deeper
|
|
21
|
+
* path (the client routes by path: `base/<org>/<world>`), or null for a path outside `base`. */
|
|
22
|
+
export declare function createConsole(): ConsoleMount;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// THE CONSOLE (apps/console/README.md, 2026-09-06): the one UI of Volter World, a PURE
|
|
2
|
+
// FRONTEND the way a pack's mirror is — a React client bundled by `Bun.build` at serve time behind
|
|
3
|
+
// one app shell, with no data path of its own. Every read and every write the console makes is a
|
|
4
|
+
// door of the host or of a world, called from the browser with the token the person typed. The
|
|
5
|
+
// host mounts it at `/-/console/` (the same origin as the doors: one origin, one token, no CORS);
|
|
6
|
+
// the platform serves the same client later. This module is the shell and its assets; `handle`
|
|
7
|
+
// answers a request under `base` or returns null when the path is not the console's.
|
|
8
|
+
import { brandTokensResponse, bundleClient, fileResponse } from '@volter/world-core';
|
|
9
|
+
const CLIENT_ENTRY = () => new URL('../client/console.tsx', import.meta.url).pathname; // lazy: never a top-level import.meta.url URL (workerd)
|
|
10
|
+
const CLIENT_CSS = () => new URL('../client/console.css', import.meta.url).pathname;
|
|
11
|
+
/** The brand's tokens and faces (company decision 0018), fetched at build into client/brand/ (gitignored). */
|
|
12
|
+
const BRAND_DIR = () => new URL('../client/brand', import.meta.url).pathname;
|
|
13
|
+
// The shell carries the base, and optionally a session and the managed flag: a host mounts the
|
|
14
|
+
// console with neither (the person types a token); the platform serves it with a session token
|
|
15
|
+
// (skip the sign-in) and `managed` set (a world opens on its own host, never proxied through here).
|
|
16
|
+
const attr = (v) => v.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
17
|
+
/** Volter World's mark, served by the brand (brand.volter.ai): the favicon. */
|
|
18
|
+
const WORLD_LOGO = 'https://brand.volter.ai/logo/twin-world/svg?size=64&variant=mono';
|
|
19
|
+
const SHELL = (base, opts = {}) => `<!doctype html>
|
|
20
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
21
|
+
<title>Volter World</title><link rel="icon" type="image/svg+xml" href="${WORLD_LOGO}"><link rel="stylesheet" href="${base}/brand/tokens.css"><link rel="stylesheet" href="${base}/styles.css"></head>
|
|
22
|
+
<body><div id="root" data-base="${base}"${opts.worlds ? ` data-worlds="${attr(opts.worlds)}"` : ''}${opts.names?.length ? ` data-names="${attr(opts.names.join(','))}"` : ''}${opts.token ? ` data-token="${attr(opts.token)}"` : ''}${opts.managed ? ' data-managed="1"' : ''}></div>${opts.scripts ?? ''}<script type="module" src="${base}/app.js"></script></body></html>`;
|
|
23
|
+
/** The client, built once per process and kept (bundleClient: Bun.build under Bun, the prebuilt
|
|
24
|
+
* dist/client/console.bundle.js under Node, written by this package's build). */
|
|
25
|
+
export function buildConsoleClient() { return bundleClient(CLIENT_ENTRY()); }
|
|
26
|
+
/** The console as a host mounts it: `handle(request, '/-/console')` answers the shell at `base/`,
|
|
27
|
+
* the bundle at `base/app.js`, the styles at `base/styles.css` over the brand's at `base/brand/`, and the shell again for any deeper
|
|
28
|
+
* path (the client routes by path: `base/<org>/<world>`), or null for a path outside `base`. */
|
|
29
|
+
export function createConsole() {
|
|
30
|
+
return {
|
|
31
|
+
async handle(request, base, opts = {}) {
|
|
32
|
+
const path = new URL(request.url).pathname;
|
|
33
|
+
if (path !== base && !path.startsWith(`${base}/`))
|
|
34
|
+
return null;
|
|
35
|
+
if (request.method !== 'GET' && request.method !== 'HEAD')
|
|
36
|
+
return null;
|
|
37
|
+
if (path === `${base}/app.js`) {
|
|
38
|
+
try {
|
|
39
|
+
return new Response(await buildConsoleClient(), { headers: { 'content-type': 'text/javascript; charset=utf-8', 'cache-control': 'no-cache' } });
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return new Response(String(error), { status: 500 });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (path === `${base}/styles.css`)
|
|
46
|
+
return fileResponse(CLIENT_CSS());
|
|
47
|
+
if (path.startsWith(`${base}/brand/`))
|
|
48
|
+
return brandTokensResponse(BRAND_DIR(), path.slice(`${base}/brand/`.length));
|
|
49
|
+
if (path === base)
|
|
50
|
+
return Response.redirect(`${base}/`, 302);
|
|
51
|
+
return new Response(SHELL(base, { ...(opts.worlds ? { worlds: opts.worlds } : {}), ...(opts.names?.length ? { names: opts.names } : {}) }), { headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' } });
|
|
52
|
+
},
|
|
53
|
+
shell(base, opts) {
|
|
54
|
+
return new Response(SHELL(base, opts), { headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' } });
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@volter/world-console",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "The console of Volter World: one UI for a world in both modes — self-hosted, mounted by the host at /-/console/; managed, served by the platform. A pure frontend over the world's own doors.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/src/console.d.ts",
|
|
9
|
+
"default": "./dist/src/console.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "bun test src/*.uitest.ts",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"build": "bun ../../scripts/brand-tokens.ts client/brand && node ../../scripts/publish/build.mjs",
|
|
16
|
+
"prepack": "bun ../../scripts/brand-tokens.ts client/brand && node ../../scripts/publish/prepare-publish.mjs prepack",
|
|
17
|
+
"postpack": "node ../../scripts/publish/prepare-publish.mjs postpack"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"react": "^19.2.7",
|
|
21
|
+
"react-dom": "^19.2.7"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@volter/world-host": "2.0.0",
|
|
25
|
+
"@volter/world-runtime": "2.0.0",
|
|
26
|
+
"@volter/world-tooling": "0.1.0",
|
|
27
|
+
"@types/bun": "^1.2.20",
|
|
28
|
+
"@types/node": "^24.0.0",
|
|
29
|
+
"@types/react": "^19.2.7",
|
|
30
|
+
"@types/react-dom": "^19.2.7",
|
|
31
|
+
"playwright": "^1.61.0",
|
|
32
|
+
"typescript": "^5.9.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"license": "Apache-2.0",
|
|
38
|
+
"files": [
|
|
39
|
+
"src",
|
|
40
|
+
"client",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"!**/*.test.ts",
|
|
44
|
+
"!**/*.uitest.ts",
|
|
45
|
+
"!census.json",
|
|
46
|
+
"dist"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/volter-ai/world.git",
|
|
51
|
+
"directory": "apps/console"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/console.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// THE CONSOLE (apps/console/README.md, 2026-09-06): the one UI of Volter World, a PURE
|
|
2
|
+
// FRONTEND the way a pack's mirror is — a React client bundled by `Bun.build` at serve time behind
|
|
3
|
+
// one app shell, with no data path of its own. Every read and every write the console makes is a
|
|
4
|
+
// door of the host or of a world, called from the browser with the token the person typed. The
|
|
5
|
+
// host mounts it at `/-/console/` (the same origin as the doors: one origin, one token, no CORS);
|
|
6
|
+
// the platform serves the same client later. This module is the shell and its assets; `handle`
|
|
7
|
+
// answers a request under `base` or returns null when the path is not the console's.
|
|
8
|
+
|
|
9
|
+
import { brandTokensResponse, bundleClient, fileResponse } from '@volter/world-core';
|
|
10
|
+
const CLIENT_ENTRY = () => new URL('../client/console.tsx', import.meta.url).pathname; // lazy: never a top-level import.meta.url URL (workerd)
|
|
11
|
+
const CLIENT_CSS = () => new URL('../client/console.css', import.meta.url).pathname;
|
|
12
|
+
/** The brand's tokens and faces (company decision 0018), fetched at build into client/brand/ (gitignored). */
|
|
13
|
+
const BRAND_DIR = () => new URL('../client/brand', import.meta.url).pathname;
|
|
14
|
+
|
|
15
|
+
// The shell carries the base, and optionally a session and the managed flag: a host mounts the
|
|
16
|
+
// console with neither (the person types a token); the platform serves it with a session token
|
|
17
|
+
// (skip the sign-in) and `managed` set (a world opens on its own host, never proxied through here).
|
|
18
|
+
const attr = (v: string): string => v.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
19
|
+
/** Volter World's mark, served by the brand (brand.volter.ai): the favicon. */
|
|
20
|
+
const WORLD_LOGO = 'https://brand.volter.ai/logo/twin-world/svg?size=64&variant=mono';
|
|
21
|
+
const SHELL = (base: string, opts: { token?: string; managed?: boolean; scripts?: string; worlds?: string; names?: string[] } = {}): string => `<!doctype html>
|
|
22
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
23
|
+
<title>Volter World</title><link rel="icon" type="image/svg+xml" href="${WORLD_LOGO}"><link rel="stylesheet" href="${base}/brand/tokens.css"><link rel="stylesheet" href="${base}/styles.css"></head>
|
|
24
|
+
<body><div id="root" data-base="${base}"${opts.worlds ? ` data-worlds="${attr(opts.worlds)}"` : ''}${opts.names?.length ? ` data-names="${attr(opts.names.join(','))}"` : ''}${opts.token ? ` data-token="${attr(opts.token)}"` : ''}${opts.managed ? ' data-managed="1"' : ''}></div>${opts.scripts ?? ''}<script type="module" src="${base}/app.js"></script></body></html>`;
|
|
25
|
+
|
|
26
|
+
export type ConsoleMount = {
|
|
27
|
+
/** `worlds`: the origin the Worlds are served at, when the console has an origin of its own; `names`: the
|
|
28
|
+
* Worlds (`<org>/<world>`) a World token may open there, for a host that does not list its Worlds (a hosted one). */
|
|
29
|
+
handle: (request: Request, base: string, opts?: { worlds?: string; names?: string[] }) => Promise<Response | null>;
|
|
30
|
+
/** Serve the shell with a session already in it — the platform's portal (managed mode). */
|
|
31
|
+
/** `scripts`: HTML the mount puts before the app script — the platform's identity keep-alive rides here. */
|
|
32
|
+
shell: (base: string, opts: { token: string; managed: boolean; scripts?: string }) => Response;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** The client, built once per process and kept (bundleClient: Bun.build under Bun, the prebuilt
|
|
36
|
+
* dist/client/console.bundle.js under Node, written by this package's build). */
|
|
37
|
+
export function buildConsoleClient(): Promise<string> { return bundleClient(CLIENT_ENTRY()); }
|
|
38
|
+
|
|
39
|
+
/** The console as a host mounts it: `handle(request, '/-/console')` answers the shell at `base/`,
|
|
40
|
+
* the bundle at `base/app.js`, the styles at `base/styles.css` over the brand's at `base/brand/`, and the shell again for any deeper
|
|
41
|
+
* path (the client routes by path: `base/<org>/<world>`), or null for a path outside `base`. */
|
|
42
|
+
export function createConsole(): ConsoleMount {
|
|
43
|
+
return {
|
|
44
|
+
async handle(request, base, opts = {}) {
|
|
45
|
+
const path = new URL(request.url).pathname;
|
|
46
|
+
if (path !== base && !path.startsWith(`${base}/`)) return null;
|
|
47
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') return null;
|
|
48
|
+
if (path === `${base}/app.js`) {
|
|
49
|
+
try { return new Response(await buildConsoleClient(), { headers: { 'content-type': 'text/javascript; charset=utf-8', 'cache-control': 'no-cache' } }); }
|
|
50
|
+
catch (error) { return new Response(String(error), { status: 500 }); }
|
|
51
|
+
}
|
|
52
|
+
if (path === `${base}/styles.css`) return fileResponse(CLIENT_CSS());
|
|
53
|
+
if (path.startsWith(`${base}/brand/`)) return brandTokensResponse(BRAND_DIR(), path.slice(`${base}/brand/`.length));
|
|
54
|
+
if (path === base) return Response.redirect(`${base}/`, 302);
|
|
55
|
+
return new Response(SHELL(base, { ...(opts.worlds ? { worlds: opts.worlds } : {}), ...(opts.names?.length ? { names: opts.names } : {}) }), { headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' } });
|
|
56
|
+
},
|
|
57
|
+
shell(base, opts) {
|
|
58
|
+
return new Response(SHELL(base, opts), { headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' } });
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|