toiljs 0.0.67 → 0.0.69
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/CHANGELOG.md +10 -0
- package/README.md +63 -61
- package/build/backend/.tsbuildinfo +1 -1
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +13 -1
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/index.d.ts +2 -0
- package/build/client/index.js +1 -0
- package/build/client/rpc.js +21 -1
- package/build/client/stream/client.d.ts +11 -0
- package/build/client/stream/client.js +59 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/config.d.ts +2 -0
- package/build/compiler/config.js +9 -7
- package/build/compiler/index.d.ts +1 -0
- package/build/compiler/index.js +16 -2
- package/build/compiler/toil-docs.generated.js +5 -4
- package/build/devserver/.tsbuildinfo +1 -1
- package/build/devserver/daemon/runtime.d.ts +13 -0
- package/build/devserver/daemon/runtime.js +29 -0
- package/build/devserver/db/database.d.ts +1 -0
- package/build/devserver/db/database.js +10 -0
- package/build/devserver/db/derives.d.ts +7 -0
- package/build/devserver/db/derives.js +94 -0
- package/build/devserver/db/index.d.ts +1 -0
- package/build/devserver/db/index.js +1 -0
- package/build/devserver/db/types.d.ts +1 -0
- package/build/devserver/db/types.js +1 -0
- package/build/devserver/http/proxy.d.ts +5 -1
- package/build/devserver/http/proxy.js +39 -36
- package/build/devserver/http/runtime.d.ts +62 -0
- package/build/devserver/http/runtime.js +194 -0
- package/build/devserver/index.d.ts +2 -0
- package/build/devserver/index.js +1 -0
- package/build/devserver/production-ipc.d.ts +50 -0
- package/build/devserver/production-ipc.js +21 -0
- package/build/devserver/production-worker.d.ts +1 -0
- package/build/devserver/production-worker.js +73 -0
- package/build/devserver/production.d.ts +35 -0
- package/build/devserver/production.js +502 -0
- package/build/devserver/runtime/module.d.ts +5 -0
- package/build/devserver/runtime/module.js +47 -1
- package/build/devserver/server.d.ts +1 -0
- package/build/devserver/server.js +32 -145
- package/build/devserver/ssr.d.ts +2 -0
- package/build/devserver/ssr.js +19 -2
- package/build/devserver/stream/catalog.d.ts +20 -0
- package/build/devserver/stream/catalog.js +54 -0
- package/build/devserver/stream/host.d.ts +9 -0
- package/build/devserver/stream/host.js +15 -0
- package/build/devserver/stream/index.d.ts +37 -0
- package/build/devserver/stream/index.js +220 -0
- package/build/devserver/stream/manager.d.ts +34 -0
- package/build/devserver/stream/manager.js +103 -0
- package/build/devserver/stream/router.d.ts +25 -0
- package/build/devserver/stream/router.js +64 -0
- package/build/devserver/stream/wire.d.ts +5 -0
- package/build/devserver/stream/wire.js +33 -0
- package/build/devserver/stream/ws.d.ts +18 -0
- package/build/devserver/stream/ws.js +46 -0
- package/docs/cli.md +3 -1
- package/docs/derive.md +159 -0
- package/docs/getting-started.md +7 -7
- package/docs/index.md +1 -1
- package/docs/streams.md +46 -14
- package/examples/basic/server/routes/Guestbook.ts +38 -13
- package/package.json +2 -2
- package/src/cli/index.ts +14 -1
- package/src/client/index.ts +2 -0
- package/src/client/rpc.ts +25 -1
- package/src/client/stream/client.ts +109 -0
- package/src/compiler/config.ts +15 -7
- package/src/compiler/index.ts +24 -5
- package/src/compiler/toil-docs.generated.ts +5 -4
- package/src/devserver/daemon/runtime.ts +48 -0
- package/src/devserver/db/database.ts +14 -0
- package/src/devserver/db/derives.ts +121 -0
- package/src/devserver/db/index.ts +1 -0
- package/src/devserver/db/types.ts +6 -0
- package/src/devserver/http/proxy.ts +53 -39
- package/src/devserver/http/runtime.ts +287 -0
- package/src/devserver/index.ts +2 -0
- package/src/devserver/production-ipc.ts +63 -0
- package/src/devserver/production-worker.ts +83 -0
- package/src/devserver/production.ts +706 -0
- package/src/devserver/runtime/module.ts +95 -1
- package/src/devserver/server.ts +52 -201
- package/src/devserver/ssr.ts +23 -3
- package/src/devserver/stream/catalog.ts +106 -0
- package/src/devserver/stream/host.ts +42 -0
- package/src/devserver/stream/index.ts +308 -0
- package/src/devserver/stream/manager.ts +163 -0
- package/src/devserver/stream/router.ts +101 -0
- package/src/devserver/stream/wire.ts +58 -0
- package/src/devserver/stream/ws.ts +76 -0
- package/test/built-ssr.test.ts +98 -0
- package/test/devserver.test.ts +20 -4
- package/test/example-guestbook.test.ts +8 -5
- package/test/fixtures/stream-echo.ts +26 -0
- package/test/fixtures/stream-gate.ts +24 -0
- package/test/fixtures/stream-trap.ts +18 -0
- package/test/fixtures/stream-typed.ts +41 -0
- package/test/stream-emulation.test.ts +433 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toiljs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.69",
|
|
5
5
|
"author": "Dacely",
|
|
6
6
|
"description": "The modern React framework: a file-based React frontend and a ToilScript-compiled WebAssembly backend.",
|
|
7
7
|
"repository": {
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"nodemailer": "^9.0.1",
|
|
135
135
|
"picocolors": "^1.1.1",
|
|
136
136
|
"sharp": "^0.35.2",
|
|
137
|
-
"toilscript": "^0.1.
|
|
137
|
+
"toilscript": "^0.1.44",
|
|
138
138
|
"typescript-eslint": "^8.62.0",
|
|
139
139
|
"vite": "^8.1.0",
|
|
140
140
|
"vite-imagetools": "^10.0.1",
|
package/src/cli/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ interface Flags {
|
|
|
19
19
|
root?: string;
|
|
20
20
|
port?: number;
|
|
21
21
|
host?: string;
|
|
22
|
+
threads?: number;
|
|
22
23
|
name?: string;
|
|
23
24
|
template?: Template;
|
|
24
25
|
preprocessor?: Preprocessor;
|
|
@@ -51,6 +52,12 @@ function parseArgs(argv: string[]): Flags {
|
|
|
51
52
|
case '--host':
|
|
52
53
|
flags.host = argv[++i];
|
|
53
54
|
break;
|
|
55
|
+
case '--threads':
|
|
56
|
+
case '--workers': {
|
|
57
|
+
const threads = Number(argv[++i]);
|
|
58
|
+
if (!Number.isNaN(threads)) flags.threads = threads;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
54
61
|
case '--template':
|
|
55
62
|
case '-t': {
|
|
56
63
|
const t = argv[++i];
|
|
@@ -138,6 +145,7 @@ function printHelp(): void {
|
|
|
138
145
|
bold('Options'),
|
|
139
146
|
cmd('--root <dir>', 'project root (default: current directory)'),
|
|
140
147
|
cmd('--port <n>', 'dev server port'),
|
|
148
|
+
cmd('--threads <n>', 'start: production HTTP worker count'),
|
|
141
149
|
cmd('-t, --template', 'create: app | minimal'),
|
|
142
150
|
cmd('--style <name>', 'create/configure: css | sass | less | stylus'),
|
|
143
151
|
cmd('--tailwind', 'create/configure: enable Tailwind (--no-tailwind to remove)'),
|
|
@@ -226,7 +234,12 @@ async function main(): Promise<void> {
|
|
|
226
234
|
case 'start': {
|
|
227
235
|
banner();
|
|
228
236
|
process.stdout.write(dim(' self-hosting the built app…') + '\n\n');
|
|
229
|
-
const server = await start({
|
|
237
|
+
const server = await start({
|
|
238
|
+
root: flags.root,
|
|
239
|
+
port: flags.port,
|
|
240
|
+
host: flags.host,
|
|
241
|
+
threads: flags.threads,
|
|
242
|
+
});
|
|
230
243
|
process.stdout.write(
|
|
231
244
|
accent(' ➜ ') +
|
|
232
245
|
bold(`http://localhost:${String(server.port)}`) +
|
package/src/client/index.ts
CHANGED
|
@@ -79,6 +79,8 @@ export { matchRoute } from './routing/match.js';
|
|
|
79
79
|
export type { RouteParams } from './routing/match.js';
|
|
80
80
|
export { connectChannel, useChannel, resolveChannelUrl } from './channel/channel.js';
|
|
81
81
|
export type { Channel, ChannelOptions, ChannelHook, ChannelData } from './channel/channel.js';
|
|
82
|
+
export { makeStreamClient } from './stream/client.js';
|
|
83
|
+
export type { StreamChannel, StreamConnectable, StreamClient } from './stream/client.js';
|
|
82
84
|
export { useHead, useTitle, Head, mergeHead } from './head/head.js';
|
|
83
85
|
export type { HeadSpec, MetaTag, LinkTag, ResolvedHead } from './head/head.js';
|
|
84
86
|
export { resolveMetadata, useMetadata, Metadata } from './head/metadata.js';
|
package/src/client/rpc.ts
CHANGED
|
@@ -24,7 +24,26 @@ function restMissingStub(path: string): unknown {
|
|
|
24
24
|
return new Proxy(call, {
|
|
25
25
|
get(_target, prop) {
|
|
26
26
|
if (typeof prop === 'symbol' || prop === 'then') return undefined;
|
|
27
|
-
return restMissingStub(`${path}.${
|
|
27
|
+
return restMissingStub(`${path}.${prop}`);
|
|
28
|
+
},
|
|
29
|
+
apply() {
|
|
30
|
+
return call();
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A recursive proxy that throws on call, used when the stream client hasn't loaded. */
|
|
36
|
+
function streamMissingStub(path: string): unknown {
|
|
37
|
+
const call = (): never => {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`toiljs Stream: ${path}() is unavailable. The generated stream client has not loaded - ` +
|
|
40
|
+
`import a type from your 'shared/server' (so the client attaches), or run 'npm run build:server'.`,
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
return new Proxy(call, {
|
|
44
|
+
get(_target, prop) {
|
|
45
|
+
if (typeof prop === 'symbol' || prop === 'then') return undefined;
|
|
46
|
+
return streamMissingStub(`${path}.${prop}`);
|
|
28
47
|
},
|
|
29
48
|
apply() {
|
|
30
49
|
return call();
|
|
@@ -49,6 +68,11 @@ function rpcStub(path: string): unknown {
|
|
|
49
68
|
const rest = (globalThis as { __toilRest?: unknown }).__toilRest;
|
|
50
69
|
return rest !== undefined ? rest : restMissingStub('Server.REST');
|
|
51
70
|
}
|
|
71
|
+
// `Server.Stream` surfaces the generated stream client attached by shared/server.ts.
|
|
72
|
+
if (path === 'Server' && prop === 'Stream') {
|
|
73
|
+
const stream = (globalThis as { __toilStream?: unknown }).__toilStream;
|
|
74
|
+
return stream !== undefined ? stream : streamMissingStub('Server.Stream');
|
|
75
|
+
}
|
|
52
76
|
return rpcStub(`${path}.${prop}`);
|
|
53
77
|
},
|
|
54
78
|
apply() {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client runtime for the typed `@stream` channel (doc 08 section 8.2). `Server.Stream.<Class>.connect(path?)`
|
|
3
|
+
* opens a browser `WebSocket` to the class's `route` (same origin) and returns a channel:
|
|
4
|
+
* `onMessage` / `send` / `onClose` / `close`. A raw `@stream` channel sends `Uint8Array`; a typed
|
|
5
|
+
* `@stream({ message: T })` channel sends the `@data` class and encodes it on send (the per-class
|
|
6
|
+
* encoder the generated module passes). The inbound reply is always raw bytes. The generated
|
|
7
|
+
* `shared/server.ts` (toilscript hot pass) attaches `makeStreamClient(routes, undefined, encoders)` to
|
|
8
|
+
* `globalThis.__toilStream`, and `Server.Stream`
|
|
9
|
+
* (`rpc.ts`) surfaces it - the same wiring the REST client uses via `globalThis.__toilRest`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** A live `@stream` connection. `TSend` is the outbound message type: `Uint8Array` for a raw `@stream`,
|
|
13
|
+
* or the `@data` class for a typed `@stream({ message: T })` (the channel encodes it before sending).
|
|
14
|
+
* The inbound reply is ALWAYS raw bytes - the server's `StreamOutbound` is raw (doc 03 2.5). */
|
|
15
|
+
export interface StreamChannel<TSend = Uint8Array> {
|
|
16
|
+
/** Register the inbound-frame handler (one call per server reply frame). */
|
|
17
|
+
onMessage(cb: (data: Uint8Array) => void): void;
|
|
18
|
+
/** Send one outbound message (one `@message` on the server); a typed channel encodes it first. */
|
|
19
|
+
send(data: TSend): void;
|
|
20
|
+
/** Register the close handler (`code` is the `0x02xx` stream close code, or the WS code). */
|
|
21
|
+
onClose(cb: (code: number) => void): void;
|
|
22
|
+
/** Close the connection. */
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The connect factory for one `@stream` class. `path` is the `@connect` path (default `''`). */
|
|
27
|
+
export interface StreamConnectable<TSend = Uint8Array> {
|
|
28
|
+
connect(path?: string): Promise<StreamChannel<TSend>>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** `Server.Stream`: one `connect()` factory per `@stream` class name. */
|
|
32
|
+
export type StreamClient = Record<string, StreamConnectable>;
|
|
33
|
+
|
|
34
|
+
/** Open a WebSocket to `url` and resolve a channel once the upgrade completes; reject if the socket
|
|
35
|
+
* closes/errors BEFORE it opens (a 421 redirect / wrong-node / unreachable). A server close AFTER
|
|
36
|
+
* open (e.g. a `@connect` reject or a guest reject) surfaces through `onClose(code)`. */
|
|
37
|
+
function connectStream<TSend = Uint8Array>(
|
|
38
|
+
url: string,
|
|
39
|
+
encode?: (msg: never) => Uint8Array,
|
|
40
|
+
): Promise<StreamChannel<TSend>> {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const ws = new WebSocket(url);
|
|
43
|
+
ws.binaryType = 'arraybuffer';
|
|
44
|
+
let opened = false;
|
|
45
|
+
let messageCb: ((data: Uint8Array) => void) | undefined;
|
|
46
|
+
let closeCb: ((code: number) => void) | undefined;
|
|
47
|
+
|
|
48
|
+
const channel: StreamChannel<TSend> = {
|
|
49
|
+
onMessage: (cb): void => {
|
|
50
|
+
messageCb = cb;
|
|
51
|
+
},
|
|
52
|
+
onClose: (cb): void => {
|
|
53
|
+
closeCb = cb;
|
|
54
|
+
},
|
|
55
|
+
send: (data): void => {
|
|
56
|
+
if (ws.readyState !== WebSocket.OPEN) return;
|
|
57
|
+
// A typed channel encodes the @data message; a raw channel sends the bytes as-is.
|
|
58
|
+
const bytes = encode ? encode(data as never) : (data as unknown as Uint8Array);
|
|
59
|
+
ws.send(bytes as BufferSource);
|
|
60
|
+
},
|
|
61
|
+
close: (): void => {
|
|
62
|
+
ws.close();
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
ws.addEventListener('open', () => {
|
|
67
|
+
opened = true;
|
|
68
|
+
resolve(channel);
|
|
69
|
+
});
|
|
70
|
+
ws.addEventListener('message', (event: MessageEvent) => {
|
|
71
|
+
if (event.data instanceof ArrayBuffer) messageCb?.(new Uint8Array(event.data));
|
|
72
|
+
});
|
|
73
|
+
ws.addEventListener('close', (event: CloseEvent) => {
|
|
74
|
+
if (!opened) reject(new Error(`stream connect failed (closed ${String(event.code)})`));
|
|
75
|
+
else closeCb?.(event.code);
|
|
76
|
+
});
|
|
77
|
+
ws.addEventListener('error', () => {
|
|
78
|
+
if (!opened) reject(new Error('stream connect error'));
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The same-origin WebSocket base (`ws://` / `wss://` per the page protocol). */
|
|
84
|
+
function defaultOrigin(): string {
|
|
85
|
+
const loc = globalThis.location;
|
|
86
|
+
return `${loc.protocol === 'https:' ? 'wss:' : 'ws:'}//${loc.host}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build the `Server.Stream` client from the generated route map (`{ ClassName: route }`). `origin`
|
|
91
|
+
* defaults to the page origin. `encoders` carries one `@data` encoder per typed `@stream({ message: T })`
|
|
92
|
+
* class (the generated `(m) => m.encode()`); a class with no entry is a raw byte channel. The generated
|
|
93
|
+
* `shared/server.ts` calls this and assigns the result to `globalThis.__toilStream`.
|
|
94
|
+
*/
|
|
95
|
+
export function makeStreamClient(
|
|
96
|
+
routes: Record<string, string>,
|
|
97
|
+
origin?: string,
|
|
98
|
+
encoders?: Record<string, (msg: never) => Uint8Array>,
|
|
99
|
+
): StreamClient {
|
|
100
|
+
const base = origin ?? defaultOrigin();
|
|
101
|
+
const client: StreamClient = {};
|
|
102
|
+
for (const [name, route] of Object.entries(routes)) {
|
|
103
|
+
const encode = encoders?.[name];
|
|
104
|
+
client[name] = {
|
|
105
|
+
connect: (path = ''): Promise<StreamChannel> => connectStream(`${base}${route}${path}`, encode),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return client;
|
|
109
|
+
}
|
package/src/compiler/config.ts
CHANGED
|
@@ -142,6 +142,11 @@ export interface ServerConfig {
|
|
|
142
142
|
readonly nodeMode?: DevNodeMode;
|
|
143
143
|
/** Daemon (L4) config mirror (dev / self-host). */
|
|
144
144
|
readonly daemon?: DaemonConfig;
|
|
145
|
+
/**
|
|
146
|
+
* Self-host HTTP worker count for `toiljs start`. Default `auto`
|
|
147
|
+
* (`os.availableParallelism()`). Set `1` to disable the worker pool.
|
|
148
|
+
*/
|
|
149
|
+
readonly threads?: number | 'auto';
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
/** Fully-resolved {@link DaemonConfig}; every field non-optional, defaults applied. */
|
|
@@ -199,6 +204,8 @@ export interface ResolvedToilConfig {
|
|
|
199
204
|
readonly nodeMode: DevNodeMode;
|
|
200
205
|
/** Daemon (L4) config mirror (dev / self-host), every field resolved. */
|
|
201
206
|
readonly daemon: ResolvedDaemonConfig;
|
|
207
|
+
/** Self-host HTTP worker count for `toiljs start`. */
|
|
208
|
+
readonly threads: number | 'auto';
|
|
202
209
|
/** Absolute path to the framework client runtime (`toiljs/client`). */
|
|
203
210
|
readonly runtimePath: string;
|
|
204
211
|
readonly vite: InlineConfig;
|
|
@@ -273,18 +280,13 @@ export async function loadConfig(
|
|
|
273
280
|
email: user.server?.email ?? null,
|
|
274
281
|
nodeMode: resolveNodeMode(user.server?.nodeMode),
|
|
275
282
|
daemon: resolveDaemonConfig(user.server?.daemon),
|
|
283
|
+
threads: resolveThreads(user.server?.threads),
|
|
276
284
|
runtimePath: resolveRuntimePath(),
|
|
277
285
|
vite: client.vite ?? {},
|
|
278
286
|
};
|
|
279
287
|
}
|
|
280
288
|
|
|
281
|
-
const DEV_NODE_MODES: readonly DevNodeMode[] = [
|
|
282
|
-
'hot',
|
|
283
|
-
'regional',
|
|
284
|
-
'continental',
|
|
285
|
-
'daemon',
|
|
286
|
-
'all',
|
|
287
|
-
];
|
|
289
|
+
const DEV_NODE_MODES: readonly DevNodeMode[] = ['hot', 'regional', 'continental', 'daemon', 'all'];
|
|
288
290
|
|
|
289
291
|
/** A `nodeMode` outside the enum falls back to `all` with a warning (fail-soft:
|
|
290
292
|
* the authoritative role is the edge's TCF + plan, so dev never bricks on it). */
|
|
@@ -319,3 +321,9 @@ function resolveDaemonConfig(d: DaemonConfig | undefined): ResolvedDaemonConfig
|
|
|
319
321
|
maxTasks,
|
|
320
322
|
};
|
|
321
323
|
}
|
|
324
|
+
|
|
325
|
+
function resolveThreads(threads: number | 'auto' | undefined): number | 'auto' {
|
|
326
|
+
if (threads === undefined || threads === 'auto') return 'auto';
|
|
327
|
+
if (!Number.isFinite(threads)) return 'auto';
|
|
328
|
+
return Math.max(1, Math.min(128, Math.floor(threads)));
|
|
329
|
+
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -524,6 +524,8 @@ export interface ToilCommandOptions {
|
|
|
524
524
|
readonly port?: number;
|
|
525
525
|
/** Bind host for `start`. Defaults to loopback (`127.0.0.1`); pass `0.0.0.0` to expose. */
|
|
526
526
|
readonly host?: string;
|
|
527
|
+
/** `start` only: production HTTP worker count. Defaults to `server.threads` / auto. */
|
|
528
|
+
readonly threads?: number;
|
|
527
529
|
/** `build` only: build the server (regenerate `shared/server.ts` + the wasm) and skip the client. */
|
|
528
530
|
readonly serverOnly?: boolean;
|
|
529
531
|
}
|
|
@@ -699,6 +701,10 @@ export async function dev(opts: ToilCommandOptions = {}): Promise<ViteDevServer>
|
|
|
699
701
|
// The daemon (cold) emulator drives `release-cold.wasm` per `nodeMode`; absent for a
|
|
700
702
|
// project with no `@daemon` (the cold artifact never gets built, so the host stays idle).
|
|
701
703
|
coldWasmFile: serverArtifacts(cfg.root).cold,
|
|
704
|
+
// The stream router serves `@stream`-route WebSocket upgrades from `release-stream.wasm` per
|
|
705
|
+
// `nodeMode`; the path points at the (maybe-not-yet-built) stream artifact, mtime-reloaded so
|
|
706
|
+
// a `@stream` build activates it, and harmless for a project with no `@stream` (no routes).
|
|
707
|
+
streamWasmFile: serverArtifacts(cfg.root).stream,
|
|
702
708
|
nodeMode: cfg.nodeMode,
|
|
703
709
|
daemon: cfg.daemon,
|
|
704
710
|
vite: { host: '127.0.0.1', port: vitePort },
|
|
@@ -779,9 +785,9 @@ export async function build(opts: ToilCommandOptions = {}): Promise<void> {
|
|
|
779
785
|
}
|
|
780
786
|
|
|
781
787
|
/**
|
|
782
|
-
* Self-hosts the built
|
|
783
|
-
*
|
|
784
|
-
* `build`. Returns the running backend.
|
|
788
|
+
* Self-hosts the built app over the high-performance hyper-express backend (uWebSockets.js).
|
|
789
|
+
* Server projects use the built wasm + SSR templates before the SPA fallback; client-only projects
|
|
790
|
+
* use the static backend. Requires a prior `build`. Returns the running backend.
|
|
785
791
|
*/
|
|
786
792
|
export async function start(opts: ToilCommandOptions = {}): Promise<RunningBackend> {
|
|
787
793
|
const cfg = await loadConfig(opts);
|
|
@@ -789,8 +795,21 @@ export async function start(opts: ToilCommandOptions = {}): Promise<RunningBacke
|
|
|
789
795
|
if (!fs.existsSync(path.join(outDir, 'index.html'))) {
|
|
790
796
|
throw new Error(`No build found in ${outDir}. Run \`toiljs build\` first.`);
|
|
791
797
|
}
|
|
792
|
-
const
|
|
793
|
-
|
|
798
|
+
const wasmFile = serverWasmFile(cfg.root);
|
|
799
|
+
const { startBuiltServer } = await import('toiljs/devserver');
|
|
800
|
+
const artifacts = serverArtifacts(cfg.root);
|
|
801
|
+
return startBuiltServer({
|
|
802
|
+
root: cfg.root,
|
|
803
|
+
staticRoot: outDir,
|
|
804
|
+
wasmFile: fs.existsSync(wasmFile) ? wasmFile : undefined,
|
|
805
|
+
coldWasmFile: artifacts.cold,
|
|
806
|
+
nodeMode: cfg.nodeMode,
|
|
807
|
+
daemon: cfg.daemon,
|
|
808
|
+
threads: opts.threads ?? cfg.threads,
|
|
809
|
+
port: cfg.port,
|
|
810
|
+
host: opts.host,
|
|
811
|
+
email: cfg.email ?? undefined,
|
|
812
|
+
});
|
|
794
813
|
}
|
|
795
814
|
|
|
796
815
|
export { defineConfig, loadConfig, AiProvider } from './config.js';
|